From cb2aaede67b9e5480c818fab15918f9dd5a96bd8 Mon Sep 17 00:00:00 2001 From: advplyr Date: Thu, 7 Jul 2022 17:24:26 -0500 Subject: [PATCH 01/43] Fix:Socket reconnection on disconnect, Add:Connection indicator icon showing socket/cellular --- components/app/Appbar.vue | 9 ++- components/app/AudioPlayer.vue | 1 - components/app/SideDrawer.vue | 2 +- components/widgets/ConnectionIndicator.vue | 73 ++++++++++++++++++++++ ios/App/Podfile | 12 ++-- layouts/default.vue | 5 -- plugins/server.js | 14 +++-- 7 files changed, 95 insertions(+), 21 deletions(-) create mode 100644 components/widgets/ConnectionIndicator.vue diff --git a/components/app/Appbar.vue b/components/app/Appbar.vue index 21d17a4c..c4628437 100644 --- a/components/app/Appbar.vue +++ b/components/app/Appbar.vue @@ -13,20 +13,23 @@

{{ currentLibraryName }}

+ + +
- cast + cast
- + search -
+
menu
diff --git a/components/app/AudioPlayer.vue b/components/app/AudioPlayer.vue index fbbd908d..14b8ee92 100644 --- a/components/app/AudioPlayer.vue +++ b/components/app/AudioPlayer.vue @@ -523,7 +523,6 @@ export default { var data = await AbsAudioPlayer.getCurrentTime() this.currentTime = Number(data.value.toFixed(2)) this.bufferedTime = Number(data.bufferedTime.toFixed(2)) - console.log('[AudioPlayer] Got Current Time', this.currentTime) this.timeupdate() }, 1000) }, diff --git a/components/app/SideDrawer.vue b/components/app/SideDrawer.vue index 28660b7c..8506812f 100644 --- a/components/app/SideDrawer.vue +++ b/components/app/SideDrawer.vue @@ -19,7 +19,7 @@
-

{{ serverConnectionConfig.address }} (v{{ serverSettings.version }})

+

{{ serverConnectionConfig.address }} (v{{ serverSettings.version }})

{{ $config.version }}

diff --git a/components/widgets/ConnectionIndicator.vue b/components/widgets/ConnectionIndicator.vue new file mode 100644 index 00000000..2301f2b7 --- /dev/null +++ b/components/widgets/ConnectionIndicator.vue @@ -0,0 +1,73 @@ + + + \ No newline at end of file diff --git a/ios/App/Podfile b/ios/App/Podfile index dcdae730..89125e80 100644 --- a/ios/App/Podfile +++ b/ios/App/Podfile @@ -9,12 +9,12 @@ install! 'cocoapods', :disable_input_output_paths => true def capacitor_pods pod 'Capacitor', :path => '../../node_modules/@capacitor/ios' pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios' - pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app' - pod 'CapacitorDialog', :path => '../../node_modules/@capacitor/dialog' - pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics' - pod 'CapacitorNetwork', :path => '../../node_modules/@capacitor/network' - pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar' - pod 'CapacitorStorage', :path => '../../node_modules/@capacitor/storage' + pod 'CapacitorApp', :path => '..\..\node_modules\@capacitor\app' + pod 'CapacitorDialog', :path => '..\..\node_modules\@capacitor\dialog' + pod 'CapacitorHaptics', :path => '..\..\node_modules\@capacitor\haptics' + pod 'CapacitorNetwork', :path => '..\..\node_modules\@capacitor\network' + pod 'CapacitorStatusBar', :path => '..\..\node_modules\@capacitor\status-bar' + pod 'CapacitorStorage', :path => '..\..\node_modules\@capacitor\storage' end target 'App' do diff --git a/layouts/default.vue b/layouts/default.vue index 327c8d9a..29191138 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -154,9 +154,6 @@ export default { // Only cancels stream if streamining not playing downloaded this.$eventBus.$emit('close-stream') }, - socketConnectionUpdate(isConnected) { - console.log('Socket connection update', isConnected) - }, socketConnectionFailed(err) { this.$toast.error('Socket connection error: ' + err.message) }, @@ -253,7 +250,6 @@ export default { } }, async mounted() { - this.$socket.on('connection-update', this.socketConnectionUpdate) this.$socket.on('initialized', this.socketInit) this.$socket.on('user_updated', this.userUpdated) this.$socket.on('user_media_progress_updated', this.userMediaProgressUpdated) @@ -282,7 +278,6 @@ export default { } }, beforeDestroy() { - this.$socket.off('connection-update', this.socketConnectionUpdate) this.$socket.off('initialized', this.socketInit) this.$socket.off('user_updated', this.userUpdated) this.$socket.off('user_media_progress_updated', this.userMediaProgressUpdated) diff --git a/plugins/server.js b/plugins/server.js index ca1a2e3c..e56f44c1 100644 --- a/plugins/server.js +++ b/plugins/server.js @@ -39,6 +39,7 @@ class ServerSocket extends EventEmitter { logout() { if (this.socket) this.socket.disconnect() + this.removeListeners() } setSocketListeners() { @@ -54,6 +55,14 @@ class ServerSocket extends EventEmitter { // }) } + removeListeners() { + if (!this.socket) return + this.socket.removeAllListeners() + if (this.socket.io && this.socket.io.removeAllListeners) { + this.socket.io.removeAllListeners() + } + } + onConnect() { console.log('[SOCKET] Socket Connected ' + this.socket.id) this.connected = true @@ -67,11 +76,6 @@ class ServerSocket extends EventEmitter { this.connected = false this.$store.commit('setSocketConnected', false) this.emit('connection-update', false) - - this.socket.removeAllListeners() - if (this.socket.io && this.socket.io.removeAllListeners) { - this.socket.io.removeAllListeners() - } } onInit(data) { From f998deb725a4f3ca6ccc386b2a07014740c23528 Mon Sep 17 00:00:00 2001 From: Jnewbon <48688400+Jnewbon@users.noreply.github.com> Date: Mon, 11 Jul 2022 00:26:53 +0100 Subject: [PATCH 02/43] Added Storage Media type Write access --- android/app/build.gradle | 2 +- .../com/audiobookshelf/app/MainActivity.kt | 18 ------- .../app/plugins/AbsFileSystem.kt | 47 ++++++++++++++----- 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 163290a6..c077489b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -111,7 +111,7 @@ dependencies { implementation 'io.github.pilgr:paperdb:2.7.2' // Simple Storage - implementation "com.anggrayudi:storage:0.13.0" + implementation "com.anggrayudi:storage:1.3.0" // OK HTTP implementation 'com.squareup.okhttp3:okhttp:4.9.2' diff --git a/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt b/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt index c1f60c88..09095282 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt @@ -5,11 +5,9 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.ServiceConnection -import android.content.pm.PackageManager import android.os.Bundle import android.os.IBinder import android.util.Log -import androidx.core.app.ActivityCompat import com.anggrayudi.storage.SimpleStorage import com.anggrayudi.storage.SimpleStorageHelper import com.audiobookshelf.app.data.AbsDatabase @@ -19,7 +17,6 @@ import com.audiobookshelf.app.plugins.AbsAudioPlayer import com.audiobookshelf.app.plugins.AbsDownloader import com.audiobookshelf.app.plugins.AbsFileSystem import com.getcapacitor.BridgeActivity -import io.paperdb.Paper class MainActivity : BridgeActivity() { @@ -34,11 +31,6 @@ class MainActivity : BridgeActivity() { val storageHelper = SimpleStorageHelper(this) val storage = SimpleStorage(this) - val REQUEST_PERMISSIONS = 1 - var PERMISSIONS_ALL = arrayOf( - Manifest.permission.READ_EXTERNAL_STORAGE - ) - public override fun onCreate(savedInstanceState: Bundle?) { // TODO: Optimize using strict mode logs // StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder() @@ -58,16 +50,6 @@ class MainActivity : BridgeActivity() { DbManager.initialize(applicationContext) - // Grant full storage access for testing - // var ss = SimpleStorage(this) - // ss.requestFullStorageAccess() - - val permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) - if (permission != PackageManager.PERMISSION_GRANTED) { - ActivityCompat.requestPermissions(this, - PERMISSIONS_ALL, - REQUEST_PERMISSIONS) - } registerPlugin(AbsAudioPlayer::class.java) registerPlugin(AbsDownloader::class.java) diff --git a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsFileSystem.kt b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsFileSystem.kt index 4beb4436..3d58cb41 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsFileSystem.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsFileSystem.kt @@ -1,5 +1,6 @@ package com.audiobookshelf.app.plugins +import android.app.AlertDialog import android.database.Cursor import android.net.Uri import android.os.Build @@ -65,39 +66,59 @@ class AbsFileSystem : Plugin() { @PluginMethod fun selectFolder(call: PluginCall) { - var mediaType = call.data.getString("mediaType", "book").toString() + val mediaType = call.data.getString("mediaType", "book").toString() + val REQUEST_CODE_SELECT_FOLDER = 6 + val REQUEST_CODE_SDCARD_ACCESS = 7 mainActivity.storage.folderPickerCallback = object : FolderPickerCallback { override fun onFolderSelected(requestCode: Int, folder: DocumentFile) { Log.d(TAG, "ON FOLDER SELECTED ${folder.uri} ${folder.name}") - var absolutePath = folder.getAbsolutePath(activity) - var storageType = folder.getStorageType(activity) - var simplePath = folder.getSimplePath(activity) - var basePath = folder.getBasePath(activity) - var folderId = android.util.Base64.encodeToString(folder.id.toByteArray(), android.util.Base64.DEFAULT) + val absolutePath = folder.getAbsolutePath(activity) + val storageType = folder.getStorageType(activity) + val simplePath = folder.getSimplePath(activity) + val basePath = folder.getBasePath(activity) + val folderId = android.util.Base64.encodeToString(folder.id.toByteArray(), android.util.Base64.DEFAULT) - var localFolder = LocalFolder(folderId, folder.name ?: "", folder.uri.toString(),basePath,absolutePath, simplePath, storageType.toString(), mediaType) + val localFolder = LocalFolder(folderId, folder.name ?: "", folder.uri.toString(),basePath,absolutePath, simplePath, storageType.toString(), mediaType) DeviceManager.dbManager.saveLocalFolder(localFolder) call.resolve(JSObject(jacksonMapper.writeValueAsString(localFolder))) } override fun onStorageAccessDenied(requestCode: Int, folder: DocumentFile?, storageType: StorageType) { - Log.e(TAG, "STORAGE ACCESS DENIED") - var jsobj = JSObject() - jsobj.put("error", "Access Denied") - call.resolve(jsobj) + val jsobj = JSObject() + if (requestCode == REQUEST_CODE_SELECT_FOLDER) { + + val builder: AlertDialog.Builder = AlertDialog.Builder(mainActivity) + builder.setMessage( + "You have no write access to this storage, thus selecting this folder is useless." + + "\nWould you like to grant access to this folder?") + builder.setNegativeButton("Dont Allow") { _, _ -> + run { + jsobj.put("error", "User Canceled, Access Denied") + call.resolve(jsobj) + } + } + builder.setPositiveButton("Allow.") { _, _ -> mainActivity.storageHelper.requestStorageAccess(REQUEST_CODE_SDCARD_ACCESS, storageType) } + builder.show() + } else { + Log.d(TAG, "STORAGE ACCESS DENIED $requestCode") + jsobj.put("error", "Access Denied") + call.resolve(jsobj) + } } + override fun onStoragePermissionDenied(requestCode: Int) { Log.d(TAG, "STORAGE PERMISSION DENIED $requestCode") - var jsobj = JSObject() + val jsobj = JSObject() jsobj.put("error", "Permission Denied") call.resolve(jsobj) } + } - mainActivity.storage.openFolderPicker(6) + mainActivity.storage.openFolderPicker(REQUEST_CODE_SELECT_FOLDER) } @RequiresApi(Build.VERSION_CODES.R) From 7fe384970569555c25cc8da696223d032fedf173 Mon Sep 17 00:00:00 2001 From: Jnewbon <48688400+Jnewbon@users.noreply.github.com> Date: Mon, 11 Jul 2022 00:43:36 +0100 Subject: [PATCH 03/43] Re Added read Permission check as i probably shouldn't have removed it --- .../java/com/audiobookshelf/app/MainActivity.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt b/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt index 09095282..1ba21952 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt @@ -5,9 +5,11 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.ServiceConnection +import android.content.pm.PackageManager import android.os.Bundle import android.os.IBinder import android.util.Log +import androidx.core.app.ActivityCompat import com.anggrayudi.storage.SimpleStorage import com.anggrayudi.storage.SimpleStorageHelper import com.audiobookshelf.app.data.AbsDatabase @@ -31,6 +33,11 @@ class MainActivity : BridgeActivity() { val storageHelper = SimpleStorageHelper(this) val storage = SimpleStorage(this) + val REQUEST_PERMISSIONS = 1 + var PERMISSIONS_ALL = arrayOf( + Manifest.permission.READ_EXTERNAL_STORAGE + ) + public override fun onCreate(savedInstanceState: Bundle?) { // TODO: Optimize using strict mode logs // StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder() @@ -50,6 +57,12 @@ class MainActivity : BridgeActivity() { DbManager.initialize(applicationContext) + val permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) + if (permission != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, + PERMISSIONS_ALL, + REQUEST_PERMISSIONS) + } registerPlugin(AbsAudioPlayer::class.java) registerPlugin(AbsDownloader::class.java) From a58965306afa30a0c14dce0fbcd74196da218f7f Mon Sep 17 00:00:00 2001 From: advplyr Date: Wed, 13 Jul 2022 16:44:02 -0500 Subject: [PATCH 04/43] Fix misleading plugin function name --- .../src/main/java/com/audiobookshelf/app/data/DbManager.kt | 2 +- .../main/java/com/audiobookshelf/app/plugins/AbsDatabase.kt | 4 ++-- ios/App/App/plugins/AbsDatabase.m | 2 +- ios/App/App/plugins/AbsDatabase.swift | 2 +- layouts/default.vue | 2 +- pages/item/_id.vue | 2 +- plugins/capacitor/AbsDatabase.js | 2 +- plugins/db.js | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/DbManager.kt b/android/app/src/main/java/com/audiobookshelf/app/data/DbManager.kt index 79676738..20cac976 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/DbManager.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/DbManager.kt @@ -45,7 +45,7 @@ class DbManager { } } - fun getLocalLibraryItemByLLId(libraryItemId:String):LocalLibraryItem? { + fun getLocalLibraryItemByLId(libraryItemId:String):LocalLibraryItem? { return getLocalLibraryItems().find { it.libraryItemId == libraryItemId } } diff --git a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDatabase.kt b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDatabase.kt index 3899608a..3076ae6e 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDatabase.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsDatabase.kt @@ -77,10 +77,10 @@ class AbsDatabase : Plugin() { } @PluginMethod - fun getLocalLibraryItemByLLId(call:PluginCall) { + fun getLocalLibraryItemByLId(call:PluginCall) { val libraryItemId = call.getString("libraryItemId", "").toString() GlobalScope.launch(Dispatchers.IO) { - val localLibraryItem = DeviceManager.dbManager.getLocalLibraryItemByLLId(libraryItemId) + val localLibraryItem = DeviceManager.dbManager.getLocalLibraryItemByLId(libraryItemId) if (localLibraryItem == null) { call.resolve() } else { diff --git a/ios/App/App/plugins/AbsDatabase.m b/ios/App/App/plugins/AbsDatabase.m index e948a11a..c66e1bd8 100644 --- a/ios/App/App/plugins/AbsDatabase.m +++ b/ios/App/App/plugins/AbsDatabase.m @@ -17,7 +17,7 @@ CAP_PLUGIN(AbsDatabase, "AbsDatabase", CAP_PLUGIN_METHOD(getLocalLibraryItems, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(getLocalLibraryItem, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(getLocalLibraryItemByLLId, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(getLocalLibraryItemByLId, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(getLocalLibraryItemsInFolder, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(updateDeviceSettings, CAPPluginReturnPromise); ) diff --git a/ios/App/App/plugins/AbsDatabase.swift b/ios/App/App/plugins/AbsDatabase.swift index 673f002e..4cdc31f8 100644 --- a/ios/App/App/plugins/AbsDatabase.swift +++ b/ios/App/App/plugins/AbsDatabase.swift @@ -80,7 +80,7 @@ public class AbsDatabase: CAPPlugin { @objc func getLocalLibraryItem(_ call: CAPPluginCall) { call.resolve() } - @objc func getLocalLibraryItemByLLId(_ call: CAPPluginCall) { + @objc func getLocalLibraryItemByLId(_ call: CAPPluginCall) { call.resolve() } @objc func getLocalLibraryItemsInFolder(_ call: CAPPluginCall) { diff --git a/layouts/default.vue b/layouts/default.vue index 29191138..1b808df2 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -215,7 +215,7 @@ export default { newLocalMediaProgress = await this.$db.syncServerMediaProgressWithLocalMediaProgress(payload) } else { // Check if local library item exists - var localLibraryItem = await this.$db.getLocalLibraryItemByLLId(prog.libraryItemId) + var localLibraryItem = await this.$db.getLocalLibraryItemByLId(prog.libraryItemId) if (localLibraryItem) { if (prog.episodeId) { // If episode check if local episode exists diff --git a/pages/item/_id.vue b/pages/item/_id.vue index f01d283a..e9005ffb 100644 --- a/pages/item/_id.vue +++ b/pages/item/_id.vue @@ -136,7 +136,7 @@ export default { }) // Check if if (libraryItem) { - var localLibraryItem = await app.$db.getLocalLibraryItemByLLId(libraryItemId) + var localLibraryItem = await app.$db.getLocalLibraryItemByLId(libraryItemId) if (localLibraryItem) { console.log('Library item has local library item also', localLibraryItem.id) libraryItem.localLibraryItem = localLibraryItem diff --git a/plugins/capacitor/AbsDatabase.js b/plugins/capacitor/AbsDatabase.js index bb7bac28..69cc7b9f 100644 --- a/plugins/capacitor/AbsDatabase.js +++ b/plugins/capacitor/AbsDatabase.js @@ -164,7 +164,7 @@ class AbsDatabaseWeb extends WebPlugin { async getLocalLibraryItem({ id }) { return this.getLocalLibraryItems().then((data) => data.value[0]) } - async getLocalLibraryItemByLLId({ libraryItemId }) { + async getLocalLibraryItemByLId({ libraryItemId }) { return this.getLocalLibraryItems().then((data) => data.value.find(lli => lli.libraryItemId == libraryItemId)) } async getAllLocalMediaProgress() { diff --git a/plugins/db.js b/plugins/db.js index 58b929af..1b31332e 100644 --- a/plugins/db.js +++ b/plugins/db.js @@ -54,8 +54,8 @@ class DbService { return AbsDatabase.getLocalLibraryItem({ id }) } - getLocalLibraryItemByLLId(libraryItemId) { - return AbsDatabase.getLocalLibraryItemByLLId({ libraryItemId }) + getLocalLibraryItemByLId(libraryItemId) { + return AbsDatabase.getLocalLibraryItemByLId({ libraryItemId }) } getAllLocalMediaProgress() { From 721f812df09059f9fa7b2348bfa6701735243db8 Mon Sep 17 00:00:00 2001 From: advplyr Date: Wed, 13 Jul 2022 17:10:47 -0500 Subject: [PATCH 05/43] Update:Library widget UI --- components/app/Appbar.vue | 4 ++-- layouts/default.vue | 3 ++- tailwind.config.js | 3 +++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/components/app/Appbar.vue b/components/app/Appbar.vue index c4628437..a2e9a8bd 100644 --- a/components/app/Appbar.vue +++ b/components/app/Appbar.vue @@ -8,9 +8,9 @@ arrow_back
-
+
-

{{ currentLibraryName }}

+

{{ currentLibraryName }}

diff --git a/layouts/default.vue b/layouts/default.vue index 1b808df2..68a10886 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -213,8 +213,9 @@ export default { mediaProgress: prog } newLocalMediaProgress = await this.$db.syncServerMediaProgressWithLocalMediaProgress(payload) - } else { + } else if (!localProg) { // Check if local library item exists + // local media progress may not exist yet if it hasn't been played var localLibraryItem = await this.$db.getLocalLibraryItemByLId(prog.libraryItemId) if (localLibraryItem) { if (prog.episodeId) { diff --git a/tailwind.config.js b/tailwind.config.js index 368e3bfd..a0011750 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -36,6 +36,9 @@ module.exports = { }, fontSize: { xxs: '0.625rem' + }, + maxWidth: { + '24': '6rem' } } }, From 9847ed9fcbd7b252fd126f1e09c8c9200c97f32a Mon Sep 17 00:00:00 2001 From: advplyr Date: Wed, 13 Jul 2022 17:13:15 -0500 Subject: [PATCH 06/43] Fix network connection indicator --- components/widgets/ConnectionIndicator.vue | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/components/widgets/ConnectionIndicator.vue b/components/widgets/ConnectionIndicator.vue index 2301f2b7..90aa4d5c 100644 --- a/components/widgets/ConnectionIndicator.vue +++ b/components/widgets/ConnectionIndicator.vue @@ -28,18 +28,16 @@ export default { return this.networkConnectionType === 'cellular' }, icon() { + if (!this.user) return null // hide when not connected to server + if (!this.networkConnected) { return 'wifi_off' } else if (!this.socketConnected) { return 'cloud_off' - } else if (this.user) { - if (this.isCellular) { - return 'signal_cellular_alt' - } else { - return 'cloud_done' - } + } else if (this.isCellular) { + return 'signal_cellular_alt' } else { - return null + return 'cloud_done' } }, iconClass() { From e7c913643a26cd1a640b6244d11e58b5c8bf30a8 Mon Sep 17 00:00:00 2001 From: advplyr Date: Wed, 13 Jul 2022 19:17:34 -0500 Subject: [PATCH 07/43] Add:Last local media progress sync with server widget, Update:Remove local media progress with bad id --- .../com/audiobookshelf/app/data/DbManager.kt | 6 ++- layouts/default.vue | 10 ++-- pages/localMedia/folders/index.vue | 47 ++++++++++++++++++- store/index.js | 6 ++- store/user.js | 3 ++ 5 files changed, 65 insertions(+), 7 deletions(-) diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/DbManager.kt b/android/app/src/main/java/com/audiobookshelf/app/data/DbManager.kt index 20cac976..f7da6233 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/DbManager.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/DbManager.kt @@ -213,7 +213,11 @@ class DbManager { val localLibraryItems = getLocalLibraryItems() localMediaProgress.forEach { val matchingLLI = localLibraryItems.find { lli -> lli.id == it.localLibraryItemId } - if (matchingLLI == null) { + if (!it.id.startsWith("local")) { + // A bug on the server when syncing local media progress was replacing the media progress id causing duplicate progress. Remove them. + Log.d(tag, "cleanLocalMediaProgress: Invalid local media progress does not start with 'local' (fixed on server 2.0.24)") + Paper.book("localMediaProgress").delete(it.id) + } else if (matchingLLI == null) { Log.d(tag, "cleanLocalMediaProgress: No matching local library item for local media progress ${it.id} - removing") Paper.book("localMediaProgress").delete(it.id) } else if (matchingLLI.isPodcast) { diff --git a/layouts/default.vue b/layouts/default.vue index 68a10886..97420d4d 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -66,9 +66,6 @@ export default { }, currentLibraryId() { return this.$store.state.libraries.currentLibraryId - }, - isSocketConnected() { - return this.$store.state.socketConnected } }, methods: { @@ -174,6 +171,7 @@ export default { async syncLocalMediaProgress() { if (!this.user) { console.log('[default] No need to sync local media progress - not connected to server') + this.$store.commit('setLastLocalMediaSyncResults', null) return } @@ -181,10 +179,15 @@ export default { var response = await this.$db.syncLocalMediaProgressWithServer() if (!response) { if (this.$platform != 'web') this.$toast.error('Failed to sync local media with server') + this.$store.commit('setLastLocalMediaSyncResults', null) return } const { numLocalMediaProgressForServer, numServerProgressUpdates, numLocalProgressUpdates } = response if (numLocalMediaProgressForServer > 0) { + response.syncedAt = Date.now() + response.serverConfigName = this.$store.getters['user/getServerConfigName'] + this.$store.commit('setLastLocalMediaSyncResults', response) + if (numServerProgressUpdates > 0 || numLocalProgressUpdates > 0) { console.log(`[default] ${numServerProgressUpdates} Server progress updates | ${numLocalProgressUpdates} Local progress updates`) } else { @@ -192,6 +195,7 @@ export default { } } else { console.log('[default] syncLocalMediaProgress No local media progress to sync') + this.$store.commit('setLastLocalMediaSyncResults', null) } }, async userUpdated(user) { diff --git a/pages/localMedia/folders/index.vue b/pages/localMedia/folders/index.vue index 00029bef..d6b09ce4 100644 --- a/pages/localMedia/folders/index.vue +++ b/pages/localMedia/folders/index.vue @@ -1,5 +1,28 @@
+
+ arrow_back +

Server address

@@ -273,7 +276,8 @@ export default { this.error = 'Invalid username' return } - const duplicateConfig = this.serverConnectionConfigs.find((scc) => scc.address === this.serverConfig.address && scc.username === this.serverConfig.username) + + const duplicateConfig = this.serverConnectionConfigs.find((scc) => scc.address === this.serverConfig.address && scc.username === this.serverConfig.username && this.serverConfig.id !== scc.id) if (duplicateConfig) { this.error = 'Config already exists for this address and username' return @@ -293,7 +297,7 @@ export default { console.log('Successfully logged in', JSON.stringify(user)) - this.$store.commit('setServerSettings', data.serverSettings) + this.$store.commit('setServerSettings', serverSettings) // Set library - Use last library if set and available fallback to default user library var lastLibraryId = await this.$localStore.getLastLibraryId() From b51f65d2a4c6b91f1448473c72ae35bc602abefa Mon Sep 17 00:00:00 2001 From: advplyr Date: Tue, 19 Jul 2022 18:09:55 -0500 Subject: [PATCH 17/43] Fix:Closing playback first closes media progress syncer #268 --- .../audiobookshelf/app/player/PlayerNotificationService.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt index 43c637f7..060e4f56 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt @@ -670,6 +670,11 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { fun closePlayback() { Log.d(tag, "closePlayback") + if (mediaProgressSyncer.listeningTimerRunning) { + Log.i(tag, "About to close playback so stopping media progress syncer first") + mediaProgressSyncer.stop() + } + try { currentPlayer.stop() currentPlayer.clearMediaItems() From 5f6a1ef7e965819e2f643cfe359227935bc05dec Mon Sep 17 00:00:00 2001 From: advplyr Date: Tue, 19 Jul 2022 18:50:14 -0500 Subject: [PATCH 18/43] Update:Show error icon on player cover when local media progress fails to sync & remove sync failure toast --- .../app/player/MediaProgressSyncer.kt | 17 ++++++++++++++-- .../app/player/PlayerNotificationService.kt | 5 +++++ .../app/plugins/AbsAudioPlayer.kt | 4 ++++ .../audiobookshelf/app/server/ApiHandler.kt | 8 ++++++-- components/app/AudioPlayer.vue | 20 ++++++++++++++++++- components/app/AudioPlayerContainer.vue | 10 +--------- components/connection/ServerConnectForm.vue | 2 +- plugins/constants.js | 7 +++++++ 8 files changed, 58 insertions(+), 15 deletions(-) diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/MediaProgressSyncer.kt b/android/app/src/main/java/com/audiobookshelf/app/player/MediaProgressSyncer.kt index 25a35876..25bea081 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/MediaProgressSyncer.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/MediaProgressSyncer.kt @@ -109,11 +109,23 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic // Local library item is linked to a server library item // Send sync to server also if connected to this server and local item belongs to this server if (!it.libraryItemId.isNullOrEmpty() && it.serverConnectionConfigId != null && DeviceManager.serverConnectionConfig?.id == it.serverConnectionConfigId) { - apiHandler.sendLocalProgressSync(it) { + apiHandler.sendLocalProgressSync(it) { syncSuccess -> Log.d( tag, "Local progress sync data sent to server $currentDisplayTitle for time $currentTime" ) + if (syncSuccess) { + failedSyncs = 0 + playerNotificationService.alertSyncSuccess() + } else { + failedSyncs++ + if (failedSyncs == 2) { + playerNotificationService.alertSyncFailing() // Show alert in client + failedSyncs = 0 + } + Log.e(tag, "Local Progress sync failed ($failedSyncs) to send to server $currentDisplayTitle for time $currentTime") + } + cb() } } else { @@ -125,13 +137,14 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic if (it) { Log.d(tag, "Progress sync data sent to server $currentDisplayTitle for time $currentTime") failedSyncs = 0 + playerNotificationService.alertSyncSuccess() } else { failedSyncs++ if (failedSyncs == 2) { playerNotificationService.alertSyncFailing() // Show alert in client failedSyncs = 0 } - Log.d(tag, "Progress sync failed ($failedSyncs) to send to server $currentDisplayTitle for time $currentTime") + Log.e(tag, "Progress sync failed ($failedSyncs) to send to server $currentDisplayTitle for time $currentTime") } cb() } diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt index 060e4f56..8b0c09cf 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt @@ -58,6 +58,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { fun onPlaybackFailed(errorMessage:String) fun onMediaPlayerChanged(mediaPlayer:String) fun onProgressSyncFailing() + fun onProgressSyncSuccess() } private val tag = "PlayerService" @@ -722,6 +723,10 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { clientEventEmitter?.onProgressSyncFailing() } + fun alertSyncSuccess() { + clientEventEmitter?.onProgressSyncSuccess() + } + // // MEDIA BROWSER STUFF (ANDROID AUTO) // diff --git a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt index 2e2bdb35..b0d82226 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt @@ -80,6 +80,10 @@ class AbsAudioPlayer : Plugin() { override fun onProgressSyncFailing() { emit("onProgressSyncFailing", "") } + + override fun onProgressSyncSuccess() { + emit("onProgressSyncSuccess", "") + } }) } mainActivity.pluginCallback = foregroundServiceReady diff --git a/android/app/src/main/java/com/audiobookshelf/app/server/ApiHandler.kt b/android/app/src/main/java/com/audiobookshelf/app/server/ApiHandler.kt index 80846d85..aebcede3 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/server/ApiHandler.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/server/ApiHandler.kt @@ -230,11 +230,15 @@ class ApiHandler(var ctx:Context) { } } - fun sendLocalProgressSync(playbackSession:PlaybackSession, cb: () -> Unit) { + fun sendLocalProgressSync(playbackSession:PlaybackSession, cb: (Boolean) -> Unit) { val payload = JSObject(jacksonMapper.writeValueAsString(playbackSession)) postRequest("/api/session/local", payload) { - cb() + if (!it.getString("error").isNullOrEmpty()) { + cb(false) + } else { + cb(true) + } } } diff --git a/components/app/AudioPlayer.vue b/components/app/AudioPlayer.vue index 14b8ee92..61a94a19 100644 --- a/components/app/AudioPlayer.vue +++ b/components/app/AudioPlayer.vue @@ -34,6 +34,10 @@
+ +
+ error +
@@ -129,13 +133,16 @@ export default { onPlaybackClosedListener: null, onPlayingUpdateListener: null, onMetadataListener: null, + onProgressSyncFailing: null, + onProgressSyncSuccess: null, touchStartY: 0, touchStartTime: 0, touchEndY: 0, useChapterTrack: false, isLoading: false, touchTrackStart: false, - dragPercent: 0 + dragPercent: 0, + syncStatus: 0 } }, watch: { @@ -675,6 +682,7 @@ export default { this.isEnded = false this.isLoading = true + this.syncStatus = 0 this.$store.commit('setPlayerItem', this.playbackSession) // Set track width @@ -703,6 +711,8 @@ export default { this.onPlaybackFailedListener = AbsAudioPlayer.addListener('onPlaybackFailed', this.onPlaybackFailed) this.onPlayingUpdateListener = AbsAudioPlayer.addListener('onPlayingUpdate', this.onPlayingUpdate) this.onMetadataListener = AbsAudioPlayer.addListener('onMetadata', this.onMetadata) + this.onProgressSyncFailing = AbsAudioPlayer.addListener('onProgressSyncFailing', this.showProgressSyncIsFailing) + this.onProgressSyncSuccess = AbsAudioPlayer.addListener('onProgressSyncSuccess', this.showProgressSyncSuccess) }, screenOrientationChange() { setTimeout(this.updateScreenSize, 50) @@ -716,6 +726,12 @@ export default { minimizePlayerEvt() { console.log('Minimize Player Evt') this.showFullscreen = false + }, + showProgressSyncIsFailing() { + this.syncStatus = this.$constants.SyncStatus.FAILED + }, + showProgressSyncSuccess() { + this.syncStatus = this.$constants.SyncStatus.SUCCESS } }, mounted() { @@ -751,6 +767,8 @@ export default { if (this.onPlaybackSessionListener) this.onPlaybackSessionListener.remove() if (this.onPlaybackClosedListener) this.onPlaybackClosedListener.remove() if (this.onPlaybackFailedListener) this.onPlaybackFailedListener.remove() + if (this.onProgressSyncFailing) this.onProgressSyncFailing.remove() + if (this.onProgressSyncSuccess) this.onProgressSyncSuccess.remove() clearInterval(this.playInterval) } } diff --git a/components/app/AudioPlayerContainer.vue b/components/app/AudioPlayerContainer.vue index df90791c..0516fd98 100644 --- a/components/app/AudioPlayerContainer.vue +++ b/components/app/AudioPlayerContainer.vue @@ -30,11 +30,9 @@ export default { onSleepTimerEndedListener: null, onSleepTimerSetListener: null, onMediaPlayerChangedListener: null, - onProgressSyncFailing: null, sleepInterval: null, currentEndOfChapterTime: 0, - serverLibraryItemId: null, - syncFailedToast: null + serverLibraryItemId: null } }, watch: { @@ -255,10 +253,6 @@ export default { onMediaPlayerChanged(data) { var mediaPlayer = data.value this.$store.commit('setMediaPlayer', mediaPlayer) - }, - showProgressSyncIsFailing() { - if (!isNaN(this.syncFailedToast)) this.$toast.dismiss(this.syncFailedToast) - this.syncFailedToast = this.$toast('Progress is not being synced', { timeout: false, type: 'error' }) } }, mounted() { @@ -266,7 +260,6 @@ export default { this.onSleepTimerEndedListener = AbsAudioPlayer.addListener('onSleepTimerEnded', this.onSleepTimerEnded) this.onSleepTimerSetListener = AbsAudioPlayer.addListener('onSleepTimerSet', this.onSleepTimerSet) this.onMediaPlayerChangedListener = AbsAudioPlayer.addListener('onMediaPlayerChanged', this.onMediaPlayerChanged) - this.onProgressSyncFailing = AbsAudioPlayer.addListener('onProgressSyncFailing', this.showProgressSyncIsFailing) this.playbackSpeed = this.$store.getters['user/getUserSetting']('playbackRate') console.log(`[AudioPlayerContainer] Init Playback Speed: ${this.playbackSpeed}`) @@ -283,7 +276,6 @@ export default { if (this.onSleepTimerEndedListener) this.onSleepTimerEndedListener.remove() if (this.onSleepTimerSetListener) this.onSleepTimerSetListener.remove() if (this.onMediaPlayerChangedListener) this.onMediaPlayerChangedListener.remove() - if (this.onProgressSyncFailing) this.onProgressSyncFailing.remove() // if (this.$server.socket) { // this.$server.socket.off('stream_open', this.streamOpen) diff --git a/components/connection/ServerConnectForm.vue b/components/connection/ServerConnectForm.vue index 4ef943f9..047a37cc 100644 --- a/components/connection/ServerConnectForm.vue +++ b/components/connection/ServerConnectForm.vue @@ -152,7 +152,7 @@ export default { var payload = await this.authenticateToken() if (payload) { - this.setUserAndConnection(payload.user, payload.userDefaultLibraryId) + this.setUserAndConnection(payload) } else { this.showAuth = true } diff --git a/plugins/constants.js b/plugins/constants.js index b1471010..e6e84210 100644 --- a/plugins/constants.js +++ b/plugins/constants.js @@ -5,6 +5,12 @@ const DownloadStatus = { FAILED: 3 } +const SyncStatus = { + UNSET: 0, + SUCCESS: 1, + FAILED: 2 +} + const CoverDestination = { METADATA: 0, AUDIOBOOK: 1 @@ -31,6 +37,7 @@ const PlayerState = { const Constants = { DownloadStatus, + SyncStatus, CoverDestination, BookCoverAspectRatio, PlayMethod, From 3b34029ca2113f3a674fa3c34011953ceabc5b40 Mon Sep 17 00:00:00 2001 From: advplyr Date: Wed, 20 Jul 2022 17:38:13 -0500 Subject: [PATCH 19/43] Fix:M4B downloads adding MP3 extension by downloading to SimpleStorage v0.14.0 #292 --- android/app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index eb351188..f8eddb2c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -111,7 +111,7 @@ dependencies { implementation 'io.github.pilgr:paperdb:2.7.2' // Simple Storage - implementation "com.anggrayudi:storage:1.3.0" + implementation "com.anggrayudi:storage:0.14.0" // OK HTTP implementation 'com.squareup.okhttp3:okhttp:4.9.2' From 1f60a552e5e4ce999c29ac5ca27185c1885296af Mon Sep 17 00:00:00 2001 From: advplyr Date: Wed, 20 Jul 2022 18:02:07 -0500 Subject: [PATCH 20/43] Version bump 0.9.53-beta --- android/app/build.gradle | 4 ++-- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index f8eddb2c..ac438430 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -29,8 +29,8 @@ android { applicationId "com.audiobookshelf.app" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 83 - versionName "0.9.52-beta" + versionCode 84 + versionName "0.9.53-beta" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/package-lock.json b/package-lock.json index e347a77f..2f9f6512 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "audiobookshelf-app", - "version": "0.9.52-beta", + "version": "0.9.53-beta", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 3b0df246..936322d7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "audiobookshelf-app", - "version": "0.9.52-beta", + "version": "0.9.53-beta", "author": "advplyr", "scripts": { "dev": "nuxt --hostname 0.0.0.0 --port 1337", From 2a87f1de28c0f0eb0831fb28c628de06db45c6f2 Mon Sep 17 00:00:00 2001 From: advplyr Date: Thu, 21 Jul 2022 17:54:00 -0500 Subject: [PATCH 21/43] Fix:Android check local media progress after a pause reverting to previous progress #290 --- .../app/player/MediaProgressSyncer.kt | 23 ++++++++++- .../app/player/PlayerListener.kt | 23 ++++++----- .../app/player/PlayerNotificationService.kt | 38 ++++++++++++++----- .../app/plugins/AbsAudioPlayer.kt | 31 +++++++++++++-- 4 files changed, 91 insertions(+), 24 deletions(-) diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/MediaProgressSyncer.kt b/android/app/src/main/java/com/audiobookshelf/app/player/MediaProgressSyncer.kt index 25bea081..2f774a1d 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/MediaProgressSyncer.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/MediaProgressSyncer.kt @@ -46,7 +46,10 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic } else { return } + } else if (playerNotificationService.getCurrentPlaybackSessionId() != currentSessionId) { + currentLocalMediaProgress = null } + listeningTimerRunning = true lastSyncTime = System.currentTimeMillis() currentPlaybackSession = playerNotificationService.getCurrentPlaybackSessionCopy() @@ -63,13 +66,30 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic } } - fun stop() { + fun stop(cb: () -> Unit) { if (!listeningTimerRunning) return Log.d(tag, "stop: Stopping listening for $currentDisplayTitle") val currentTime = playerNotificationService.getCurrentTimeSeconds() sync(currentTime) { reset() + cb() + } + } + + fun pause(cb: () -> Unit) { + if (!listeningTimerRunning) return + Log.d(tag, "pause: Pausing progress syncer for $currentDisplayTitle") + + val currentTime = playerNotificationService.getCurrentTimeSeconds() + sync(currentTime) { + listeningTimerTask?.cancel() + listeningTimerTask = null + listeningTimerRunning = false + lastSyncTime = 0L + failedSyncs = 0 + + cb() } } @@ -77,7 +97,6 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic currentPlaybackSession?.let { it.updatedAt = mediaProgress.lastUpdate it.currentTime = mediaProgress.currentTime - DeviceManager.dbManager.saveLocalPlaybackSession(it) saveLocalProgress(it) } diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerListener.kt b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerListener.kt index cc9f1e3c..302abf33 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerListener.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerListener.kt @@ -71,32 +71,36 @@ class PlayerListener(var playerNotificationService:PlayerNotificationService) : if (player.isPlaying) { Log.d(tag, "SeekBackTime: Player is playing") if (lastPauseTime > 0 && DeviceManager.deviceData.deviceSettings?.disableAutoRewind != true) { + var seekBackTime = 0L if (onSeekBack) onSeekBack = false else { Log.d(tag, "SeekBackTime: playing started now set seek back time $lastPauseTime") - var backTime = calcPauseSeekBackTime() - if (backTime > 0) { + seekBackTime = calcPauseSeekBackTime() + if (seekBackTime > 0) { // Current chapter is used so that seek back does not go back to the previous chapter val currentChapter = playerNotificationService.getCurrentBookChapter() val minSeekBackTime = currentChapter?.startMs ?: 0 val currentTime = playerNotificationService.getCurrentTime() - val newTime = currentTime - backTime + val newTime = currentTime - seekBackTime if (newTime < minSeekBackTime) { - backTime = currentTime - minSeekBackTime + seekBackTime = currentTime - minSeekBackTime } - Log.d(tag, "SeekBackTime $backTime") + Log.d(tag, "SeekBackTime $seekBackTime") onSeekBack = true - playerNotificationService.seekBackward(backTime) } } // Check if playback session still exists or sync media progress if updated val pauseLength: Long = System.currentTimeMillis() - lastPauseTime if (pauseLength > PAUSE_LEN_BEFORE_RECHECK) { - val shouldCarryOn = playerNotificationService.checkCurrentSessionProgress() + val shouldCarryOn = playerNotificationService.checkCurrentSessionProgress(seekBackTime) if (!shouldCarryOn) return } + + if (seekBackTime > 0L) { + playerNotificationService.seekBackward(seekBackTime) + } } } else { Log.d(tag, "SeekBackTime: Player not playing set last pause time") @@ -104,12 +108,13 @@ class PlayerListener(var playerNotificationService:PlayerNotificationService) : } // Start/stop progress sync interval - Log.d(tag, "Playing ${playerNotificationService.getCurrentBookTitle()}") if (player.isPlaying) { player.volume = 1F // Volume on sleep timer might have decreased this playerNotificationService.mediaProgressSyncer.start() } else { - playerNotificationService.mediaProgressSyncer.stop() + playerNotificationService.mediaProgressSyncer.pause { + Log.d(tag, "Media Progress Syncer paused and synced") + } } playerNotificationService.clientEventEmitter?.onPlayingUpdate(player.isPlaying) diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt index 8b0c09cf..df082706 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt @@ -550,10 +550,10 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { // Called from PlayerListener play event // check with server if progress has updated since last play and sync progress update - fun checkCurrentSessionProgress():Boolean { + fun checkCurrentSessionProgress(seekBackTime:Long):Boolean { if (currentPlaybackSession == null) return true - currentPlaybackSession?.let { playbackSession -> + mediaProgressSyncer.currentPlaybackSession?.let { playbackSession -> if (!apiHandler.isOnline() || playbackSession.isLocalLibraryItemOnly) { return true // carry on } @@ -575,16 +575,28 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { Log.d(tag, "checkCurrentSessionProgress: Media progress was updated since last play time updating from ${playbackSession.currentTime} to ${mediaProgress.currentTime}") mediaProgressSyncer.syncFromServerProgress(mediaProgress) + // Update current playback session stored in PNS since MediaProgressSyncer version is a copy + mediaProgressSyncer.currentPlaybackSession?.let { updatedPlaybackSession -> + currentPlaybackSession = updatedPlaybackSession + } + Handler(Looper.getMainLooper()).post { seekPlayer(playbackSession.currentTimeMs) + // Should already be playing + currentPlayer.volume = 1F // Volume on sleep timer might have decreased this + mediaProgressSyncer.start() + clientEventEmitter?.onPlayingUpdate(true) + } + } else { + Handler(Looper.getMainLooper()).post { + if (seekBackTime > 0L) { + seekBackward(seekBackTime) + } + // Should already be playing + currentPlayer.volume = 1F // Volume on sleep timer might have decreased this + mediaProgressSyncer.start() + clientEventEmitter?.onPlayingUpdate(true) } - } - - Handler(Looper.getMainLooper()).post { - // Should already be playing - currentPlayer.volume = 1F // Volume on sleep timer might have decreased this - mediaProgressSyncer.start() - clientEventEmitter?.onPlayingUpdate(true) } } } else { @@ -607,6 +619,10 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { } else { Log.d(tag, "checkCurrentSessionProgress: Playback session still available on server") Handler(Looper.getMainLooper()).post { + if (seekBackTime > 0L) { + seekBackward(seekBackTime) + } + currentPlayer.volume = 1F // Volume on sleep timer might have decreased this mediaProgressSyncer.start() clientEventEmitter?.onPlayingUpdate(true) @@ -673,7 +689,9 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { Log.d(tag, "closePlayback") if (mediaProgressSyncer.listeningTimerRunning) { Log.i(tag, "About to close playback so stopping media progress syncer first") - mediaProgressSyncer.stop() + mediaProgressSyncer.stop { + Log.d(tag, "Media Progress syncer stopped and synced") + } } try { diff --git a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt index b0d82226..2a36a584 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt @@ -177,7 +177,21 @@ class AbsAudioPlayer : Plugin() { Handler(Looper.getMainLooper()).post { Log.d(tag, "prepareLibraryItem: Preparing Local Media item ${jacksonMapper.writeValueAsString(it)}") val playbackSession = it.getPlaybackSession(episode) - playerNotificationService.preparePlayer(playbackSession, playWhenReady, playbackRate) + + if (playerNotificationService.mediaProgressSyncer.listeningTimerRunning) { // If progress syncing then first stop before preparing next + playerNotificationService.mediaProgressSyncer.stop { + Log.d(tag, "Media progress syncer was already syncing - stopped") + Handler(Looper.getMainLooper()).post { // TODO: This was needed again which is probably a design a flaw + playerNotificationService.preparePlayer( + playbackSession, + playWhenReady, + playbackRate + ) + } + } + } else { + playerNotificationService.preparePlayer(playbackSession, playWhenReady, playbackRate) + } } return call.resolve(JSObject()) } @@ -188,9 +202,20 @@ class AbsAudioPlayer : Plugin() { if (it == null) { call.resolve(JSObject("{\"error\":\"Server play request failed\"}")) } else { + Handler(Looper.getMainLooper()).post { - Log.d(tag, "Preparing Player TEST ${jacksonMapper.writeValueAsString(it)}") - playerNotificationService.preparePlayer(it, playWhenReady, playbackRate) + Log.d(tag, "Preparing Player playback session ${jacksonMapper.writeValueAsString(it)}") + + if (playerNotificationService.mediaProgressSyncer.listeningTimerRunning) { // If progress syncing then first stop before preparing next + playerNotificationService.mediaProgressSyncer.stop { + Log.d(tag, "Media progress syncer was already syncing - stopped") + Handler(Looper.getMainLooper()).post { // TODO: This was needed again which is probably a design a flaw + playerNotificationService.preparePlayer(it, playWhenReady, playbackRate) + } + } + } else { + playerNotificationService.preparePlayer(it, playWhenReady, playbackRate) + } } call.resolve(JSObject(jacksonMapper.writeValueAsString(it))) From fd134097a1e0b5544fcbaf6ca862653e178224e8 Mon Sep 17 00:00:00 2001 From: advplyr Date: Thu, 21 Jul 2022 18:06:33 -0500 Subject: [PATCH 22/43] Fix:Android auto load libraries handle no libraries returned, Update:Local media items cover images width alignment #279 --- .../audiobookshelf/app/media/MediaManager.kt | 41 +++++++++++-------- pages/localMedia/folders/_id.vue | 2 +- tailwind.config.js | 6 +++ 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt b/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt index 4bc3955f..4ee9bb62 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt @@ -236,32 +236,37 @@ class MediaManager(var apiHandler: ApiHandler, var ctx: Context) { serverConfigIdUsed = DeviceManager.serverConnectionConfigId loadLibraries { libraries -> - val library = libraries[0] - Log.d(tag, "Loading categories for library ${library.name} - ${library.id} - ${library.mediaType}") + if (libraries.isEmpty()) { + Log.w(tag, "No libraries returned from server request") + cb(cats) // Return download category only + } else { + val library = libraries[0] + Log.d(tag, "Loading categories for library ${library.name} - ${library.id} - ${library.mediaType}") - loadLibraryCategories(library.id) { libraryCategories -> + loadLibraryCategories(library.id) { libraryCategories -> - // Only using book or podcast library categories for now - libraryCategories.forEach { + // Only using book or podcast library categories for now + libraryCategories.forEach { - // Add items in continue listening to serverLibraryItems - if (it.id == "continue-listening") { - it.entities.forEach { libraryItemWrapper -> - val libraryItem = libraryItemWrapper as LibraryItem - if (serverLibraryItems.find { li -> li.id == libraryItem.id } == null) { - serverLibraryItems.add(libraryItem) + // Add items in continue listening to serverLibraryItems + if (it.id == "continue-listening") { + it.entities.forEach { libraryItemWrapper -> + val libraryItem = libraryItemWrapper as LibraryItem + if (serverLibraryItems.find { li -> li.id == libraryItem.id } == null) { + serverLibraryItems.add(libraryItem) + } } } + + // Log.d(tag, "Found library category ${it.label} with type ${it.type}") + if (it.type == library.mediaType) { + // Log.d(tag, "Using library category ${it.id}") + cats.add(it) + } } - // Log.d(tag, "Found library category ${it.label} with type ${it.type}") - if (it.type == library.mediaType) { - // Log.d(tag, "Using library category ${it.id}") - cats.add(it) - } + cb(cats) } - - cb(cats) } } } else { // Not connected/no internet sent downloaded cats only diff --git a/pages/localMedia/folders/_id.vue b/pages/localMedia/folders/_id.vue index 2c1e0d15..22645149 100644 --- a/pages/localMedia/folders/_id.vue +++ b/pages/localMedia/folders/_id.vue @@ -17,7 +17,7 @@