diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 571c5ee5..8b47d571 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -1,17 +1,17 @@ name: 🐞 ABS App Bug Report description: File a bug/issue and help us improve the Audiobookshelf mobile apps. -title: "[Bug]: " -labels: ["bug", "triage"] +title: '[Bug]: ' +labels: ['bug', 'triage'] body: - type: markdown attributes: - value: "## App Bug Description" + value: '## App Bug Description' - type: markdown attributes: - value: "Thank you for filing a bug report! 🐛" + value: 'Thank you for filing a bug report! 🐛' - type: markdown attributes: - value: "Join the [discord server](https://discord.gg/HQgCbd6E75) for questions or if you are not sure about a bug." + value: 'Join the [discord server](https://discord.gg/HQgCbd6E75) for questions or if you are not sure about a bug.' - type: textarea id: what-happened attributes: @@ -25,7 +25,7 @@ body: attributes: label: Steps to Reproduce the Issue description: Please help us understand how we can reliably reproduce the issue. - placeholder: "1. Go to the library page of a Podcast library and..." + placeholder: '1. Go to the library page of a Podcast library and...' validations: required: true - type: textarea @@ -38,7 +38,7 @@ body: required: true - type: markdown attributes: - value: "## Mobile Environment" + value: '## Mobile Environment' - type: input id: phone-model attributes: @@ -62,10 +62,10 @@ body: description: Please ensure your app is up to date. *If you are using a 3rd-party app, please reach out to them directly.* multiple: true options: - - Android App - 0.9.74 - - iOS App - 0.9.74 - - Android App - 0.9.73 - - iOS App - 0.9.73 + - Android App - 0.9.77 + - iOS App - 0.9.77 + - Android App - 0.9.76 + - iOS App - 0.9.76 validations: required: true - type: dropdown @@ -85,4 +85,4 @@ body: attributes: label: Additional Notes description: Anything else you want to add? - placeholder: "e.g. I have tried X, Y, and Z." + placeholder: 'e.g. I have tried X, Y, and Z.' diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index b320c89c..381871fb 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -1,14 +1,14 @@ name: 🚀 App Feature Request description: Request a feature/enhancement -title: "[Enhancement]: " -labels: ["enhancement"] +title: '[Enhancement]: ' +labels: ['enhancement'] body: - type: markdown attributes: - value: "## App Feature Request Description" + value: '## App Feature Request Description' - type: markdown attributes: - value: "Please first search in both issues & discussions for your enhancement and make sure your app is up to date." + value: 'Please first search in both issues & discussions for your enhancement and make sure your app is up to date.' - type: textarea id: describe attributes: @@ -35,7 +35,7 @@ body: required: true - type: markdown attributes: - value: "## App Current Implementation" + value: '## App Current Implementation' - type: dropdown id: version attributes: @@ -43,10 +43,10 @@ body: description: Please ensure your app is up to date. *If you are using a 3rd-party app, please reach out to them directly.* multiple: true options: - - Android App - 0.9.74 - - iOS App - 0.9.74 - - Android App - 0.9.73 - - iOS App - 0.9.73 + - Android App - 0.9.77 + - iOS App - 0.9.77 + - Android App - 0.9.76 + - iOS App - 0.9.76 validations: required: true - type: textarea diff --git a/.github/workflows/close-issues-on-release.yml b/.github/workflows/close-issues-on-release.yml new file mode 100644 index 00000000..9c590758 --- /dev/null +++ b/.github/workflows/close-issues-on-release.yml @@ -0,0 +1,20 @@ +name: Close fixed issues on release. +on: + release: + types: [published] + +permissions: + contents: read + issues: write + +jobs: + comment: + runs-on: ubuntu-latest + steps: + - name: Close issues marked as fixed upon a release. + uses: gcampbell-msft/fixed-pending-release@7fa1b75a0c04bcd4b375110522878e5f6100cff5 + with: + label: 'awaiting release' + removeLabel: true + applyToAll: true + message: Fixed in [${releaseTag}](${releaseUrl}). diff --git a/android/app/build.gradle b/android/app/build.gradle index 5a687a35..83edbece 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -28,13 +28,13 @@ android { kotlinOptions { freeCompilerArgs = ['-Xjvm-default=all'] } - compileSdkVersion rootProject.ext.compileSdkVersion - defaultConfig { + compileSdkVersion rootProject.ext.compileSdkVersion + defaultConfig { applicationId "com.audiobookshelf.app" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 105 - versionName "0.9.74-beta" + versionCode 108 + versionName "0.9.77-beta" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" manifestPlaceholders = [ "appAuthRedirectScheme": "com.audiobookshelf.app" @@ -64,8 +64,6 @@ repositories { dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs' } mavenCentral() - // TODO: Temporarily using SNAPSHOT version of Simple Storage that resolves https://github.com/anggrayudi/SimpleStorage/issues/133 - maven { url "https://oss.sonatype.org/content/repositories/snapshots" } } configurations.configureEach { @@ -120,7 +118,7 @@ dependencies { implementation 'io.github.pilgr:paperdb:2.7.2' // Simple Storage - implementation "com.anggrayudi:storage:1.5.5-SNAPSHOT" + implementation "com.anggrayudi:storage:1.5.6" // OK HTTP implementation 'com.squareup.okhttp3:okhttp:4.9.2' diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle index c12243cc..8abfd517 100644 --- a/android/app/capacitor.build.gradle +++ b/android/app/capacitor.build.gradle @@ -10,6 +10,7 @@ android { apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" dependencies { implementation project(':byteowls-capacitor-filesharer') + implementation project(':capacitor-community-volume-buttons') implementation project(':capacitor-app') implementation project(':capacitor-browser') implementation project(':capacitor-clipboard') diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index dae13fbd..3af65bd7 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ + + if (episode != null) { // Get podcast episode audio track + episode.audioTrack?.let { at -> mutableListOf(at) }?.let { tracks -> audioTracks = tracks } + } + if (audioTracks.size == 0) return false + audioTracks.forEach { + // Check that metadata is not null + if (it.metadata === null) { + return false + } + // Check that file exists + val file = File(it.metadata!!.path) + if (!file.exists()) { + return false + } + } + return true + } + @JsonIgnore fun getPlaybackSession(episode:PodcastEpisode?, deviceInfo:DeviceInfo):PlaybackSession { val localEpisodeId = episode?.id 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 a591740f..7781dfc2 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 @@ -335,11 +335,10 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { val mediaDescriptionBuilder = MediaDescriptionCompat.Builder() .setExtras(extra) .setTitle(currentPlaybackSession!!.displayTitle) - .setIconUri(coverUri) bitmap?.let { mediaDescriptionBuilder.setIconBitmap(it) - } + } ?: mediaDescriptionBuilder.setIconUri(coverUri) return mediaDescriptionBuilder.build() } @@ -903,16 +902,18 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { fun closePlayback(calledOnError:Boolean? = false) { Log.d(tag, "closePlayback") + val config = DeviceManager.serverConnectionConfig + val isLocal = mediaProgressSyncer.currentIsLocal val currentSessionId = mediaProgressSyncer.currentSessionId if (mediaProgressSyncer.listeningTimerRunning) { Log.i(tag, "About to close playback so stopping media progress syncer first") + mediaProgressSyncer.stop(calledOnError == false) { // If closing on error then do not sync progress (causes exception) Log.d(tag, "Media Progress syncer stopped") - // If not local session then close on server if (!isLocal && currentSessionId != "") { - apiHandler.closePlaybackSession(currentSessionId) { + apiHandler.closePlaybackSession(currentSessionId, config) { Log.d(tag, "Closed playback session $currentSessionId") } } @@ -920,7 +921,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { } else { // If not local session then close on server if (!isLocal && currentSessionId != "") { - apiHandler.closePlaybackSession(currentSessionId) { + apiHandler.closePlaybackSession(currentSessionId, config) { Log.d(tag, "Closed playback session $currentSessionId") } } 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 25a423ba..e51e2ee6 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 @@ -198,6 +198,9 @@ class AbsAudioPlayer : Plugin() { return call.resolve(JSObject("{\"error\":\"Podcast episode not found\"}")) } } + if (!it.hasTracks(episode)) { + return call.resolve(JSObject("{\"error\":\"No audio files found on device. Download book again to fix.\"}")) + } Handler(Looper.getMainLooper()).post { Log.d(tag, "prepareLibraryItem: Preparing Local Media item ${jacksonMapper.writeValueAsString(it)}") 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 29165012..35828180 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 @@ -196,7 +196,11 @@ class AbsFileSystem : Plugin() { if (localLibraryItem?.folderId?.startsWith("internal-") == true) { Log.d(tag, "Deleting internal library item at absolutePath $absolutePath") val file = File(absolutePath) - success = file.deleteRecursively() + success = if (file.exists()) { + file.deleteRecursively() + } else { + true + } } else { var subfolderPathToDelete = "" localLibraryItem?.folderId?.let { folderId -> @@ -218,7 +222,12 @@ class AbsFileSystem : Plugin() { } val docfile = DocumentFileCompat.fromUri(mainActivity, Uri.parse(contentUrl)) - success = docfile?.delete() == true + if (docfile?.exists() == true) { + success = docfile.delete() == true + } else { + Log.d(tag, "Folder $contentUrl doesn't exist") + success = true + } if (subfolderPathToDelete != "") { Log.d(tag, "Deleting empty subfolder at $subfolderPathToDelete") 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 9c564ae3..63ad5b3c 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 @@ -45,10 +45,17 @@ class ApiHandler(var ctx:Context) { val address = config?.address ?: DeviceManager.serverAddress val token = config?.token ?: DeviceManager.token - val request = Request.Builder() - .url("${address}$endpoint").addHeader("Authorization", "Bearer $token") - .build() - makeRequest(request, httpClient, cb) + try { + val request = Request.Builder() + .url("${address}$endpoint").addHeader("Authorization", "Bearer $token") + .build() + makeRequest(request, httpClient, cb) + } catch(e: Exception) { + e.printStackTrace() + val jsobj = JSObject() + jsobj.put("error", "Request failed: ${e.message}") + cb(jsobj) + } } private fun postRequest(endpoint:String, payload: JSObject?, config:ServerConnectionConfig?, cb: (JSObject) -> Unit) { @@ -58,23 +65,38 @@ class ApiHandler(var ctx:Context) { val requestBody = payload?.toString()?.toRequestBody(mediaType) ?: EMPTY_REQUEST val requestUrl = "${address}$endpoint" Log.d(tag, "postRequest to $requestUrl") - val request = Request.Builder().post(requestBody) - .url(requestUrl).addHeader("Authorization", "Bearer ${token}") - .build() - makeRequest(request, null, cb) + try { + val request = Request.Builder().post(requestBody) + .url(requestUrl).addHeader("Authorization", "Bearer ${token}") + .build() + makeRequest(request, null, cb) + } catch(e: Exception) { + e.printStackTrace() + val jsobj = JSObject() + jsobj.put("error", "Request failed: ${e.message}") + cb(jsobj) + } } private fun patchRequest(endpoint:String, payload: JSObject, cb: (JSObject) -> Unit) { val mediaType = "application/json; charset=utf-8".toMediaType() val requestBody = payload.toString().toRequestBody(mediaType) - val request = Request.Builder().patch(requestBody) - .url("${DeviceManager.serverAddress}$endpoint").addHeader("Authorization", "Bearer ${DeviceManager.token}") - .build() - makeRequest(request, null, cb) + try { + val request = Request.Builder().patch(requestBody) + .url("${DeviceManager.serverAddress}$endpoint").addHeader("Authorization", "Bearer ${DeviceManager.token}") + .build() + makeRequest(request, null, cb) + } catch(e: Exception) { + e.printStackTrace() + val jsobj = JSObject() + jsobj.put("error", "Request failed: ${e.message}") + cb(jsobj) + } } private fun makeRequest(request:Request, httpClient:OkHttpClient?, cb: (JSObject) -> Unit) { val client = httpClient ?: defaultClient + client.newCall(request).enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { Log.d(tag, "FAILURE TO CONNECT") @@ -424,9 +446,9 @@ class ApiHandler(var ctx:Context) { } } - fun closePlaybackSession(playbackSessionId:String, cb: (Boolean) -> Unit) { + fun closePlaybackSession(playbackSessionId:String, config:ServerConnectionConfig?, cb: (Boolean) -> Unit) { Log.d(tag, "closePlaybackSession: playbackSessionId=$playbackSessionId") - postRequest("/api/session/$playbackSessionId/close", null, null) { + postRequest("/api/session/$playbackSessionId/close", null, config) { cb(true) } } diff --git a/android/build.gradle b/android/build.gradle index 2322379e..134724a4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.7.20' + ext.kotlin_version = '2.0.0' repositories { google() diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle index e38371ae..c9e8de60 100644 --- a/android/capacitor.settings.gradle +++ b/android/capacitor.settings.gradle @@ -5,6 +5,9 @@ project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/ include ':byteowls-capacitor-filesharer' project(':byteowls-capacitor-filesharer').projectDir = new File('../node_modules/@byteowls/capacitor-filesharer/android') +include ':capacitor-community-volume-buttons' +project(':capacitor-community-volume-buttons').projectDir = new File('../node_modules/@capacitor-community/volume-buttons/android') + include ':capacitor-app' project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android') diff --git a/android/variables.gradle b/android/variables.gradle index 60f5d0a1..0d71b4b8 100644 --- a/android/variables.gradle +++ b/android/variables.gradle @@ -1,9 +1,9 @@ ext { minSdkVersion = 24 compileSdkVersion = 34 - targetSdkVersion = 33 + targetSdkVersion = 34 androidxActivityVersion = '1.7.0' - androidxAppCompatVersion = '1.6.1' + androidxAppCompatVersion = '1.7.0' androidxCoordinatorLayoutVersion = '1.2.0' androidxCoreVersion = '1.10.0' androidPlayCore = '1.9.0' @@ -13,8 +13,8 @@ ext { androidxEspressoCoreVersion = '3.5.1' cordovaAndroidVersion = '10.1.1' androidx_car_version = '1.0.0-alpha7' - androidx_core_ktx_version = '1.12.0' - androidx_media_version = '1.6.0' + androidx_core_ktx_version = '1.13.1' + androidx_media_version = '1.7.0' androidx_preference_version = '1.1.1' androidx_test_runner_version = '1.3.0' arch_lifecycle_version = '2.2.0' @@ -27,7 +27,7 @@ ext { gradle_version = '3.1.4' gson_version = '2.8.5' junit_version = '4.13' - kotlin_version = '1.8.10' + kotlin_version = '2.0.0' kotlin_coroutines_version = '1.6.4' multidex_version = '1.0.3' play_services_auth_version = '18.1.0' diff --git a/components/app/Appbar.vue b/components/app/Appbar.vue index fee86c0b..af10a670 100644 --- a/components/app/Appbar.vue +++ b/components/app/Appbar.vue @@ -7,7 +7,7 @@ arrow_back -
+

{{ currentLibraryName }}

@@ -54,8 +54,8 @@ export default { this.$store.commit('setCastAvailable', val) } }, - networkConnected() { - return this.$store.state.networkConnected + socketConnected() { + return this.$store.state.socketConnected }, currentLibrary() { return this.$store.getters['libraries/getCurrentLibrary'] @@ -160,4 +160,4 @@ export default { transform: translate(10px, 0); } } - \ No newline at end of file + diff --git a/components/app/AudioPlayer.vue b/components/app/AudioPlayer.vue index 4d9da9ca..cc34b698 100644 --- a/components/app/AudioPlayer.vue +++ b/components/app/AudioPlayer.vue @@ -50,7 +50,7 @@
- {{ bookmarks.length ? 'bookmark' : 'bookmark_border' }} + {{ bookmarks.length ? 'bookmark' : 'bookmark_border' }} bookmark @@ -375,8 +375,8 @@ export default { return secondsRemaining + 's' } }, - networkConnected() { - return this.$store.state.networkConnected + socketConnected() { + return this.$store.state.socketConnected }, mediaId() { if (this.isPodcast || !this.playbackSession) return null diff --git a/components/app/SideDrawer.vue b/components/app/SideDrawer.vue index b4a308dd..a2724997 100644 --- a/components/app/SideDrawer.vue +++ b/components/app/SideDrawer.vue @@ -171,6 +171,10 @@ export default { }, async logout() { if (this.user) { + if (this.$store.getters['getIsPlayerOpen']) { + this.$eventBus.$emit('close-stream') + } + await this.$nativeHttp.post('/logout').catch((error) => { console.error('Failed to logout', error) }) diff --git a/components/bookshelf/LazyBookshelf.vue b/components/bookshelf/LazyBookshelf.vue index cad31a21..adfdbb2c 100644 --- a/components/bookshelf/LazyBookshelf.vue +++ b/components/bookshelf/LazyBookshelf.vue @@ -8,7 +8,8 @@
-
No {{ entityName }}
+
{{ $strings.MessageNoCollections }}
+
No {{ entityName }}
{{ $strings.ButtonClearFilter }}
diff --git a/components/cards/LazyBookCard.vue b/components/cards/LazyBookCard.vue index ffe56089..de3ab7a8 100644 --- a/components/cards/LazyBookCard.vue +++ b/components/cards/LazyBookCard.vue @@ -284,7 +284,7 @@ export default { if (this.collapsedSeries) return null if (this.orderBy === 'mtimeMs') return 'Modified ' + this.$formatDate(this._libraryItem.mtimeMs) if (this.orderBy === 'birthtimeMs') return 'Born ' + this.$formatDate(this._libraryItem.birthtimeMs) - if (this.orderBy === 'addedAt') return 'Added ' + this.$formatDate(this._libraryItem.addedAt) + if (this.orderBy === 'addedAt') return this.$getString('LabelAddedDate', [this.$formatDate(this._libraryItem.addedAt)]) if (this.orderBy === 'media.duration') return 'Duration: ' + this.$elapsedPrettyExtended(this.media.duration, false) if (this.orderBy === 'size') return 'Size: ' + this.$bytesPretty(this._libraryItem.size) if (this.orderBy === 'media.numTracks') return `${this.numEpisodes} Episodes` diff --git a/components/cards/LazyListBookCard.vue b/components/cards/LazyListBookCard.vue index 449c3e9f..c44adfac 100644 --- a/components/cards/LazyListBookCard.vue +++ b/components/cards/LazyListBookCard.vue @@ -108,11 +108,7 @@ export default { }, episodes() { if (this.isPodcast) { - if (this.media.numEpisodes == 1) { - return '1 episode' - } else { - return this.media.numEpisodes + ' episodes' - } + return this.$getString('LabelNumEpisodes', [this.media.numEpisodes]) } else { return null } @@ -201,7 +197,7 @@ export default { if (this.collapsedSeries) return null if (this.orderBy === 'mtimeMs') return 'Modified ' + this.$formatDate(this._libraryItem.mtimeMs) if (this.orderBy === 'birthtimeMs') return 'Born ' + this.$formatDate(this._libraryItem.birthtimeMs) - if (this.orderBy === 'addedAt') return 'Added ' + this.$formatDate(this._libraryItem.addedAt) + if (this.orderBy === 'addedAt') return this.$getString('LabelAddedDate', [this.$formatDate(this._libraryItem.addedAt)]) if (this.orderBy === 'size') return 'Size: ' + this.$bytesPretty(this._libraryItem.size) return null }, diff --git a/components/connection/ServerConnectForm.vue b/components/connection/ServerConnectForm.vue index bc87d61b..4c686a36 100644 --- a/components/connection/ServerConnectForm.vue +++ b/components/connection/ServerConnectForm.vue @@ -486,9 +486,8 @@ export default { validateServerUrl(url, protocolOverride = null) { try { var urlObject = new URL(url) - var address = `${protocolOverride ? protocolOverride : urlObject.protocol}//${urlObject.hostname}` - if (urlObject.port) address += ':' + urlObject.port - return address + if (protocolOverride) urlObject.protocol = protocolOverride + return urlObject.href } catch (error) { console.error('Invalid URL', error) return null diff --git a/components/home/BookshelfToolbar.vue b/components/home/BookshelfToolbar.vue index 3f045efb..ff3cbef7 100644 --- a/components/home/BookshelfToolbar.vue +++ b/components/home/BookshelfToolbar.vue @@ -13,6 +13,7 @@
sort + download more_vert
@@ -144,6 +145,10 @@ export default { async changeView() { this.bookshelfListView = !this.bookshelfListView await this.$hapticsImpact() + }, + downloadSeries() { + console.log('Download Series click') + this.$eventBus.$emit('download-series-click') } }, mounted() { diff --git a/components/modals/OrderModal.vue b/components/modals/OrderModal.vue index 9cc98de6..6c40b660 100644 --- a/components/modals/OrderModal.vue +++ b/components/modals/OrderModal.vue @@ -63,6 +63,10 @@ export default { { text: this.$strings.LabelFileModified, value: 'mtimeMs' + }, + { + text: this.$strings.LabelRandomly, + value: 'random' } ], podcastItems: [ @@ -89,6 +93,10 @@ export default { { text: this.$strings.LabelFileModified, value: 'mtimeMs' + }, + { + text: this.$strings.LabelRandomly, + value: 'random' } ], episodeItems: [ diff --git a/components/modals/PodcastEpisodesFeedModal.vue b/components/modals/PodcastEpisodesFeedModal.vue index 7d0b9676..da34649b 100644 --- a/components/modals/PodcastEpisodesFeedModal.vue +++ b/components/modals/PodcastEpisodesFeedModal.vue @@ -17,7 +17,7 @@

#{{ episode.episode }}

{{ episode.title }}

{{ episode.subtitle }}

-

Published {{ episode.publishedAt ? $dateDistanceFromNow(episode.publishedAt) : 'Unknown' }}

+

{{ $getString('LabelPublishedDate', [episode.publishedAt ? $dateDistanceFromNow(episode.publishedAt) : $strings.LabelUnknown]) }}

diff --git a/components/readers/Reader.vue b/components/readers/Reader.vue index 7355bf3d..d24ce78b 100644 --- a/components/readers/Reader.vue +++ b/components/readers/Reader.vue @@ -54,9 +54,9 @@ - +
-
+

{{ $strings.HeaderEreaderSettings }}

-
+

{{ $strings.LabelLayout }}:

+
+
+

{{ $strings.LabelNavigateWithVolume }}:

+
+ +
+
+
+

{{ $strings.LabelNavigateWithVolumeWhilePlaying }}:

+
+ +
@@ -103,6 +115,7 @@ \ No newline at end of file + diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index 62dc2b8e..990775be 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -740,12 +740,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = Icons; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 31; + CURRENT_PROJECT_VERSION = 34; DEVELOPMENT_TEAM = 7UFJ7D8V6A; INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 0.9.74; + MARKETING_VERSION = 0.9.77; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.app.dev; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -764,12 +764,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = Icons; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 31; + CURRENT_PROJECT_VERSION = 34; DEVELOPMENT_TEAM = 7UFJ7D8V6A; INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 0.9.74; + MARKETING_VERSION = 0.9.77; PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.app; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; diff --git a/ios/App/Podfile b/ios/App/Podfile index b29cd4cb..5a5b31f4 100644 --- a/ios/App/Podfile +++ b/ios/App/Podfile @@ -12,6 +12,7 @@ def capacitor_pods pod 'Capacitor', :path => '../../node_modules/@capacitor/ios' pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios' pod 'ByteowlsCapacitorFilesharer', :path => '../../node_modules/@byteowls/capacitor-filesharer' + pod 'CapacitorCommunityVolumeButtons', :path => '../../node_modules/@capacitor-community/volume-buttons' pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app' pod 'CapacitorBrowser', :path => '../../node_modules/@capacitor/browser' pod 'CapacitorClipboard', :path => '../../node_modules/@capacitor/clipboard' diff --git a/ios/App/Podfile.lock b/ios/App/Podfile.lock index 7c0c98c5..c2505320 100644 --- a/ios/App/Podfile.lock +++ b/ios/App/Podfile.lock @@ -2,7 +2,7 @@ PODS: - Alamofire (5.8.1) - ByteowlsCapacitorFilesharer (5.0.0): - Capacitor - - Capacitor (5.4.0): + - Capacitor (5.6.0): - CapacitorCordova - CapacitorApp (5.0.6): - Capacitor @@ -10,7 +10,9 @@ PODS: - Capacitor - CapacitorClipboard (5.0.6): - Capacitor - - CapacitorCordova (5.4.0) + - CapacitorCommunityVolumeButtons (1.0.2): + - Capacitor + - CapacitorCordova (5.6.0) - CapacitorDialog (5.0.6): - Capacitor - CapacitorHaptics (5.0.6): @@ -21,7 +23,7 @@ PODS: - Capacitor - CapacitorStatusBar (5.0.6): - Capacitor - - CordovaPlugins (5.4.0): + - CordovaPlugins (5.6.0): - CapacitorCordova - Realm (10.47.0): - Realm/Headers (= 10.47.0) @@ -36,6 +38,7 @@ DEPENDENCIES: - "CapacitorApp (from `../../node_modules/@capacitor/app`)" - "CapacitorBrowser (from `../../node_modules/@capacitor/browser`)" - "CapacitorClipboard (from `../../node_modules/@capacitor/clipboard`)" + - "CapacitorCommunityVolumeButtons (from `../../node_modules/@capacitor-community/volume-buttons`)" - "CapacitorCordova (from `../../node_modules/@capacitor/ios`)" - "CapacitorDialog (from `../../node_modules/@capacitor/dialog`)" - "CapacitorHaptics (from `../../node_modules/@capacitor/haptics`)" @@ -62,6 +65,8 @@ EXTERNAL SOURCES: :path: "../../node_modules/@capacitor/browser" CapacitorClipboard: :path: "../../node_modules/@capacitor/clipboard" + CapacitorCommunityVolumeButtons: + :path: "../../node_modules/@capacitor-community/volume-buttons" CapacitorCordova: :path: "../../node_modules/@capacitor/ios" CapacitorDialog: @@ -80,20 +85,21 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Alamofire: 3ca42e259043ee0dc5c0cdd76c4bc568b8e42af7 ByteowlsCapacitorFilesharer: f6a773825632d65d5404a34764c4a3fd857bb176 - Capacitor: a5cd803e02b471591c81165f400ace01f40b11d3 + Capacitor: ebfc16cdb8116d04c101686b080342872da42d43 CapacitorApp: 024e1b1bea5f883d79f6330d309bc441c88ad04a CapacitorBrowser: 7a0fb6a1011abfaaf2dfedfd8248f942a8eda3d6 CapacitorClipboard: 77edf49827ea21da2a9c05c690a4a6a4d07199c4 - CapacitorCordova: 66ce22f9976de30fd816f746e9e92e07d6befafd + CapacitorCommunityVolumeButtons: 132d27a8e482898e45480b7edc882f3d26a00cb6 + CapacitorCordova: 931b48fcdbc9bc985fc2f16cec9f77c794a27729 CapacitorDialog: 0f3c15dfe9414b83bc64aef4078f1b92bcfead26 CapacitorHaptics: 1fffc1217c7e64a472d7845be50fb0c2f7d4204c CapacitorNetwork: d80b3e79bef6ec37640ee2806c19771f07ff2d0c CapacitorPreferences: f03954bcb0ff09c792909e46bff88e3183c16b10 CapacitorStatusBar: 565c0a1ebd79bb40d797606a8992b4a105885309 - CordovaPlugins: a5db67e5ac1061b9869a0efd754f2c2f776aeccc + CordovaPlugins: dae7dac59b3cce58f5a7ce3894709d8f0f824656 Realm: e43fb540ae947497e3ea8a662443256920602060 RealmSwift: 8b06ed06b5d16749ae0c4d91c0cba414a9e28189 -PODFILE CHECKSUM: 02e6ffe2f51a453ce222ee9af0e55e9448d8514c +PODFILE CHECKSUM: d0bbe98fb520752929ffc76e7c901d54b2eed7f0 COCOAPODS: 1.12.1 diff --git a/layouts/default.vue b/layouts/default.vue index 45107c81..135df4ce 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -177,10 +177,6 @@ export default { } } }, - userLoggedOut() { - // Only cancels stream if streamining not playing downloaded - this.$eventBus.$emit('close-stream') - }, socketConnectionFailed(err) { this.$toast.error('Socket connection error: ' + err.message) }, diff --git a/package-lock.json b/package-lock.json index c4d0d795..c81cea87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,15 @@ { "name": "audiobookshelf-app", - "version": "0.9.74-beta", + "version": "0.9.77-beta", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "audiobookshelf-app", - "version": "0.9.74-beta", + "version": "0.9.77-beta", "dependencies": { "@byteowls/capacitor-filesharer": "^5.0.0", + "@capacitor-community/volume-buttons": "^1.0.2", "@capacitor/android": "^5.0.0", "@capacitor/app": "^5.0.6", "@capacitor/browser": "^5.1.0", @@ -1979,6 +1980,18 @@ "@capacitor/core": ">=5" } }, + "node_modules/@capacitor-community/volume-buttons": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@capacitor-community/volume-buttons/-/volume-buttons-1.0.2.tgz", + "integrity": "sha512-weEwVCgMEdkYF9uWOeZmA3kXltXSbiGlLPTmygF6NMcL1VUg1vBsiCIaikeI5XRne5V4q8UeEda83EfW7eb46g==", + "engines": { + "node": ">=16.0.0", + "npm": ">=8.0.0" + }, + "peerDependencies": { + "@capacitor/core": "^5.0.0" + } + }, "node_modules/@capacitor/android": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.6.0.tgz", diff --git a/package.json b/package.json index 32c27c54..63411faa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "audiobookshelf-app", - "version": "0.9.74-beta", + "version": "0.9.77-beta", "author": "advplyr", "scripts": { "dev": "nuxt --hostname 0.0.0.0 --port 1337", @@ -14,6 +14,7 @@ }, "dependencies": { "@byteowls/capacitor-filesharer": "^5.0.0", + "@capacitor-community/volume-buttons": "^1.0.2", "@capacitor/android": "^5.0.0", "@capacitor/app": "^5.0.6", "@capacitor/browser": "^5.1.0", diff --git a/pages/bookshelf/add-podcast.vue b/pages/bookshelf/add-podcast.vue index cff78b5e..712edd8e 100644 --- a/pages/bookshelf/add-podcast.vue +++ b/pages/bookshelf/add-podcast.vue @@ -3,11 +3,11 @@