diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml
new file mode 100644
index 00000000..55b65a30
--- /dev/null
+++ b/.github/workflows/publish.yaml
@@ -0,0 +1,65 @@
+name: Publish
+
+on:
+ push:
+ tags:
+ - v*
+
+jobs:
+ publish:
+ name: Publish
+ runs-on: ubuntu-22.04
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: 3.3.0
+ bundler-cache: true
+
+ - name: Validate Gradle Wrapper
+ uses: gradle/wrapper-validation-action@v2
+
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
+ with:
+ java-version: 17
+ distribution: temurin
+
+ - name: Set up Gradle
+ uses: gradle/actions/setup-gradle@v3
+
+ - name: Decode keystore file
+ uses: timheuer/base64-to-file@v1
+ id: findroid_keystore
+ with:
+ fileName: 'findroid-keystore.jks'
+ encodedString: ${{ secrets.FINDROID_KEYSTORE }}
+
+ - name: Decode Play API credentials file
+ uses: timheuer/base64-to-file@v1
+ id: findroid_play_api_credentials
+ with:
+ fileName: 'findroid-play-api-credentials.json'
+ encodedString: ${{ secrets.FINDROID_PLAY_API_CREDENTIALS }}
+
+ - name: Build and publish
+ run: bundle exec fastlane publish
+ env:
+ FINDROID_KEYSTORE: ${{ steps.findroid_keystore.outputs.filePath }}
+ FINDROID_KEYSTORE_PASSWORD: ${{ secrets.FINDROID_KEYSTORE_PASSWORD }}
+ FINDROID_KEY_ALIAS: ${{ secrets.FINDROID_KEY_ALIAS }}
+ FINDROID_KEY_PASSWORD: ${{ secrets.FINDROID_KEY_PASSWORD }}
+ FINDROID_PLAY_API_CREDENTIALS: ${{ steps.findroid_play_api_credentials.outputs.filePath }}
+
+ - name: Create release
+ uses: softprops/action-gh-release@v2
+ with:
+ draft: true
+ files: |
+ ./app/phone/build/outputs/apk/libre/release/findroid-${{ github.ref_name }}-libre-arm64-v8a.apk
+ ./app/phone/build/outputs/apk/libre/release/findroid-${{ github.ref_name }}-libre-armeabi-v7a.apk
+ ./app/phone/build/outputs/apk/libre/release/findroid-${{ github.ref_name }}-libre-x86_64.apk
+ ./app/phone/build/outputs/apk/libre/release/findroid-${{ github.ref_name }}-libre-x86.apk
diff --git a/.gitignore b/.gitignore
index 16dcd122..69c4d737 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,4 +30,10 @@ render.experimental.xml
google-services.json
# Android Profiling
-*.hprof
\ No newline at end of file
+*.hprof
+
+# Fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 00000000..adc90d98
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,3 @@
+source "https://rubygems.org"
+
+gem "fastlane"
\ No newline at end of file
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 00000000..712d595b
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,218 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ CFPropertyList (3.0.7)
+ base64
+ nkf
+ rexml
+ addressable (2.8.6)
+ public_suffix (>= 2.0.2, < 6.0)
+ artifactory (3.0.17)
+ atomos (0.1.3)
+ aws-eventstream (1.3.0)
+ aws-partitions (1.913.0)
+ aws-sdk-core (3.191.6)
+ aws-eventstream (~> 1, >= 1.3.0)
+ aws-partitions (~> 1, >= 1.651.0)
+ aws-sigv4 (~> 1.8)
+ jmespath (~> 1, >= 1.6.1)
+ aws-sdk-kms (1.79.0)
+ aws-sdk-core (~> 3, >= 3.191.0)
+ aws-sigv4 (~> 1.1)
+ aws-sdk-s3 (1.146.1)
+ aws-sdk-core (~> 3, >= 3.191.0)
+ aws-sdk-kms (~> 1)
+ aws-sigv4 (~> 1.8)
+ aws-sigv4 (1.8.0)
+ aws-eventstream (~> 1, >= 1.0.2)
+ babosa (1.0.4)
+ base64 (0.2.0)
+ claide (1.1.0)
+ colored (1.2)
+ colored2 (3.1.2)
+ commander (4.6.0)
+ highline (~> 2.0.0)
+ declarative (0.0.20)
+ digest-crc (0.6.5)
+ rake (>= 12.0.0, < 14.0.0)
+ domain_name (0.6.20240107)
+ dotenv (2.8.1)
+ emoji_regex (3.2.3)
+ excon (0.110.0)
+ faraday (1.10.3)
+ faraday-em_http (~> 1.0)
+ faraday-em_synchrony (~> 1.0)
+ faraday-excon (~> 1.1)
+ faraday-httpclient (~> 1.0)
+ faraday-multipart (~> 1.0)
+ faraday-net_http (~> 1.0)
+ faraday-net_http_persistent (~> 1.0)
+ faraday-patron (~> 1.0)
+ faraday-rack (~> 1.0)
+ faraday-retry (~> 1.0)
+ ruby2_keywords (>= 0.0.4)
+ faraday-cookie_jar (0.0.7)
+ faraday (>= 0.8.0)
+ http-cookie (~> 1.0.0)
+ faraday-em_http (1.0.0)
+ faraday-em_synchrony (1.0.0)
+ faraday-excon (1.1.0)
+ faraday-httpclient (1.0.1)
+ faraday-multipart (1.0.4)
+ multipart-post (~> 2)
+ faraday-net_http (1.0.1)
+ faraday-net_http_persistent (1.2.0)
+ faraday-patron (1.0.0)
+ faraday-rack (1.0.0)
+ faraday-retry (1.0.3)
+ faraday_middleware (1.2.0)
+ faraday (~> 1.0)
+ fastimage (2.3.1)
+ fastlane (2.220.0)
+ CFPropertyList (>= 2.3, < 4.0.0)
+ addressable (>= 2.8, < 3.0.0)
+ artifactory (~> 3.0)
+ aws-sdk-s3 (~> 1.0)
+ babosa (>= 1.0.3, < 2.0.0)
+ bundler (>= 1.12.0, < 3.0.0)
+ colored (~> 1.2)
+ commander (~> 4.6)
+ dotenv (>= 2.1.1, < 3.0.0)
+ emoji_regex (>= 0.1, < 4.0)
+ excon (>= 0.71.0, < 1.0.0)
+ faraday (~> 1.0)
+ faraday-cookie_jar (~> 0.0.6)
+ faraday_middleware (~> 1.0)
+ fastimage (>= 2.1.0, < 3.0.0)
+ gh_inspector (>= 1.1.2, < 2.0.0)
+ google-apis-androidpublisher_v3 (~> 0.3)
+ google-apis-playcustomapp_v1 (~> 0.1)
+ google-cloud-env (>= 1.6.0, < 2.0.0)
+ google-cloud-storage (~> 1.31)
+ highline (~> 2.0)
+ http-cookie (~> 1.0.5)
+ json (< 3.0.0)
+ jwt (>= 2.1.0, < 3)
+ mini_magick (>= 4.9.4, < 5.0.0)
+ multipart-post (>= 2.0.0, < 3.0.0)
+ naturally (~> 2.2)
+ optparse (>= 0.1.1, < 1.0.0)
+ plist (>= 3.1.0, < 4.0.0)
+ rubyzip (>= 2.0.0, < 3.0.0)
+ security (= 0.1.5)
+ simctl (~> 1.6.3)
+ terminal-notifier (>= 2.0.0, < 3.0.0)
+ terminal-table (~> 3)
+ tty-screen (>= 0.6.3, < 1.0.0)
+ tty-spinner (>= 0.8.0, < 1.0.0)
+ word_wrap (~> 1.0.0)
+ xcodeproj (>= 1.13.0, < 2.0.0)
+ xcpretty (~> 0.3.0)
+ xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
+ gh_inspector (1.1.3)
+ google-apis-androidpublisher_v3 (0.54.0)
+ google-apis-core (>= 0.11.0, < 2.a)
+ google-apis-core (0.11.3)
+ addressable (~> 2.5, >= 2.5.1)
+ googleauth (>= 0.16.2, < 2.a)
+ httpclient (>= 2.8.1, < 3.a)
+ mini_mime (~> 1.0)
+ representable (~> 3.0)
+ retriable (>= 2.0, < 4.a)
+ rexml
+ google-apis-iamcredentials_v1 (0.17.0)
+ google-apis-core (>= 0.11.0, < 2.a)
+ google-apis-playcustomapp_v1 (0.13.0)
+ google-apis-core (>= 0.11.0, < 2.a)
+ google-apis-storage_v1 (0.31.0)
+ google-apis-core (>= 0.11.0, < 2.a)
+ google-cloud-core (1.7.0)
+ google-cloud-env (>= 1.0, < 3.a)
+ google-cloud-errors (~> 1.0)
+ google-cloud-env (1.6.0)
+ faraday (>= 0.17.3, < 3.0)
+ google-cloud-errors (1.4.0)
+ google-cloud-storage (1.47.0)
+ addressable (~> 2.8)
+ digest-crc (~> 0.4)
+ google-apis-iamcredentials_v1 (~> 0.1)
+ google-apis-storage_v1 (~> 0.31.0)
+ google-cloud-core (~> 1.6)
+ googleauth (>= 0.16.2, < 2.a)
+ mini_mime (~> 1.0)
+ googleauth (1.8.1)
+ faraday (>= 0.17.3, < 3.a)
+ jwt (>= 1.4, < 3.0)
+ multi_json (~> 1.11)
+ os (>= 0.9, < 2.0)
+ signet (>= 0.16, < 2.a)
+ highline (2.0.3)
+ http-cookie (1.0.5)
+ domain_name (~> 0.5)
+ httpclient (2.8.3)
+ jmespath (1.6.2)
+ json (2.7.2)
+ jwt (2.8.1)
+ base64
+ mini_magick (4.12.0)
+ mini_mime (1.1.5)
+ multi_json (1.15.0)
+ multipart-post (2.4.0)
+ nanaimo (0.3.0)
+ naturally (2.2.1)
+ nkf (0.2.0)
+ optparse (0.4.0)
+ os (1.1.4)
+ plist (3.7.1)
+ public_suffix (5.0.5)
+ rake (13.2.1)
+ representable (3.2.0)
+ declarative (< 0.1.0)
+ trailblazer-option (>= 0.1.1, < 0.2.0)
+ uber (< 0.2.0)
+ retriable (3.1.2)
+ rexml (3.2.6)
+ rouge (2.0.7)
+ ruby2_keywords (0.0.5)
+ rubyzip (2.3.2)
+ security (0.1.5)
+ signet (0.19.0)
+ addressable (~> 2.8)
+ faraday (>= 0.17.5, < 3.a)
+ jwt (>= 1.5, < 3.0)
+ multi_json (~> 1.10)
+ simctl (1.6.10)
+ CFPropertyList
+ naturally
+ terminal-notifier (2.0.0)
+ terminal-table (3.0.2)
+ unicode-display_width (>= 1.1.1, < 3)
+ trailblazer-option (0.1.2)
+ tty-cursor (0.7.1)
+ tty-screen (0.8.2)
+ tty-spinner (0.9.3)
+ tty-cursor (~> 0.7)
+ uber (0.1.0)
+ unicode-display_width (2.5.0)
+ word_wrap (1.0.0)
+ xcodeproj (1.24.0)
+ CFPropertyList (>= 2.3.3, < 4.0)
+ atomos (~> 0.1.3)
+ claide (>= 1.0.2, < 2.0)
+ colored2 (~> 3.1)
+ nanaimo (~> 0.3.0)
+ rexml (~> 3.2.4)
+ xcpretty (0.3.0)
+ rouge (~> 2.0.7)
+ xcpretty-travis-formatter (1.0.1)
+ xcpretty (~> 0.2, >= 0.0.7)
+
+PLATFORMS
+ ruby
+ x86_64-linux
+
+DEPENDENCIES
+ fastlane
+
+BUNDLED WITH
+ 2.5.4
diff --git a/README.md b/README.md
index 9c7f0390..10842fa3 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ I am developing this application in my spare time.
**This project is in its early stages so expect bugs.**
-


+

## Screenshots
| Home | Library | Movie | Season | Episode |
@@ -29,7 +29,7 @@ I am developing this application in my spare time.
- ExoPlayer
- Video codecs: H.263, H.264, H.265, VP8, VP9, AV1
- Support depends on Android device
- - Audio codecs: Vorbis, Opus, FLAC, ALAC, PCM, MP3, AMR-NB, AMR-WB, AAC, AC-3, E-AC-3, DTS, DTS-HD, TrueHD
+ - Audio codecs: Vorbis, Opus, FLAC, ALAC, PCM, MP3, AAC, AC-3, E-AC-3, DTS, DTS-HD, TrueHD
- Support provided by ExoPlayer FFmpeg extension
- Subtitle codecs: SRT, VTT, SSA/ASS, PGSSUB
- SSA/ASS has limited styling support see [this issue](https://github.com/google/ExoPlayer/issues/8435)
diff --git a/app/phone/build.gradle.kts b/app/phone/build.gradle.kts
index 2782a57a..b9a5e35e 100644
--- a/app/phone/build.gradle.kts
+++ b/app/phone/build.gradle.kts
@@ -21,6 +21,20 @@ android {
versionCode = Versions.appCode
versionName = Versions.appName
+
+ testInstrumentationRunner = "dev.jdtech.jellyfin.HiltTestRunner"
+ }
+
+ applicationVariants.all {
+ val variant = this
+ variant.outputs
+ .map { it as com.android.build.gradle.internal.api.BaseVariantOutputImpl }
+ .forEach { output ->
+ if (variant.buildType.name == "release") {
+ val outputFileName = "findroid-v${variant.versionName}-${variant.flavorName}-${output.getFilter("ABI")}.apk"
+ output.outputFileName = outputFileName
+ }
+ }
}
buildTypes {
@@ -47,9 +61,6 @@ android {
dimension = "variant"
isDefault = true
}
- register("huawei") {
- dimension = "variant"
- }
}
splits {
@@ -61,6 +72,8 @@ android {
}
compileOptions {
+ isCoreLibraryDesugaringEnabled = true
+
sourceCompatibility = Versions.java
targetCompatibility = Versions.java
}
@@ -109,7 +122,14 @@ dependencies {
implementation(libs.jellyfin.core)
compileOnly(libs.libmpv)
implementation(libs.material)
+ implementation(libs.media3.ffmpeg.decoder)
implementation(libs.timber)
- implementation(rootProject.files("libs/lib-decoder-ffmpeg-release.aar"))
+ coreLibraryDesugaring(libs.android.desugar.jdk)
+
+ androidTestImplementation(libs.androidx.room.runtime)
+ androidTestImplementation(libs.junit)
+ androidTestImplementation(libs.bundles.androidx.test)
+ androidTestImplementation(libs.hilt.android.testing)
+ kspTest(libs.hilt.android.compiler)
}
diff --git a/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/HiltTestRunner.kt b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/HiltTestRunner.kt
new file mode 100644
index 00000000..e7f52dcb
--- /dev/null
+++ b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/HiltTestRunner.kt
@@ -0,0 +1,16 @@
+package dev.jdtech.jellyfin
+
+import android.app.Application
+import android.content.Context
+import androidx.test.runner.AndroidJUnitRunner
+import dagger.hilt.android.testing.HiltTestApplication
+
+class HiltTestRunner : AndroidJUnitRunner() {
+ override fun newApplication(
+ cl: ClassLoader?,
+ className: String?,
+ context: Context?,
+ ): Application {
+ return super.newApplication(cl, HiltTestApplication::class.java.name, context)
+ }
+}
diff --git a/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/MainActivityTest.kt b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/MainActivityTest.kt
new file mode 100644
index 00000000..486b6759
--- /dev/null
+++ b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/MainActivityTest.kt
@@ -0,0 +1,95 @@
+package dev.jdtech.jellyfin
+
+import android.util.Log
+import androidx.hilt.work.HiltWorkerFactory
+import androidx.test.core.app.launchActivity
+import androidx.test.espresso.Espresso
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.ViewActions.click
+import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
+import androidx.test.espresso.action.ViewActions.typeText
+import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
+import androidx.test.espresso.matcher.ViewMatchers.isEnabled
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.work.Configuration
+import androidx.work.testing.SynchronousExecutor
+import androidx.work.testing.WorkManagerTestInitHelper
+import dagger.hilt.android.testing.HiltAndroidRule
+import dagger.hilt.android.testing.HiltAndroidTest
+import dagger.hilt.android.testing.UninstallModules
+import dev.jdtech.jellyfin.di.DatabaseModule
+import org.hamcrest.CoreMatchers.allOf
+import org.hamcrest.CoreMatchers.not
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import javax.inject.Inject
+
+@HiltAndroidTest
+@UninstallModules(DatabaseModule::class)
+class MainActivityTest {
+ @get:Rule
+ var hiltRule = HiltAndroidRule(this)
+
+ @Inject
+ lateinit var workerFactory: HiltWorkerFactory
+
+ @Before
+ fun setUp() {
+ hiltRule.inject()
+
+ val context = InstrumentationRegistry.getInstrumentation().targetContext
+ val config = Configuration.Builder()
+ .setWorkerFactory(workerFactory)
+ .setMinimumLoggingLevel(Log.DEBUG)
+ .setExecutor(SynchronousExecutor())
+ .build()
+
+ // Initialize WorkManager for instrumentation tests.
+ WorkManagerTestInitHelper.initializeTestWorkManager(context, config)
+ }
+
+ @Test
+ fun testMainFlow() {
+ launchActivity().use {
+ // Wait for the app to load
+ waitForElement(allOf(withId(R.id.edit_text_server_address), isDisplayed()))
+
+ // Connect to demo server
+ onView(withId(R.id.edit_text_server_address)).perform(typeText("https://demo.jellyfin.org/stable"), closeSoftKeyboard())
+ onView(withId(R.id.button_connect)).perform(click())
+
+ // Connecting to the server
+ waitForElement(allOf(withId(R.id.edit_text_username), isDisplayed()))
+
+ // Login
+ onView(withId(R.id.edit_text_username)).perform(typeText("demo"), closeSoftKeyboard())
+ onView(withId(R.id.button_login)).perform(click())
+
+ // Navigate to My media
+ waitForElement(allOf(withText("Continue Watching"), isDisplayed()))
+ onView(withId(R.id.mediaFragment)).perform(click())
+
+ // Navigate to movies
+ waitForElement(allOf(withText("Movies"), isDisplayed()))
+ onView(withText("Movies")).perform(click())
+
+ // Navigate to Battle of the Stars
+ waitForElement(allOf(withText("Battle of the Stars"), isDisplayed()))
+ onView(withText("Battle of the Stars")).perform(click())
+
+ // Play the movie
+ waitForElement(allOf(withId(R.id.play_button), isEnabled()))
+ onView(withId(R.id.play_button)).perform(click())
+
+ // Wait for movie to start playing
+ waitForElement(allOf(withId(androidx.media3.ui.R.id.exo_buffering), isDisplayed()))
+ waitForElement(allOf(withId(androidx.media3.ui.R.id.exo_buffering), not(isDisplayed())))
+
+ // Navigate back
+ Espresso.pressBack()
+ }
+ }
+}
diff --git a/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/ViewPropertyChangeCallback.kt b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/ViewPropertyChangeCallback.kt
new file mode 100644
index 00000000..a3a0c8b1
--- /dev/null
+++ b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/ViewPropertyChangeCallback.kt
@@ -0,0 +1,64 @@
+package dev.jdtech.jellyfin
+
+import android.view.View
+import android.view.ViewTreeObserver
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.IdlingRegistry
+import androidx.test.espresso.IdlingResource
+import androidx.test.espresso.UiController
+import androidx.test.espresso.ViewAction
+import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
+import androidx.test.espresso.matcher.ViewMatchers.isRoot
+import org.hamcrest.CoreMatchers
+import org.hamcrest.Matcher
+import org.hamcrest.StringDescription
+
+private class ViewPropertyChangeCallback(private val matcher: Matcher, private val view: View) : IdlingResource, ViewTreeObserver.OnDrawListener {
+ private lateinit var callback: IdlingResource.ResourceCallback
+ private var matched = false
+
+ override fun getName() = "View property change callback"
+
+ override fun isIdleNow() = matched
+
+ override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback) {
+ this.callback = callback
+ }
+
+ override fun onDraw() {
+ matched = matcher.matches(view)
+ callback.onTransitionToIdle()
+ }
+}
+
+fun waitUntil(matcher: Matcher): ViewAction = object : ViewAction {
+ override fun getConstraints(): Matcher {
+ return CoreMatchers.any(View::class.java)
+ }
+
+ override fun getDescription(): String {
+ return StringDescription().let {
+ matcher.describeTo(it)
+ "wait until: $it"
+ }
+ }
+
+ override fun perform(uiController: UiController, view: View) {
+ if (!matcher.matches(view)) {
+ ViewPropertyChangeCallback(matcher, view).run {
+ try {
+ IdlingRegistry.getInstance().register(this)
+ view.viewTreeObserver.addOnDrawListener(this)
+ uiController.loopMainThreadUntilIdle()
+ } finally {
+ view.viewTreeObserver.removeOnDrawListener(this)
+ IdlingRegistry.getInstance().unregister(this)
+ }
+ }
+ }
+ }
+}
+
+fun waitForElement(matcher: Matcher) {
+ onView(isRoot()).perform(waitUntil(hasDescendant(matcher)))
+}
diff --git a/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/di/DatabaseTestModule.kt b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/di/DatabaseTestModule.kt
new file mode 100644
index 00000000..e5a367b1
--- /dev/null
+++ b/app/phone/src/androidTest/kotlin/dev/jdtech/jellyfin/di/DatabaseTestModule.kt
@@ -0,0 +1,29 @@
+package dev.jdtech.jellyfin.di
+
+import android.content.Context
+import androidx.room.Room
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.components.SingletonComponent
+import dev.jdtech.jellyfin.database.ServerDatabase
+import dev.jdtech.jellyfin.database.ServerDatabaseDao
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+object DatabaseTestModule {
+ @Singleton
+ @Provides
+ fun provideServerDatabaseDao(@ApplicationContext app: Context): ServerDatabaseDao {
+ return Room.inMemoryDatabaseBuilder(
+ app.applicationContext,
+ ServerDatabase::class.java,
+ )
+ .fallbackToDestructiveMigration()
+ .allowMainThreadQueries()
+ .build()
+ .getServerDatabaseDao()
+ }
+}
diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt
index d8aa8293..3919b1e5 100644
--- a/app/phone/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt
+++ b/app/phone/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt
@@ -200,7 +200,9 @@ class PlayerActivity : BasePlayerActivity() {
is PlayerEvents.NavigateBack -> finish()
is PlayerEvents.IsPlayingChanged -> {
if (appPreferences.playerPipGesture) {
- setPictureInPictureParams(pipParams(event.isPlaying))
+ try {
+ setPictureInPictureParams(pipParams(event.isPlaying))
+ } catch (_: IllegalArgumentException) { }
}
}
}
diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/adapters/EpisodeListAdapter.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/adapters/EpisodeListAdapter.kt
index 4df73fbb..bddb8781 100644
--- a/app/phone/src/main/java/dev/jdtech/jellyfin/adapters/EpisodeListAdapter.kt
+++ b/app/phone/src/main/java/dev/jdtech/jellyfin/adapters/EpisodeListAdapter.kt
@@ -1,5 +1,6 @@
package dev.jdtech.jellyfin.adapters
+import android.text.Html.fromHtml
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
@@ -45,7 +46,7 @@ class EpisodeListAdapter(
binding.root.context.getString(CoreR.string.episode_name_with_end, episode.indexNumber, episode.indexNumberEnd, episode.name)
}
- binding.episodeOverview.text = episode.overview
+ binding.episodeOverview.text = fromHtml(episode.overview, 0)
if (episode.playbackPositionTicks > 0) {
binding.progressBar.layoutParams.width = TypedValue.applyDimension(
diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/CollectionFragment.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/CollectionFragment.kt
index 69b57fed..c8bc3bda 100644
--- a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/CollectionFragment.kt
+++ b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/CollectionFragment.kt
@@ -24,6 +24,7 @@ import dev.jdtech.jellyfin.utils.checkIfLoginRequired
import dev.jdtech.jellyfin.viewmodels.CollectionViewModel
import kotlinx.coroutines.launch
import timber.log.Timber
+import dev.jdtech.jellyfin.core.R as CoreR
@AndroidEntryPoint
class CollectionFragment : Fragment() {
@@ -40,6 +41,8 @@ class CollectionFragment : Fragment() {
): View {
binding = FragmentFavoriteBinding.inflate(inflater, container, false)
+ binding.noFavoritesText.text = getString(CoreR.string.collection_no_media)
+
binding.favoritesRecyclerView.adapter = FavoritesListAdapter { item ->
navigateToMediaItem(item)
}
diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt
index c9c1066a..17c61caf 100644
--- a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt
+++ b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/EpisodeBottomSheetFragment.kt
@@ -2,6 +2,7 @@ package dev.jdtech.jellyfin.fragments
import android.app.DownloadManager
import android.os.Bundle
+import android.text.Html.fromHtml
import android.text.format.Formatter
import android.util.TypedValue
import android.view.LayoutInflater
@@ -285,11 +286,13 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() {
}
binding.seriesName.text = episode.seriesName
- binding.overview.text = episode.overview
+ binding.overview.text = fromHtml(episode.overview, 0)
binding.year.text = formatDateTime(episode.premiereDate)
binding.playtime.text = getString(CoreR.string.runtime_minutes, episode.runtimeTicks.div(600000000))
- binding.communityRating.isVisible = episode.communityRating != null
- binding.communityRating.text = episode.communityRating.toString()
+ episode.communityRating?.also {
+ binding.communityRating.text = episode.communityRating.toString()
+ binding.communityRating.isVisible = true
+ }
binding.missingIcon.isVisible = false
if (appPreferences.displayExtraInfo) {
diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt
index be6d3d40..b383842f 100644
--- a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt
+++ b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt
@@ -4,6 +4,7 @@ import android.app.DownloadManager
import android.content.Intent
import android.net.Uri
import android.os.Bundle
+import android.text.Html.fromHtml
import android.text.format.Formatter
import android.view.LayoutInflater
import android.view.View
@@ -276,7 +277,6 @@ class MovieFragment : Fragment() {
if (item.trailer != null) {
binding.itemActions.trailerButton.isVisible = true
}
- binding.communityRating.isVisible = item.communityRating != null
binding.actors.isVisible = actors.isNotEmpty()
binding.itemActions.playButton.isEnabled = item.canPlay && item.sources.isNotEmpty()
@@ -309,7 +309,10 @@ class MovieFragment : Fragment() {
binding.playtime.text = runTime
}
binding.officialRating.text = item.officialRating
- binding.communityRating.text = item.communityRating.toString()
+ item.communityRating?.also {
+ binding.communityRating.text = it.toString()
+ binding.communityRating.isVisible = true
+ }
videoMetadata.let {
with(binding) {
@@ -379,7 +382,7 @@ class MovieFragment : Fragment() {
binding.info.sizeGroup.isVisible = size != null
}
- binding.info.description.text = item.overview
+ binding.info.description.text = fromHtml(item.overview, 0)
binding.info.genres.text = genresString
binding.info.genresGroup.isVisible = item.genres.isNotEmpty()
binding.info.director.text = director?.name
diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/ShowFragment.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/ShowFragment.kt
index 21be0c63..242f4c60 100644
--- a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/ShowFragment.kt
+++ b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/ShowFragment.kt
@@ -3,6 +3,7 @@ package dev.jdtech.jellyfin.fragments
import android.content.Intent
import android.net.Uri
import android.os.Bundle
+import android.text.Html.fromHtml
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -170,7 +171,6 @@ class ShowFragment : Fragment() {
if (item.trailer != null) {
binding.itemActions.trailerButton.isVisible = true
}
- binding.communityRating.isVisible = item.communityRating != null
binding.actors.isVisible = actors.isNotEmpty()
// TODO currently the sources of a show is always empty, we need a way to check if sources are available
@@ -212,9 +212,12 @@ class ShowFragment : Fragment() {
binding.playtime.text = runTime
}
binding.officialRating.text = item.officialRating
- binding.communityRating.text = item.communityRating.toString()
+ item.communityRating?.also {
+ binding.communityRating.text = item.communityRating.toString()
+ binding.communityRating.isVisible = true
+ }
- binding.info.description.text = item.overview
+ binding.info.description.text = fromHtml(item.overview, 0)
binding.info.genres.text = genresString
binding.info.genresGroup.isVisible = item.genres.isNotEmpty()
binding.info.director.text = director?.name
diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt
index 75c1a531..4a96003b 100644
--- a/buildSrc/src/main/kotlin/Versions.kt
+++ b/buildSrc/src/main/kotlin/Versions.kt
@@ -1,8 +1,8 @@
import org.gradle.api.JavaVersion
object Versions {
- const val appCode = 23
- const val appName = "2024.02"
+ const val appCode = 25
+ const val appName = "0.14.2"
const val compileSdk = 34
const val buildTools = "34.0.0"
@@ -11,6 +11,6 @@ object Versions {
val java = JavaVersion.VERSION_17
- const val composeCompiler = "1.5.10"
+ const val composeCompiler = "1.5.11"
const val ktlint = "0.50.0"
}
\ No newline at end of file
diff --git a/core/build.gradle.kts b/core/build.gradle.kts
index 04903fa4..33930d84 100644
--- a/core/build.gradle.kts
+++ b/core/build.gradle.kts
@@ -29,7 +29,6 @@ android {
flavorDimensions += "variant"
productFlavors {
register("libre")
- register("huawei")
}
compileOptions {
diff --git a/core/src/huawei/res/drawable/ic_banner.xml b/core/src/huawei/res/drawable/ic_banner.xml
deleted file mode 100644
index 68ab6899..00000000
--- a/core/src/huawei/res/drawable/ic_banner.xml
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/core/src/huawei/res/drawable/ic_banner_foreground.xml b/core/src/huawei/res/drawable/ic_banner_foreground.xml
deleted file mode 100644
index 29c06075..00000000
--- a/core/src/huawei/res/drawable/ic_banner_foreground.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/core/src/huawei/res/drawable/ic_launcher_foreground.xml b/core/src/huawei/res/drawable/ic_launcher_foreground.xml
deleted file mode 100644
index 1cd1c375..00000000
--- a/core/src/huawei/res/drawable/ic_launcher_foreground.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/core/src/main/java/dev/jdtech/jellyfin/dialogs/AddServerAddressDialog.kt b/core/src/main/java/dev/jdtech/jellyfin/dialogs/AddServerAddressDialog.kt
index fc10227b..d6f6183c 100644
--- a/core/src/main/java/dev/jdtech/jellyfin/dialogs/AddServerAddressDialog.kt
+++ b/core/src/main/java/dev/jdtech/jellyfin/dialogs/AddServerAddressDialog.kt
@@ -2,6 +2,7 @@ package dev.jdtech.jellyfin.dialogs
import android.app.Dialog
import android.os.Bundle
+import android.text.InputType
import android.widget.EditText
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@@ -15,13 +16,14 @@ class AddServerAddressDialog(
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val editText = EditText(this.context)
editText.hint = "http://:8096"
+ editText.inputType = InputType.TYPE_TEXT_VARIATION_URI
return activity?.let { activity ->
val builder = MaterialAlertDialogBuilder(activity)
builder
.setTitle(getString(R.string.add_server_address))
.setView(editText)
.setPositiveButton(getString(R.string.add)) { _, _ ->
- viewModel.addAddress(editText.text.toString())
+ viewModel.addAddress(requireContext(), editText.text.toString())
}
.setNegativeButton(getString(R.string.cancel)) { _, _ ->
}
diff --git a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/CollectionViewModel.kt b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/CollectionViewModel.kt
index 9b6ed399..a858ba70 100644
--- a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/CollectionViewModel.kt
+++ b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/CollectionViewModel.kt
@@ -9,6 +9,7 @@ import dev.jdtech.jellyfin.models.FavoriteSection
import dev.jdtech.jellyfin.models.FindroidEpisode
import dev.jdtech.jellyfin.models.FindroidMovie
import dev.jdtech.jellyfin.models.FindroidShow
+import dev.jdtech.jellyfin.models.SortBy
import dev.jdtech.jellyfin.models.UiText
import dev.jdtech.jellyfin.repository.JellyfinRepository
import kotlinx.coroutines.Dispatchers
@@ -39,7 +40,10 @@ constructor(
_uiState.emit(UiState.Loading)
try {
- val items = jellyfinRepository.getItems(parentId = parentId)
+ val items = jellyfinRepository.getItems(
+ parentId = parentId,
+ sortBy = SortBy.RELEASE_DATE,
+ )
if (items.isEmpty()) {
_uiState.emit(UiState.Normal(emptyList()))
diff --git a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerAddressesViewModel.kt b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerAddressesViewModel.kt
index 4d2bc18c..b61682dc 100644
--- a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerAddressesViewModel.kt
+++ b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerAddressesViewModel.kt
@@ -1,5 +1,6 @@
package dev.jdtech.jellyfin.viewmodels
+import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -79,11 +80,19 @@ constructor(
}
}
- fun addAddress(address: String) {
+ fun addAddress(context: Context, address: String) {
viewModelScope.launch(Dispatchers.IO) {
- val serverAddress = ServerAddress(UUID.randomUUID(), currentServerId, address)
- database.insertServerAddress(serverAddress)
- loadAddresses(currentServerId)
+ try {
+ val jellyfinApi = JellyfinApi(context)
+ jellyfinApi.api.baseUrl = address
+ val systemInfo by jellyfinApi.systemApi.getPublicSystemInfo()
+ if (systemInfo.id != currentServerId) {
+ return@launch
+ }
+ val serverAddress = ServerAddress(UUID.randomUUID(), currentServerId, address)
+ database.insertServerAddress(serverAddress)
+ loadAddresses(currentServerId)
+ } catch (_: Exception) { }
}
}
}
diff --git a/core/src/main/res/values-de/strings.xml b/core/src/main/res/values-de/strings.xml
index ae19a4aa..7c2e24ca 100644
--- a/core/src/main/res/values-de/strings.xml
+++ b/core/src/main/res/values-de/strings.xml
@@ -170,4 +170,21 @@
Download stoppen
Download Indikator
%1$d-%2$d. %3$s
+ Trailer anschauen
+ Aus Favoriten entfernen
+ Keine Server gefunden
+ Keine Benutzer gefunden
+ Bild-in-Bild
+ Bist du sicher, dass du die Server Adresse \"%1$s\" entfernen möchtest?
+ Server Adresse entfernen
+ Diese Sammlung enthält keine Medien
+ Maximiert starten
+ Video standardmäßig maximiert öffnen
+ Kapitelmarker
+ Zeige Kapitelmarker in der Zeitleiste an
+ Benutzer auswählen
+ Als angesehen markieren
+ Zu Favoriten hinzufügen
+ Kapitel Geste
+ Drücke lange auf der linken/rechten Seite um Kapitel zu überspringen (überschreibt die 2x-Geschwindigkeitsgesten)
\ No newline at end of file
diff --git a/core/src/main/res/values-es-rMX/strings.xml b/core/src/main/res/values-es-rMX/strings.xml
index 5949df00..3f6eb4d6 100644
--- a/core/src/main/res/values-es-rMX/strings.xml
+++ b/core/src/main/res/values-es-rMX/strings.xml
@@ -172,4 +172,6 @@
Ocurrió un error al descargar
¿Está seguro de remover el servidor con dirección %1$s
Remover dirección del servidor
+ Ésta colección no contiene elementos
+ Gesto para cambiar capítulos
\ No newline at end of file
diff --git a/core/src/main/res/values-fr/strings.xml b/core/src/main/res/values-fr/strings.xml
index 012532b7..2a5b78a9 100644
--- a/core/src/main/res/values-fr/strings.xml
+++ b/core/src/main/res/values-fr/strings.xml
@@ -142,7 +142,7 @@
Ajouter une adresse
Ajouter l\'adresse d\'un serveur
Ajouter
- Le plugin Jellyscrub de nicknsy doit être installé sur le serveur
+ Nécessite que le plugin Jellyscrub de Nicknsy soit installé sur le serveur
temporaire
CC
Déplacement du curseur de lecture
@@ -175,4 +175,21 @@
Fenêtre flottante
Geste de retour à l\'accueil depuis la fenêtre flottante
Lors de la lecture, utilisez le bouton d\'accueil ou la navigation gestuelle pour lancer la fenêtre flottante
+ Non marqué comme joué
+ Aucun serveur trouvé
+ Aucun utilisateur trouvé
+ Sélectionner un utilisateur
+ Direct TV
+ Ajouter aux favoris
+ Cette collection ne contient aucun média
+ Ouvrir la vidéo en plein écran par défaut
+ Démarrer en plein écran
+ Appuyer longtemps sur les côtés de l\'écran pour passer le chapitre (cela remplace le geste de vitesse 2x)
+ Marqueurs de chapitre
+ Afficher les marqueurs de chapitre sur la barre temporelle
+ Lecture
+ Geste du chapitre
+ Regarder la bande annonce
+ Marquer comme joué
+ Retirer des favoris
\ No newline at end of file
diff --git a/core/src/main/res/values-hu/strings.xml b/core/src/main/res/values-hu/strings.xml
index 3fff6575..590a5dd1 100644
--- a/core/src/main/res/values-hu/strings.xml
+++ b/core/src/main/res/values-hu/strings.xml
@@ -30,7 +30,7 @@
Rendező
Írók
Szereplők & Stáb
- Szezonok
+ Évadok
Előzetes megtekintése
Megjelölés megtekintettnek, vagy nem-megtekintettnek
Kedvenc
@@ -187,4 +187,9 @@
Előzetes megtekintése
Videó megnyitása alapértelmezés szerint maximalizált módban
Indítás maximalizálva
+ Ez a gyűjtemény nem tartalmaz médiát
+ Fejezet gesztus
+ Hosszan nyomd meg a bal / jobb oldalt a fejezetek átugrására (felülírja a 2x sebesség gesztust)
+ Fejezet jelölések
+ Fejezetjelzők megjelenítése az idősávon
\ No newline at end of file
diff --git a/core/src/main/res/values-pt/strings.xml b/core/src/main/res/values-pt/strings.xml
index 0adc48c4..c1e824ec 100644
--- a/core/src/main/res/values-pt/strings.xml
+++ b/core/src/main/res/values-pt/strings.xml
@@ -2,14 +2,14 @@
Jellyfin banner
Adicionar Servidor
- Versão do servidor desactualizada: %1$s. Por favor, actualize o seu servidor
- Não é um servidor Jellyfin: %1$s
- Versão de servidor não suportada: %1$s. Por favor, actualize o seu servidor
+ Versão do servidor desatualizada: %1$s. Por favor, atualize o seu servidor
+ Não é um servidor de Jellyfin: %1$s
+ Versão de servidor não suportada: %1$s. Por favor, atualize o seu servidor
O servidor é demasiado lento para responder: %1$s
Endereço de servidor vazio
Servidor não encontrado
- O servidor não tem identificação, algo parece estar errado com o servidor
- Início de Sessão
+ O servidor não tem id, algo parece estar errado com o servidor
+ Iníciar Sessão
Selecionar servidor
Endereço de servidor
Ligar
@@ -18,18 +18,18 @@
Início
Cancelar
Remover
- Remover Servidor
+ Remover servidor
Têm a certeza que pretende remover o servidor %1$s
Favoritos
Definições
Transferências
Ver todos
Aplicação Jellyfin nativa de terceiros
- Entrar
+ Iníciar Sessão
Nome de utilizador ou palavra-passe errados
Erro ao carregar dados
Tentar novamente
- Conteúdo
+ O meu Conteúdo
Escritores
Temporadas
Favorito
@@ -41,16 +41,16 @@
Cartaz de Séries
Não tem favoritos
Procurar
- Preferir idioma legenda
- Reprodutor
+ Preferir idioma de subtítulo
+ Reprodutor de video
Imagens em cache
- Aspecto
+ Aspeto
Dispositivo
- Nome do Dispositivo
+ Nome de dispositivo
Cache
Tamanho da cache (MB)
Info da Aplicação
- Erro Desconhecido
+ Erro desconhecido
Procurar filmes, séries, episódios…
Sobre
reprodutor mpv
@@ -63,15 +63,15 @@
Filmes
Séries
Espisódios
- Esconder
+ Ocultar
Partilhar
Fechar
Transferir
- Utilize o leitor experimental de MPV para reproduzir vídeos. MPV tem suporte de vários codecs de vídeo, áudio e subtítulos.
+ Utilize o leitor experimental de MPV para reproduzir vídeos. MPV tem suporte para mais codecs de vídeo, áudio e subtítulos.
Gestor de Zoom
%1$s cartaz
%1$s cenário
- Gestor
+ Gestos
Gestor de volume e luminosidade
Ordenar por
Ordenar por ordem
@@ -104,7 +104,7 @@
Tempo limite do soquete (ms)
Género
Diretor
- Elenco e Equipa
+ Elenco & Equipa
Ver o trailer
Servidores
Transferências
@@ -115,13 +115,13 @@
Erro na preparação de itens do reprodutor.
Não tem nada transferido
Sem resultados da pesquisa
- A App irá utilizar esta quantidade de MB do seu espaço em disco para armazenar imagens do servidor Jellyfin. Valores maiores podem ser benéficos em redes mais lentas.
- Preferir idioma audio
+ A aplicação irá utilizar esta quantidade de MB do seu espaço em disco para armazenar imagens do servidor Jellyfin. Valores maiores podem ser benéficos em redes mais lentas.
+ Preferir idioma de audio
Cache de imagens em memória para acelerar o tempo de carregamento. Terá efeito após o reinício da aplicação.
Remover endereço do servidor
Externo
- Remover usuário
- Tem certeza de que deseja remover o usuário %1$s
+ Remover utilizador
+ Tem certeza de que deseja remover o utilizador %1$s
Saida de video
Saída de áudio
Adicionar endereço
@@ -145,7 +145,7 @@
Usuários
Idioma do aplicativo
Adicionar
- Indicador baixado
+ Indicador de transferido
Decodificação de hardware
Endereços
Conexão rápida
@@ -158,21 +158,38 @@
temperatura
Imagem em imagem
Use o botão home ou gesto para entrar na imagem enquanto o vídeo está sendo reproduzido
- Ao usar o Findroid, você concorda com a Política de Privacidade, que afirma que não coletamos quaisquer dados
+ Ao usar o Findroid, esta a concordar com a Política de Privacidade, que afirma que não coletamos quaisquer dados
Video
Ícone do modo off-line
Sem conexão com o servidor Jellyfin, para assistir off-line, ative o modo off-line
Interno
Selecione o local de armazenamento
O local de armazenamento não está disponível
- %1$s (%2$d MB grátis)
- Preparando para baixar
+ %1$s (%2$d MB livre)
+ Preparando transferência
Exibir informações extras
Este item requer %1$s de armazenamento gratuito, mas apenas %2$s está disponível
Fique online
Erro ao baixar
- Pare de baixar
+ Parar transferência
Gesto inicial imagem em imagem
Exibe informações detalhadas sobre áudio, vídeo e legendas
Tem certeza de que deseja cancelar a transferência\?
+ Esta coleção não contém nenhum conteúdo
+ Inicie maximizado
+ Abra o vídeo no modo maximizado por padrão
+ Nenhum servidor encontrado
+ Nenhum utilizador encontrado
+ Seleccione um utilizador
+ TV ao vivo
+ Reproduzir
+ Gesto de capítulo
+ Marcadores de capítulo
+ Exibir marcadores de capítulo na barra de tempo
+ Ver trailer
+ Remover dos favoritos
+ Manter pressionado no Esquerdo / Direito para saltar capítulos (anula o gesto de velocidade x2)
+ Marcar como visto
+ Desmarcar como visto
+ Adicionar aos favoritos
\ No newline at end of file
diff --git a/core/src/main/res/values-sw600dp/dimens.xml b/core/src/main/res/values-w600dp/dimens.xml
similarity index 83%
rename from core/src/main/res/values-sw600dp/dimens.xml
rename to core/src/main/res/values-w600dp/dimens.xml
index 00d2ec8f..a7206fc3 100644
--- a/core/src/main/res/values-sw600dp/dimens.xml
+++ b/core/src/main/res/values-w600dp/dimens.xml
@@ -3,6 +3,6 @@
400dp
- 6
- 3
- - 4
+ - 3
124dp
\ No newline at end of file
diff --git a/core/src/main/res/values-sw720dp/dimens.xml b/core/src/main/res/values-w720dp/dimens.xml
similarity index 76%
rename from core/src/main/res/values-sw720dp/dimens.xml
rename to core/src/main/res/values-w720dp/dimens.xml
index cf46930b..4a453509 100644
--- a/core/src/main/res/values-sw720dp/dimens.xml
+++ b/core/src/main/res/values-w720dp/dimens.xml
@@ -1,6 +1,6 @@
- 8
- - 6
+ - 4
200dp
\ No newline at end of file
diff --git a/core/src/main/res/values-w840dp/dimens.xml b/core/src/main/res/values-w840dp/dimens.xml
new file mode 100644
index 00000000..6f317297
--- /dev/null
+++ b/core/src/main/res/values-w840dp/dimens.xml
@@ -0,0 +1,4 @@
+
+
+ - 6
+
\ No newline at end of file
diff --git a/core/src/main/res/values-zh-rCN/strings.xml b/core/src/main/res/values-zh-rCN/strings.xml
index 34e71001..81cd8ca5 100644
--- a/core/src/main/res/values-zh-rCN/strings.xml
+++ b/core/src/main/res/values-zh-rCN/strings.xml
@@ -187,4 +187,9 @@
默认以最大化模式打开视频
播放
观看预告
+ 该集合不包含任何媒体
+ 章节手势
+ 长按左/右侧可跳过章节(覆盖 2 倍速度手势)
+ 章节标记
+ 在进度栏上显示章节标记
\ No newline at end of file
diff --git a/core/src/main/res/values-zh-rTW/strings.xml b/core/src/main/res/values-zh-rTW/strings.xml
index 84b2a22e..c6487364 100644
--- a/core/src/main/res/values-zh-rTW/strings.xml
+++ b/core/src/main/res/values-zh-rTW/strings.xml
@@ -175,4 +175,21 @@
您確定要刪除伺服器位址嗎%1$s
跳轉預覽
臨時文件
+ 未找到伺服器
+ 未找到相應的用戶
+ 選擇用戶
+ 電視直播
+ 播放
+ 觀看預告
+ 標記為已播放
+ 取消標記為已播放
+ 加入收藏夾
+ 從收藏夾中刪除
+ 開始最大化
+ 預設以最大化模式開啟視頻
+ 章節手勢
+ 長按左/右側可跳過章節(覆蓋 2 倍速度手勢)
+ 章節標記
+ 在時間欄上顯示章節標記
+ 該集合不包含任何媒體
\ No newline at end of file
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 3e1dc584..056aa8e6 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -54,6 +54,7 @@
Latest %1$s
Libraries
Series poster
+ This collection does not contain any media
You have no favorites
You have nothing downloaded
Search
diff --git a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidEpisode.kt b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidEpisode.kt
index c1fbee4e..6517de5b 100644
--- a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidEpisode.kt
+++ b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidEpisode.kt
@@ -63,7 +63,7 @@ suspend fun BaseItemDto.toFindroidEpisode(
seriesName = seriesName.orEmpty(),
seriesId = seriesId!!,
seasonId = seasonId!!,
- communityRating = communityRating,
+ communityRating = communityRating?.let { Math.round(it * 10).div(10F) },
missing = locationType == LocationType.VIRTUAL,
images = toFindroidImages(jellyfinRepository),
chapters = toFindroidChapters(),
diff --git a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMovie.kt b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMovie.kt
index abeec979..2c841835 100644
--- a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMovie.kt
+++ b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMovie.kt
@@ -56,7 +56,7 @@ suspend fun BaseItemDto.toFindroidMovie(
runtimeTicks = runTimeTicks ?: 0,
playbackPositionTicks = userData?.playbackPositionTicks ?: 0,
premiereDate = premiereDate,
- communityRating = communityRating,
+ communityRating = communityRating?.let { Math.round(it * 10).div(10F) },
genres = genres ?: emptyList(),
people = people ?: emptyList(),
officialRating = officialRating,
diff --git a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidShow.kt b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidShow.kt
index 7cb6da34..79fbdcdc 100644
--- a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidShow.kt
+++ b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidShow.kt
@@ -52,7 +52,7 @@ fun BaseItemDto.toFindroidShow(
genres = genres ?: emptyList(),
people = people ?: emptyList(),
runtimeTicks = runTimeTicks ?: 0,
- communityRating = communityRating,
+ communityRating = communityRating?.let { Math.round(it * 10).div(10F) },
officialRating = officialRating,
status = status ?: "Ended",
productionYear = productionYear,
diff --git a/fastlane/Appfile b/fastlane/Appfile
new file mode 100644
index 00000000..bfff7ed2
--- /dev/null
+++ b/fastlane/Appfile
@@ -0,0 +1 @@
+package_name("dev.jdtech.jellyfin")
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
new file mode 100644
index 00000000..2df93427
--- /dev/null
+++ b/fastlane/Fastfile
@@ -0,0 +1,40 @@
+default_platform(:android)
+
+platform :android do
+ desc "Build and publish"
+ lane :publish do
+ gradle(task: "clean")
+ gradle(
+ task: "app:phone:assemble",
+ flavor: "libre",
+ build_type: "release",
+ print_command: false,
+ properties: {
+ "android.injected.signing.store.file" => ENV["FINDROID_KEYSTORE"],
+ "android.injected.signing.store.password" => ENV["FINDROID_KEYSTORE_PASSWORD"],
+ "android.injected.signing.key.alias" => ENV["FINDROID_KEY_ALIAS"],
+ "android.injected.signing.key.password" => ENV["FINDROID_KEY_PASSWORD"],
+ }
+ )
+
+ gradle(
+ task: "app:phone:bundle",
+ flavor: "libre",
+ build_type: "release",
+ print_command: false,
+ properties: {
+ "android.injected.signing.store.file" => ENV["FINDROID_KEYSTORE"],
+ "android.injected.signing.store.password" => ENV["FINDROID_KEYSTORE_PASSWORD"],
+ "android.injected.signing.key.alias" => ENV["FINDROID_KEY_ALIAS"],
+ "android.injected.signing.key.password" => ENV["FINDROID_KEY_PASSWORD"],
+ }
+ )
+
+ upload_to_play_store(
+ track: "production",
+ json_key: ENV["FINDROID_PLAY_API_CREDENTIALS"],
+ skip_upload_apk: true,
+ sync_image_upload: true
+ )
+ end
+end
diff --git a/fastlane/README.md b/fastlane/README.md
new file mode 100644
index 00000000..3f8de830
--- /dev/null
+++ b/fastlane/README.md
@@ -0,0 +1,56 @@
+fastlane documentation
+----
+
+# Installation
+
+Make sure you have the latest version of the Xcode command line tools installed:
+
+```sh
+xcode-select --install
+```
+
+For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
+
+# Available Actions
+
+## Android
+
+### android test
+
+```sh
+[bundle exec] fastlane android test
+```
+
+Runs all the tests
+
+### android beta
+
+```sh
+[bundle exec] fastlane android beta
+```
+
+Submit a new Beta Build to Crashlytics Beta
+
+### android deploy
+
+```sh
+[bundle exec] fastlane android deploy
+```
+
+Deploy a new version to the Google Play
+
+### android build
+
+```sh
+[bundle exec] fastlane android build
+```
+
+build
+
+----
+
+This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
+
+More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools).
+
+The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
diff --git a/fastlane/metadata/android/en-US/changelogs/1.txt b/fastlane/metadata/android/en-US/changelogs/1.txt
new file mode 100644
index 00000000..c9f05cb0
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/1.txt
@@ -0,0 +1,9 @@
+Features:
+- Completely native interface
+- Supported media items: movies, series, seasons, episodes
+- Video codes: H.263, H.264, H.265, VP8, VP9, AV1
+- Audio codes: Vorbis, Opus, FLAC, ALAC, PCM µ-law, PCM A-law, MP1, MP2, MP3, AMR-NB, AMR-WB, AAC, AC-3, E-AC-3, DTS, DTS-HD, TrueHD
+- Subtitle codecs: SRT, VTT, SSA/ASS, PGSSUB
+- Support for multiple servers
+- Set preferred audio and subtitle language
+- Light & dark theme
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/10.txt b/fastlane/metadata/android/en-US/changelogs/10.txt
new file mode 100644
index 00000000..249270f1
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/10.txt
@@ -0,0 +1,13 @@
+New features:
+- Split gesture option into volume & brightness and zoom
+- Add support for external subtitles (only ExoPlayer)
+- Customize the seeking increments
+- Add option to disable subtitles in mpv
+
+Improvements:
+- Lot's of translations (Bulgarian, Chinese, French, German, Hungarian, Italian, Polish, Portuguese, Spanish)
+- Provide better error messages with stacktrace
+- Display downloaded episodes by series
+- Add paging support to the library
+
+Also fixed a few crashes
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/11.txt b/fastlane/metadata/android/en-US/changelogs/11.txt
new file mode 100644
index 00000000..416923b7
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/11.txt
@@ -0,0 +1,14 @@
+New features:
+- Allow seeking video by swiping or tapping
+- Material You Dynamic colors
+- Display public users on login screen
+- Display discovered servers on add server screen
+
+Improvements:
+- Layout improvements for larger screens
+- Bring back Android TV (fix crashes and improvements)
+
+Translations: Chinese (Simplified), French, Italian, Korean, Russian
+
+Fixes:
+- Fix crash when navigating to login screen (and other screens)
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/12.txt b/fastlane/metadata/android/en-US/changelogs/12.txt
new file mode 100644
index 00000000..4c9f3987
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/12.txt
@@ -0,0 +1,13 @@
+Improvements:
+- Add "pinch to zoom" support to mpv
+
+Fixes:
+- Fix play icon color in settings
+- Fix mpv subfont.ttf not loading
+ - This fixes mpv not displaying SubRip Text (SRT) subtitles
+- Fix external subtiles not working in mpv
+- Fix crash when using swiping gesture if video is not loaded yet
+- Fix player crashing when no PlayerItems are passed
+- Fix only showing 1 discovered server
+
+Translations: Korean, Polish, Spanish
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/13.txt b/fastlane/metadata/android/en-US/changelogs/13.txt
new file mode 100644
index 00000000..f4ac3970
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/13.txt
@@ -0,0 +1,18 @@
+This update forces a servers database reset! Servers will need to be added again!
+
+New features:
+- Servers database v2
+- Network settings
+ - Request timeout
+ - Connect timeout
+ - Socket timeout
+- Mutli-user support
+
+Improvements:
+- Add series name to episode sheet with navigation
+- Enable predictive back gesture
+- Improve downloads management
+- Upgrade libmpv
+- Handle audio focus
+- Lot's of library upgrades
+- Bugfixes
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/14.txt b/fastlane/metadata/android/en-US/changelogs/14.txt
new file mode 100644
index 00000000..aeb2b78d
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/14.txt
@@ -0,0 +1,16 @@
+Highlights:
+- Add support for media sessions
+- Basic support for multiple server addresses
+- More mpv options
+
+Improvements:
+- Add search button to home screen
+
+Translations:
+- Chinese
+- French
+- Korean
+
+Fixes:
+- Fix tv player showing subtitle tracks instead of audio tracks
+- Remove server already added error
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/15.txt b/fastlane/metadata/android/en-US/changelogs/15.txt
new file mode 100644
index 00000000..8538c769
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/15.txt
@@ -0,0 +1,14 @@
+New features:
+- Allow logging in with Quick Connect
+- Support for ConfusedPolarBears intro-skipper
+
+Improvements:
+- Updated mpv release (now includes all codecs in FFmpeg)
+ - Including an experimental AV1 hardware decoder.
+- Respect "Allow media playback"
+
+Translations: Chinese, Dutch, French, Italian, Korean, Polish, Portuguese, Spanish
+
+Fixes:
+- Fix playback position reporting not closing properly.
+- Optimized the loading of app preferences (backend, not the settings screen)
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/16.txt b/fastlane/metadata/android/en-US/changelogs/16.txt
new file mode 100644
index 00000000..010012c3
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/16.txt
@@ -0,0 +1,13 @@
+New features:
+- Support for collections
+
+Improvements:
+- Follow "Play next episode automatically" from user playback settings
+- ExoPlayer can now play HLS content
+
+Translations: Chinese, Italian, Korean, Portuguese
+
+Fixes:
+- Fix Quick Connect code not readable in light mode
+- Fix multiple download related issues
+- Fix app crashing when exiting the player after finishing an item using mpv
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/17.txt b/fastlane/metadata/android/en-US/changelogs/17.txt
new file mode 100644
index 00000000..97d6d36f
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/17.txt
@@ -0,0 +1,6 @@
+Fixes:
+- Fix resuming playback
+- Fix downloads playback when there is no connection to the server
+- Fix next up episode image crop
+
+Translations: Chinese, Dutch, Vietnamese, German, Hungarian, Italian, Portuguese, Polish, Russian, Yue
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/18.txt b/fastlane/metadata/android/en-US/changelogs/18.txt
new file mode 100644
index 00000000..299825aa
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/18.txt
@@ -0,0 +1,18 @@
+New features:
+- Item metadata chips
+- Seek gesture toggle
+- AMOLED dark theme
+- Scrubbing preview (trick play)
+- Downloads rework
+
+Improvements:
+- Material 3 styling in preferences
+- Gesture exclusion zones
+
+Fixes:
+- 500 error when trying to play an item
+- mpv memory leak, anr and stuck loading icon
+- And more
+
+Translations:
+- Chinese (Simplified), Dutch, French, German, Hebrew, Italian, Polish, Portuguese, Russian, Slovak, Slovenian, Spanish, Swedish, Vietnamese
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/19.txt b/fastlane/metadata/android/en-US/changelogs/19.txt
new file mode 100644
index 00000000..fdba510f
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/19.txt
@@ -0,0 +1,13 @@
+Improvements:
+- Search in offline mode
+- App language setting for devices running Android 13+
+- Show movie size in extra info and improve size formatting
+
+Fixes:
+- Navigation to collection
+- Text overflowing into "View all"
+- Text overlapping in movie and show screens
+- AMOLED theme not taking Material 3 colors
+- NullPointerException on episodes which do not contain a seriesId or seasonId
+
+Translations: Hungarian, Polish, Portuguese (Brazil), Russian, Slovak, Spanish
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/2.txt b/fastlane/metadata/android/en-US/changelogs/2.txt
new file mode 100644
index 00000000..3b10a9b1
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/2.txt
@@ -0,0 +1,9 @@
+Improvements:
+- Replaced oss-licenses-plugin with AboutLibraries.
+- Improved server url discovery, no more http://, https:// or ports required!
+- New error panel to display detailed error messages.
+- Make library images smaller to fit more on one screen.
+
+Fixes:
+- Removed books from home & media screens.
+- Move episode metadata to under the image to adjust for larger font sizes and smaller screens.
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/20.txt b/fastlane/metadata/android/en-US/changelogs/20.txt
new file mode 100644
index 00000000..bcf97475
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/20.txt
@@ -0,0 +1,16 @@
+New features:
+- Picture-in-picture support
+- Double tap center to play/pause
+
+Improvements:
+- Ripple effect when double tapping in player
+- Improvements to hiding system bars
+- Show episode size when extra info is enabled
+
+Fixes:
+- Fix playback position reset on process death or device lock
+- Fix playback sync of download being too far ahead
+- ...
+
+Translations:
+- Chinese, Dutch, French, Hebrew, Hungarian, Italian, Korean, Polish, Portuguese, Romanian, Russion, Slovak, Spanish, Ukranian
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/21.txt b/fastlane/metadata/android/en-US/changelogs/21.txt
new file mode 100644
index 00000000..bcf97475
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/21.txt
@@ -0,0 +1,16 @@
+New features:
+- Picture-in-picture support
+- Double tap center to play/pause
+
+Improvements:
+- Ripple effect when double tapping in player
+- Improvements to hiding system bars
+- Show episode size when extra info is enabled
+
+Fixes:
+- Fix playback position reset on process death or device lock
+- Fix playback sync of download being too far ahead
+- ...
+
+Translations:
+- Chinese, Dutch, French, Hebrew, Hungarian, Italian, Korean, Polish, Portuguese, Romanian, Russion, Slovak, Spanish, Ukranian
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/22.txt b/fastlane/metadata/android/en-US/changelogs/22.txt
new file mode 100644
index 00000000..fc284f9a
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/22.txt
@@ -0,0 +1,10 @@
+Fixes:
+- Multiple crashes
+- Offline mode snackbar not visible in landscape mode
+- Incorrect popup background in player when using dark mode
+- Playback resets
+- Deleted server stays visible
+- Stuck on login screen when server has no user
+
+Translations:
+- Chinese, Czech, Hebrew, Hungarian, Italian, Korean, Portuguese, Slovak, Slovenian
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/23.txt b/fastlane/metadata/android/en-US/changelogs/23.txt
new file mode 100644
index 00000000..ae7edf96
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/23.txt
@@ -0,0 +1,16 @@
+New features:
+- Disable audio track
+- Long press for 2x speed
+- Chapters
+ - Markers are displayed on the timebar
+ - Gestures
+- Support for mixed libraries
+
+Improvements:
+- Custom track selection dialog
+- Make PiP remember zoom and brightness levels
+- Improve PiP transition when using home gesture
+- Increase the limit of items displayed on the home screen
+
+Translations:
+- Bulgarian, Chinese, Danish, French, Hungarian, Italian, Korean, Portuguese, Slovak, Spanish, Turkish, Vietnamese
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/24.txt b/fastlane/metadata/android/en-US/changelogs/24.txt
new file mode 100644
index 00000000..31fe5a03
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/24.txt
@@ -0,0 +1,15 @@
+Improvements:
+- Request audio focus in mpv
+- Sort items in collections by release date
+- Improve landscape library layout on mobile
+- Reduce community rating to one decimal place
+
+Fixes:
+- Set correct surface colors when using dynamic colors or AMOLED theme
+- Fix crash when setting picture-in-picture params
+- Check address when adding extra addresses to server
+- Display correct empty collection string
+
+Translations:
+- Dutch
+- Portuguese (Brazil)
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/25.txt b/fastlane/metadata/android/en-US/changelogs/25.txt
new file mode 100644
index 00000000..d2ee60b4
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/25.txt
@@ -0,0 +1,14 @@
+Improvements:
+- Support HTML in media descriptions
+
+Fixes:
+- Library media items too small on tablet when in portrait mode
+
+Translations:
+- Chinese
+- French
+- German
+- Hungarian
+- Portuguese
+- Spanish (Mexico)
+- Turkish
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/3.txt b/fastlane/metadata/android/en-US/changelogs/3.txt
new file mode 100644
index 00000000..728eec17
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/3.txt
@@ -0,0 +1,15 @@
+Improvements:
+- Improved home screen loading
+- Added missing episode icon
+- Reworked player items preparation:
+ - Supports intros
+ - Improved loading speed
+- Show complete detailed error messages
+- Ask for login if server responds with 401
+
+Fixes:
+- Fixed playing episodes if missing episodes occur in the season
+- Fixed missing images in some places
+- Fixed library broken when media items are grouped in folders
+- Removed Live TV section from home screen
+- Fixed underlined "View detail" text
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/4.txt b/fastlane/metadata/android/en-US/changelogs/4.txt
new file mode 100644
index 00000000..9911052c
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/4.txt
@@ -0,0 +1,12 @@
+New Features:
+- Experimental mpv player
+ - Can be enabled in the settings
+ - With extra option to force software decoding
+- New player UI to support mpv
+
+Improvements:
+- Spanish translations
+- Video now extends into display cutout
+
+Fixes:
+- Fix crash when trailer button is pressed but no trailers are available
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/5.txt b/fastlane/metadata/android/en-US/changelogs/5.txt
new file mode 100644
index 00000000..76aaea90
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/5.txt
@@ -0,0 +1,2 @@
+Fixes:
+- Fix mpv player crashing
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/6.txt b/fastlane/metadata/android/en-US/changelogs/6.txt
new file mode 100644
index 00000000..d6866595
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/6.txt
@@ -0,0 +1,16 @@
+New Features:
+- Playback speed controls
+- Sorting options in library
+- Person detail screen
+- Downloads and offline playback
+- Gestures in player to adjust volume and brightness
+- STRM support
+- Image caching with options in settings
+- Customizable device name
+- Basic Android TV layout
+
+Improvements:
+- Theme improvements
+- Pull to refresh on home screen
+- Server setup improvements
+- Czech and Spanish localization
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/7.txt b/fastlane/metadata/android/en-US/changelogs/7.txt
new file mode 100644
index 00000000..e5616fa4
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/7.txt
@@ -0,0 +1,10 @@
+Improvements:
+- Change downloads to use internal database for metadata instead of files
+- Only show download button if user is allowed to download
+- Improve player gestures and add pinch to zoom
+- Reduce the size of the mpv library by disabling lot's of decoders and other components
+ - If you notice certain content doesn't play anymore please report
+
+Fixes:
+- Fix person placeholder drawable
+- Add error handling to played and favorite buttons
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/8.txt b/fastlane/metadata/android/en-US/changelogs/8.txt
new file mode 100644
index 00000000..8fb51516
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/8.txt
@@ -0,0 +1,6 @@
+Improvements:
+- Enable avi container format in mpv
+- Many dependencies updated
+
+Fixes:
+- Add missing check for if user is allowed to download in episode sheet
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/9.txt b/fastlane/metadata/android/en-US/changelogs/9.txt
new file mode 100644
index 00000000..4dce78ae
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/9.txt
@@ -0,0 +1,14 @@
+New features:
+- Add option to display extended episode title in player
+- Add option to download over mobile network
+- Add option to disable player gestures and remember screen brightness
+
+Improvements:
+- Expand episode bottom sheet by default
+- Upgrade to Material 3 theme and components
+- Redesign settings using two pane layout
+- Add option to turn off subtitles in player (only ExoPlayer)
+- Enable image caching by default
+- Add support for Vorbis audio codec in mpv player
+
+Plus bugfixes!
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt
new file mode 100644
index 00000000..aa925f9e
--- /dev/null
+++ b/fastlane/metadata/android/en-US/full_description.txt
@@ -0,0 +1,8 @@
+Findroid is a third-party Android application for Jellyfin that provides a native user interface to browse and play movies and series.
+
+To use this app you must have a Jellyfin server.
+
+You can also download movies and TV shows for offline playback while on the road.
+And with the built-in mpv player you are sure that all media formats will play correctly including styled SSA/ASS subtitles.
+
+Thanks for using Findroid!
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/images/featureGraphic.png b/fastlane/metadata/android/en-US/images/featureGraphic.png
new file mode 100644
index 00000000..d5330f28
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/featureGraphic.png differ
diff --git a/fastlane/metadata/android/en-US/images/icon.png b/fastlane/metadata/android/en-US/images/icon.png
new file mode 100644
index 00000000..edd0aa1f
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/icon.png differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png
new file mode 100644
index 00000000..3258a2be
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png
new file mode 100644
index 00000000..9392f5d3
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png
new file mode 100644
index 00000000..64006476
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png
new file mode 100644
index 00000000..327b6685
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/5_en-US.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/5_en-US.png
new file mode 100644
index 00000000..e1d6fcd0
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/5_en-US.png differ
diff --git a/fastlane/metadata/android/en-US/images/sevenInchScreenshots/1_en-US.png b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/1_en-US.png
new file mode 100644
index 00000000..3ff8179e
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/1_en-US.png differ
diff --git a/fastlane/metadata/android/en-US/images/sevenInchScreenshots/2_en-US.png b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/2_en-US.png
new file mode 100644
index 00000000..e780ea9e
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/2_en-US.png differ
diff --git a/fastlane/metadata/android/en-US/images/sevenInchScreenshots/3_en-US.png b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/3_en-US.png
new file mode 100644
index 00000000..a029f989
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/3_en-US.png differ
diff --git a/fastlane/metadata/android/en-US/images/sevenInchScreenshots/4_en-US.png b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/4_en-US.png
new file mode 100644
index 00000000..aca684a1
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/4_en-US.png differ
diff --git a/fastlane/metadata/android/en-US/images/sevenInchScreenshots/5_en-US.png b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/5_en-US.png
new file mode 100644
index 00000000..8bbc5345
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/sevenInchScreenshots/5_en-US.png differ
diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/1_en-US.png b/fastlane/metadata/android/en-US/images/tenInchScreenshots/1_en-US.png
new file mode 100644
index 00000000..b0ef8232
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/tenInchScreenshots/1_en-US.png differ
diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/2_en-US.png b/fastlane/metadata/android/en-US/images/tenInchScreenshots/2_en-US.png
new file mode 100644
index 00000000..879f9949
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/tenInchScreenshots/2_en-US.png differ
diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/3_en-US.png b/fastlane/metadata/android/en-US/images/tenInchScreenshots/3_en-US.png
new file mode 100644
index 00000000..4f0b5d26
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/tenInchScreenshots/3_en-US.png differ
diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/4_en-US.png b/fastlane/metadata/android/en-US/images/tenInchScreenshots/4_en-US.png
new file mode 100644
index 00000000..54a3668f
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/tenInchScreenshots/4_en-US.png differ
diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/5_en-US.png b/fastlane/metadata/android/en-US/images/tenInchScreenshots/5_en-US.png
new file mode 100644
index 00000000..e4c30328
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/tenInchScreenshots/5_en-US.png differ
diff --git a/fastlane/metadata/android/en-US/short_description.txt b/fastlane/metadata/android/en-US/short_description.txt
new file mode 100644
index 00000000..ec5f6c25
--- /dev/null
+++ b/fastlane/metadata/android/en-US/short_description.txt
@@ -0,0 +1 @@
+Third-party native Jellyfin app
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/title.txt b/fastlane/metadata/android/en-US/title.txt
new file mode 100644
index 00000000..8115e156
--- /dev/null
+++ b/fastlane/metadata/android/en-US/title.txt
@@ -0,0 +1 @@
+Findroid
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/video.txt b/fastlane/metadata/android/en-US/video.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 723fb8f0..1bbaaab4 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,38 +1,47 @@
[versions]
-aboutlibraries = "11.1.0"
-android-plugin = "8.3.0"
+aboutlibraries = "11.1.3"
+android-desugar-jdk-libs = "2.0.4"
+android-plugin = "8.3.2"
androidx-activity = "1.8.2"
androidx-appcompat = "1.6.1"
-androidx-compose-bom = "2024.02.01"
-androidx-compose-material3 = "1.2.0"
+androidx-compose-bom = "2024.04.00"
+androidx-compose-material3 = "1.2.1"
androidx-constraintlayout = "2.1.4"
androidx-core = "1.12.0"
androidx-hilt = "1.2.0"
androidx-lifecycle = "2.7.0"
-androidx-media3 = "1.2.1"
+androidx-media3 = "1.3.1"
androidx-navigation = "2.7.7"
androidx-paging = "3.2.1"
androidx-preference = "1.2.1"
androidx-recyclerview = "1.3.2"
androidx-room = "2.6.1"
androidx-swiperefreshlayout = "1.1.0"
+androidx-test-core = "1.5.0"
+androidx-test-expresso = "3.5.1"
+androidx-test-junit = "1.1.5"
+androidx-test-rules = "1.5.0"
+androidx-test-runner = "1.5.2"
androidx-tv = "1.0.0-alpha10"
androidx-work = "2.9.0"
coil = "2.6.0"
-hilt = "2.51"
-compose-destinations = "1.10.1"
-jellyfin = "1.4.6"
-kotlin = "1.9.22"
+hilt = "2.51.1"
+compose-destinations = "1.10.2"
+jellyfin = "1.4.7"
+junit = "4.13.2"
+kotlin = "1.9.23"
kotlinx-serialization = "1.6.3"
-ksp = "1.9.22-1.0.17"
+ksp = "1.9.23-1.0.20"
ktlint = "12.1.0"
libmpv = "0.2.0"
material = "1.11.0"
+media3-ffmpeg-decoder = "1.2.1+1"
timber = "5.0.1"
[libraries]
aboutlibraries-core = { group = "com.mikepenz", name = "aboutlibraries-core", version.ref = "aboutlibraries" }
aboutlibraries = { group = "com.mikepenz", name = "aboutlibraries", version.ref = "aboutlibraries" }
+android-desugar-jdk = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "android-desugar-jdk-libs" }
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "androidx-activity" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "androidx-activity" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" }
@@ -63,19 +72,30 @@ androidx-recyclerview = { group = "androidx.recyclerview", name = "recyclerview"
androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "androidx-room" }
androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "androidx-room" }
androidx-swiperefreshlayout = { group = "androidx.swiperefreshlayout", name = "swiperefreshlayout", version.ref = "androidx-swiperefreshlayout" }
-androidx-work = { group = "androidx.work", name = "work-runtime", version.ref = "androidx-work" }
+androidx-test-core = { group = "androidx.test", name = "core", version.ref = "androidx-test-core" }
+androidx-test-core-ktx = { group = "androidx.test", name = "core-ktx", version.ref = "androidx-test-core" }
+androidx-test-expresso = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "androidx-test-expresso"}
+androidx-test-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-junit" }
+androidx-test-rules = { group = "androidx.test" , name = "rules", version.ref = "androidx-test-rules" }
+androidx-test-runner = { group = "androidx.test", name = "runner", version.ref = "androidx-test-runner" }
androidx-tv-foundation = { group = "androidx.tv", name = "tv-foundation", version.ref = "androidx-tv" }
androidx-tv-material = { group = "androidx.tv", name = "tv-material", version.ref = "androidx-tv" }
+androidx-work = { group = "androidx.work", name = "work-runtime", version.ref = "androidx-work" }
+androidx-work-testing = { group = "androidx.work", name = "work-testing", version.ref = "androidx-work" }
coil = { group = "io.coil-kt", name = "coil", version.ref = "coil" }
coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" }
coil-svg = { group = "io.coil-kt", name = "coil-svg", version.ref = "coil" }
compose-destinations-core = { group = "io.github.raamcosta.compose-destinations", name = "core", version.ref = "compose-destinations" }
compose-destinations-ksp = { group = "io.github.raamcosta.compose-destinations", name = "ksp", version.ref = "compose-destinations" }
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
+hilt-android-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
+hilt-android-testing = { group = "com.google.dagger", name = "hilt-android-testing", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
jellyfin-core = { group = "org.jellyfin.sdk", name = "jellyfin-core", version.ref = "jellyfin" }
+junit = { group = "junit", name = "junit", version.ref = "junit" }
libmpv = { group = "dev.jdtech.mpv", name = "libmpv", version.ref = "libmpv" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
+media3-ffmpeg-decoder = { group = "org.jellyfin.media3", name = "media3-ffmpeg-decoder", version.ref = "media3-ffmpeg-decoder" }
timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
@@ -90,3 +110,6 @@ kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref =
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" }
+
+[bundles]
+androidx-test = ["androidx-test-core", "androidx-test-core-ktx", "androidx-test-expresso", "androidx-test-junit", "androidx-test-rules", "androidx-test-runner", "androidx-work-testing"]
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index d64cd491..e6441136 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index a80b22ce..b82aa23a 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/libs/lib-decoder-ffmpeg-release.aar b/libs/lib-decoder-ffmpeg-release.aar
deleted file mode 100644
index 519a00e9..00000000
Binary files a/libs/lib-decoder-ffmpeg-release.aar and /dev/null differ
diff --git a/player/video/src/main/java/dev/jdtech/jellyfin/mpv/MPVPlayer.kt b/player/video/src/main/java/dev/jdtech/jellyfin/mpv/MPVPlayer.kt
index 5d556183..d7004fe6 100644
--- a/player/video/src/main/java/dev/jdtech/jellyfin/mpv/MPVPlayer.kt
+++ b/player/video/src/main/java/dev/jdtech/jellyfin/mpv/MPVPlayer.kt
@@ -755,7 +755,17 @@ class MPVPlayer(
playWhenReadyChangeReason = Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
)
if (isPlayerReady) {
- MPVLib.setPropertyBoolean("pause", !playWhenReady)
+ // Request audio focus when starting playback
+ if (requestAudioFocus && playWhenReady) {
+ val res = audioManager.requestAudioFocus(audioFocusRequest)
+ if (res != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+ MPVLib.setPropertyBoolean("pause", true)
+ } else {
+ MPVLib.setPropertyBoolean("pause", false)
+ }
+ } else {
+ MPVLib.setPropertyBoolean("pause", !playWhenReady)
+ }
}
}
}
diff --git a/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt b/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt
index 2cc1218d..d6f78d9e 100644
--- a/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt
+++ b/player/video/src/main/java/dev/jdtech/jellyfin/viewmodels/PlayerActivityViewModel.kt
@@ -101,7 +101,7 @@ constructor(
.build()
player = MPVPlayer(
context = application,
- requestAudioFocus = false,
+ requestAudioFocus = true,
trackSelectionParameters = trackSelectionParameters,
seekBackIncrement = appPreferences.playerSeekBackIncrement,
seekForwardIncrement = appPreferences.playerSeekForwardIncrement,
diff --git a/player/video/src/main/res/values-de/strings.xml b/player/video/src/main/res/values-de/strings.xml
index b0e68dc9..e75e2210 100644
--- a/player/video/src/main/res/values-de/strings.xml
+++ b/player/video/src/main/res/values-de/strings.xml
@@ -8,4 +8,11 @@
Player verlassen
Wiederholen
Vorspulen
-
+ Player sperren
+ Zurückspulen
+ Starten/Anhalten
+ Vor springen
+ Fortschrittsanzeige
+ Keine
+ Bild-in-Bild öffnen
+
\ No newline at end of file
diff --git a/player/video/src/main/res/values-fr/strings.xml b/player/video/src/main/res/values-fr/strings.xml
index 94ad3382..13692833 100644
--- a/player/video/src/main/res/values-fr/strings.xml
+++ b/player/video/src/main/res/values-fr/strings.xml
@@ -15,4 +15,5 @@
Avancer
Barre de progression
Détacher la fenêtre flottante
+ Aucun
\ No newline at end of file
diff --git a/player/video/src/main/res/values-pt/strings.xml b/player/video/src/main/res/values-pt/strings.xml
index b07f00b0..6ddf583e 100644
--- a/player/video/src/main/res/values-pt/strings.xml
+++ b/player/video/src/main/res/values-pt/strings.xml
@@ -15,4 +15,5 @@
Avançar
Pular para trás
Insira imagem em imagem
+ Nenhum
\ No newline at end of file
diff --git a/player/video/src/main/res/values-tr/strings.xml b/player/video/src/main/res/values-tr/strings.xml
index a6b3daec..e5d31a66 100644
--- a/player/video/src/main/res/values-tr/strings.xml
+++ b/player/video/src/main/res/values-tr/strings.xml
@@ -1,2 +1,8 @@
-
\ No newline at end of file
+
+ Ses parçasını seç
+ Altyazı parçasını seç
+ Oynatma hızını seç
+ Bir sürüm seç
+ Hiçbiri
+
\ No newline at end of file
diff --git a/player/video/src/main/res/values-zh-rTW/strings.xml b/player/video/src/main/res/values-zh-rTW/strings.xml
index c4bf81c9..416d59ff 100644
--- a/player/video/src/main/res/values-zh-rTW/strings.xml
+++ b/player/video/src/main/res/values-zh-rTW/strings.xml
@@ -15,4 +15,5 @@
輸入畫中畫
特技播放
進度條
+ 一個也沒有
\ No newline at end of file