Skip to content

feat(android): remote-first player controls and ijkplayer backend - #55

Merged
ModerRAS merged 2 commits into
masterfrom
release/player-controls-ijkplayer-2.4.0
Jul 28, 2026
Merged

feat(android): remote-first player controls and ijkplayer backend#55
ModerRAS merged 2 commits into
masterfrom
release/player-controls-ijkplayer-2.4.0

Conversation

@ModerRAS

@ModerRAS ModerRAS commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Summary

  • separate focused timeline seek from DPAD control navigation and add dedicated media-key handling
  • add transparent TV player chrome, logical previous/next, sanitized INFO diagnostics, and horizontal track selectors
  • add the experimental debugly/ijkplayer Android backend with explicit Exo fallback and TV/WebControl/WebUI parity
  • bump the Android release line from 2.3.0 to 2.4.0

IJK provenance

  • pinned source: debugly/ijkplayer 2a5114f6b276744159769f17b38bfab1e74ed5ad
  • pinned FFToolChain: b7847f3b362f605085e38a0169f870bf98d0845f
  • independently rebuilt both shipped ABIs from source
  • classes.jar is byte-identical; native global-symbol sets, ELF section sets, and dynamic dependencies match
  • packaged LGPL, OpenSSL/SSLeay, BSD-3-Clause notices and reproducible build instructions

Validation

  • ./gradlew test assembleDebug lint --no-daemon --stacktrace
  • bun run build (web-control/frontend)
  • APPLICATION_ID=com.miruplay.tv.ijkdebug override build
  • HK1 four-direction player focus/navigation and timeline-only seek
  • HK1 physical MEDIA_FAST_FORWARD / MEDIA_REWIND / Play-Pause with ijkplayer
  • APK audit: versionName 2.4.0, arm64-v8a + armeabi-v7a, pinned native hashes and compliance assets present
  • git diff --check

The unrelated untracked Windows NUL entry is excluded.

Summary by CodeRabbit

  • New Features
    • Added an experimental ijkplayer playback option with audio-track support and remote playback controls.
    • Added previous/next episode navigation, dedicated remote-key actions, improved focus movement, and a playback information panel.
    • Added dynamic playback-backend choices to web settings, including an experimental-backend warning.
  • Bug Fixes
    • Added automatic fallback to the standard player for HDR or unsupported subtitle scenarios.
    • Improved episode-boundary handling and manual version selection.
  • Documentation
    • Added TV control guidance and third-party licensing/provenance documentation.
  • Chores
    • Updated the application version to 2.4.0.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@ModerRAS, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 30 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1375d397-c67c-4827-bec9-f663df49dc1d

📥 Commits

Reviewing files that changed from the base of the PR and between 17465ee and d91c073.

📒 Files selected for processing (7)
  • app/src/main/assets/third_party/ijkplayer/PROVENANCE.md
  • player-core/src/main/kotlin/com/miruplay/tv/player/ExoPlaybackController.kt
  • player-core/src/main/kotlin/com/miruplay/tv/player/IjkPlaybackAndroidIo.kt
  • player-core/src/test/kotlin/com/miruplay/tv/player/IjkPlaybackAndroidIoTest.kt
  • third_party/ijkplayer/README.md
  • ui-tv/src/main/kotlin/com/miruplay/tv/ui/player/PlayerScreen.kt
  • ui-tv/src/test/kotlin/com/miruplay/tv/ui/player/PlayerOptionsPanelFocusTest.kt
📝 Walkthrough

Walkthrough

Adds an experimental ijkplayer backend with MediaSession controls, Media3 I/O bridging, HDR/subtitle fallbacks, TV remote and focus-navigation updates, previous/next episode playback, web-configured backend options, tests, and bundled licensing/provenance metadata.

Changes

Experimental ijkplayer playback

Layer / File(s) Summary
Backend foundation and packaging
player-ijkplayer-android/..., player-core/..., third_party/ijkplayer/..., app/src/main/assets/third_party/ijkplayer/...
Adds the ijkplayer Android module, MiruIjkSurfaceView, playback request and track models, Media3 data-source bridging, keep rules, licenses, and provenance documentation.
Runtime controller integration
player-core/src/main/kotlin/com/miruplay/tv/player/...
Adds ijkplayer lifecycle, controls, audio-track selection, host binding, cleanup, MediaSession callbacks, and HDR/subtitle fallback behavior.
Backend model and validation
core/model/..., player-core/src/test/...
Adds EXPERIMENTAL_IJKPLAYER, labels and supported-backend handling, with tests for SDR/HDR resolution, lazy Exo initialization, and I/O seeking.

TV playback controls

Layer / File(s) Summary
Remote input mapping
ui-design/src/main/kotlin/..., ui-design/src/test/...
Adds media, captions, menu, and info key inputs and maps them to playback actions with repeat and menu-state rules.
Focused playback UI
ui-tv/src/main/kotlin/com/miruplay/tv/ui/player/PlayerScreen.kt, PlayerKeyHandling.kt
Adds interactive timeline focus, episode controls, option-panel focus restoration, dedicated remote handling, and the read-only playback information panel.
UI validation
ui-tv/src/test/kotlin/com/miruplay/tv/ui/player/...
Adds timeline focus and source-sanitization tests and updates key-handling and option-focus expectations.

Episode navigation

Layer / File(s) Summary
Adjacent episode resolution and playback
repository-api/..., ui-tv/src/main/kotlin/com/miruplay/tv/ui/player/PlayerViewModel.kt
Generalizes next-episode resolution to previous and next directions, exposes availability state, handles manual version selection, and adds boundary tests.

Web backend settings

Layer / File(s) Summary
Server-provided backend options
web-control-core/..., web-control/..., web-control/frontend/src/App.vue
Adds backend option DTOs, dynamically exposes supported backends, accepts ijkplayer aliases, populates the frontend dropdown from the API, and displays an ijkplayer warning.

Release metadata

Layer / File(s) Summary
Version update
app/build.gradle.kts
Bumps the base application version from 2.3.0 to 2.4.0.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: Android remote-first player controls and the experimental ijkplayer backend.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/player-controls-ijkplayer-2.4.0

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
player-core/src/main/kotlin/com/miruplay/tv/player/ExoPlaybackController.kt (1)

290-319: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

updateRemoteControlPlaybackState() may touch the IJK View off the main thread.

In pause()/resume(), updateRemoteControlPlaybackState() runs after the withContext(Dispatchers.Main) {} block returns, i.e. on whatever dispatcher the caller used to invoke pause()/resume(). That function calls isPlaying(), which for EXPERIMENTAL_IJKPLAYER calls ijkView?.isPlaybackActive()ijkView is a View, and Android Views must only be accessed from the main thread. If any caller invokes pause()/resume() off the main dispatcher, this is a real CalledFromWrongThreadException/undefined-behavior risk.

🔒 Proposed fix: move the call inside the Main-dispatched block
     override suspend fun pause() {
         withContext(Dispatchers.Main) {
             ...
             activeExoPlayer().playWhenReady = false
+            updateRemoteControlPlaybackState()
         }
-        updateRemoteControlPlaybackState()
     }

     override suspend fun resume() {
         withContext(Dispatchers.Main) {
             ...
             activeExoPlayer().playWhenReady = true
+            updateRemoteControlPlaybackState()
         }
-        updateRemoteControlPlaybackState()
     }

Also applies to: 321-349, 566-572

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@player-core/src/main/kotlin/com/miruplay/tv/player/ExoPlaybackController.kt`
around lines 290 - 319, Move updateRemoteControlPlaybackState() inside the
withContext(Dispatchers.Main) block in pause() and resume(), ensuring every
return path invokes it before leaving the main-thread context. Apply the same
adjustment to the related playback-control paths around the referenced methods,
while preserving their existing backend-specific state updates.
🧹 Nitpick comments (5)
web-control/src/test/kotlin/com/miruplay/tv/webcontrol/PlaybackDebugConfigMappingTest.kt (1)

24-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the canonical IJK alias too.

The mapper also accepts experimentalijkplayer on Line 16, but this test only covers the two shorter aliases.

Suggested assertion
         assertEquals(PlaybackRenderBackend.EXPERIMENTAL_IJKPLAYER, playbackRenderBackendFromDebugValue("ijk"))
         assertEquals(PlaybackRenderBackend.EXPERIMENTAL_IJKPLAYER, playbackRenderBackendFromDebugValue("ijkplayer"))
+        assertEquals(
+            PlaybackRenderBackend.EXPERIMENTAL_IJKPLAYER,
+            playbackRenderBackendFromDebugValue("experimentalijkplayer"),
+        )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@web-control/src/test/kotlin/com/miruplay/tv/webcontrol/PlaybackDebugConfigMappingTest.kt`
around lines 24 - 25, Add a test assertion in PlaybackDebugConfigMappingTest for
playbackRenderBackendFromDebugValue("experimentalijkplayer"), verifying it
returns PlaybackRenderBackend.EXPERIMENTAL_IJKPLAYER alongside the existing IJK
alias cases.
repository-api/src/main/kotlin/com/miruplay/tv/repository/NextPlaybackSourceResolver.kt (1)

40-50: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid the current-episode lookup when there is no adjacent episode.

currentPath performs a repository load before the episode ?: return null early exit, so every boundary call (first/last episode) pays an unnecessary I/O hit.

♻️ Proposed reorder
     private suspend fun buildAdjacent(
         currentSource: PlaybackSource,
         episode: Episode?,
     ): PlaybackSource? {
+        val adjacentEpisode = episode ?: return null
         val currentPath = currentSource.episodeId
             ?.let { loadEpisode(it)?.filePath }
             ?: currentSource.uri
-        val adjacentEpisode = episode ?: return null
         val version = adjacentEpisode.availableVersions().nearestTo(currentPath) ?: return null
         return build(adjacentEpisode, version)
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@repository-api/src/main/kotlin/com/miruplay/tv/repository/NextPlaybackSourceResolver.kt`
around lines 40 - 50, The buildAdjacent method currently loads the current
episode before checking whether an adjacent episode exists. Move the episode ?:
return null guard before currentPath computation, preserving the existing
version selection and build flow for valid adjacent episodes.
ui-tv/src/test/kotlin/com/miruplay/tv/ui/player/PlayerKeyHandlingTest.kt (1)

12-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No test asserts the forward-seek path. Key.DirectionRight + KeyDownonSkipForward is never exercised; the KeyUp test only checks non-consumption. Worth a short additional case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tv/src/test/kotlin/com/miruplay/tv/ui/player/PlayerKeyHandlingTest.kt`
around lines 12 - 31, The PlayerKeyHandlingTest coverage only verifies repeated
left-seek handling. Add a focused test for handlePlaybackTimelineKey using
Key.DirectionRight with KeyEventType.KeyDown, assert the event is consumed, and
verify onSkipForward is invoked while onSkipBackward is not.
ui-tv/src/main/kotlin/com/miruplay/tv/ui/player/PlayerScreen.kt (2)

1128-1136: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Down-target fallback skips the always-enabled picture chip.

When there are no audio tracks and no subtitles, down jumps to the speed chip even though the picture chip is the first (and always enabled) chip in the row. Consider ending the chain on pictureFocusRequester for a predictable leftmost landing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tv/src/main/kotlin/com/miruplay/tv/ui/player/PlayerScreen.kt` around lines
1128 - 1136, Update the downFocusRequester selection in PlayerScreen so the
fallback after audioTracks and subtitles uses pictureFocusRequester instead of
speedFocusRequester. Preserve the existing audio and subtitle targets when those
tracks are available.

1919-1926: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fully-qualified enum references are inconsistent with the file's imports.

MiruPlayInputIntent is already imported at Line 144; the com.miruplay.tv.design. prefixes here can be dropped.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tv/src/main/kotlin/com/miruplay/tv/ui/player/PlayerScreen.kt` around lines
1919 - 1926, Update the when expression in the event input handling flow to
reference the already imported MiruPlayInputIntent enum directly, removing the
redundant com.miruplay.tv.design. qualification from MediaPrevious, MediaNext,
and Captions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/main/assets/third_party/ijkplayer/PROVENANCE.md`:
- Around line 29-43: Update the provenance build recipe to pin exact JDK,
Android SDK/build-tools, NDK, CMake, Gradle, and native compiler versions
instead of allowing ranges or platform-dependent toolchains. Provide a
deterministic containerized environment if exact cross-platform pinning is
impractical, and add verification steps requiring the produced AAR and ABI
outputs to match the recorded SHA-256 provenance values.

In `@player-core/src/main/kotlin/com/miruplay/tv/player/ExoPlaybackController.kt`:
- Around line 1060-1078: Update updateRemoteControlPlaybackState() to pass the
player’s current playback position instead of the hardcoded 0L when building
PlaybackState. Reuse the existing current-position source used by IJK/MPV
playback, such as getCurrentPosition() or ijkPositionMs, while preserving the
existing state, speed, and action behavior.
- Around line 1461-1527: Serialize all MiruIjkPlayerListener callbacks from
MiruIjkSurfaceView onto a single controller-owned task queue or actor before
mutating shared IJK state. Ensure onPrepared, onBufferingChanged, onCompletion,
onError, and onAudioTracksChanged update ijk fields, availableAudioTracks, and
_state.value only on that serialized executor, preserving callback ordering and
existing playback-state behavior.

In
`@player-ijkplayer-android/src/main/kotlin/com/miruplay/tv/player/ijk/android/MiruIjkSurfaceView.kt`:
- Around line 14-25: The loadIjkSource flow must preserve resolved playback
headers when opening sources through the Android-I/O bridge. Update the
MiruIjkSurfaceView path and IjkPlaybackAndroidIo.open integration so the source
headers reach DataSpec via withAdditionalHeaders(), while retaining the existing
URI and I/O behavior.

In `@ui-tv/src/main/kotlin/com/miruplay/tv/ui/player/PlayerScreen.kt`:
- Around line 1497-1528: The subtitle and audio LazyRows in the PlayerMenu
rendering must scroll the selected track into view before initial focus is
assigned. Add a rememberLazyListState for each row, pass it to the corresponding
LazyRow, and use LaunchedEffect keyed to the selected subtitle/audio index to
scroll to that item (accounting for the subtitles “off” item offset) before
applying initialFocusHandle.modifier().
- Around line 1607-1611: Guard the initial focus request in the LaunchedEffect
associated with infoTabFocusRequester so requestFocus() cannot propagate an
IllegalStateException when PlayerInfoPanel is not yet attached or placed by
AnimatedVisibility. Preserve the existing focus behavior once the Button’s
internal focus target is available, and avoid assuming PlayerOptionButton itself
always provides an attached focusable node.

---

Outside diff comments:
In `@player-core/src/main/kotlin/com/miruplay/tv/player/ExoPlaybackController.kt`:
- Around line 290-319: Move updateRemoteControlPlaybackState() inside the
withContext(Dispatchers.Main) block in pause() and resume(), ensuring every
return path invokes it before leaving the main-thread context. Apply the same
adjustment to the related playback-control paths around the referenced methods,
while preserving their existing backend-specific state updates.

---

Nitpick comments:
In
`@repository-api/src/main/kotlin/com/miruplay/tv/repository/NextPlaybackSourceResolver.kt`:
- Around line 40-50: The buildAdjacent method currently loads the current
episode before checking whether an adjacent episode exists. Move the episode ?:
return null guard before currentPath computation, preserving the existing
version selection and build flow for valid adjacent episodes.

In `@ui-tv/src/main/kotlin/com/miruplay/tv/ui/player/PlayerScreen.kt`:
- Around line 1128-1136: Update the downFocusRequester selection in PlayerScreen
so the fallback after audioTracks and subtitles uses pictureFocusRequester
instead of speedFocusRequester. Preserve the existing audio and subtitle targets
when those tracks are available.
- Around line 1919-1926: Update the when expression in the event input handling
flow to reference the already imported MiruPlayInputIntent enum directly,
removing the redundant com.miruplay.tv.design. qualification from MediaPrevious,
MediaNext, and Captions.

In `@ui-tv/src/test/kotlin/com/miruplay/tv/ui/player/PlayerKeyHandlingTest.kt`:
- Around line 12-31: The PlayerKeyHandlingTest coverage only verifies repeated
left-seek handling. Add a focused test for handlePlaybackTimelineKey using
Key.DirectionRight with KeyEventType.KeyDown, assert the event is consumed, and
verify onSkipForward is invoked while onSkipBackward is not.

In
`@web-control/src/test/kotlin/com/miruplay/tv/webcontrol/PlaybackDebugConfigMappingTest.kt`:
- Around line 24-25: Add a test assertion in PlaybackDebugConfigMappingTest for
playbackRenderBackendFromDebugValue("experimentalijkplayer"), verifying it
returns PlaybackRenderBackend.EXPERIMENTAL_IJKPLAYER alongside the existing IJK
alias cases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a2cd73e9-5d70-4684-92ae-309c1a32a317

📥 Commits

Reviewing files that changed from the base of the PR and between 76d6e58 and 17465ee.

⛔ Files ignored due to path filters (3)
  • player-ijkplayer-android/libs/ijkplayer-classes.jar is excluded by !**/*.jar
  • player-ijkplayer-android/src/main/jniLibs/arm64-v8a/libijkplayer.so is excluded by !**/*.so
  • player-ijkplayer-android/src/main/jniLibs/armeabi-v7a/libijkplayer.so is excluded by !**/*.so
📒 Files selected for processing (47)
  • app/build.gradle.kts
  • app/src/main/assets/third_party/ijkplayer/COPYING.LGPLv2.1
  • app/src/main/assets/third_party/ijkplayer/LICENSE.OpenSSL-1.1.1w
  • app/src/main/assets/third_party/ijkplayer/LICENSE.libyuv
  • app/src/main/assets/third_party/ijkplayer/NOTICE
  • app/src/main/assets/third_party/ijkplayer/PROVENANCE.md
  • core/model/src/main/kotlin/com/miruplay/tv/model/PlaybackUiConventions.kt
  • core/model/src/main/kotlin/com/miruplay/tv/model/ToneMappingModels.kt
  • docs/android-tv-player-controls.md
  • player-core/build.gradle.kts
  • player-core/src/main/kotlin/com/miruplay/tv/player/ExoPlaybackController.kt
  • player-core/src/main/kotlin/com/miruplay/tv/player/IjkPlaybackAndroidIo.kt
  • player-core/src/main/kotlin/com/miruplay/tv/player/MiruPlayMediaService.kt
  • player-core/src/main/kotlin/com/miruplay/tv/player/ToneMappingRuntimeConfigResolver.kt
  • player-core/src/test/kotlin/com/miruplay/tv/player/ExoPlaybackControllerLazyInitTest.kt
  • player-core/src/test/kotlin/com/miruplay/tv/player/IjkPlaybackAndroidIoTest.kt
  • player-core/src/test/kotlin/com/miruplay/tv/player/ToneMappingRuntimeConfigResolverTest.kt
  • player-ijkplayer-android/build.gradle.kts
  • player-ijkplayer-android/consumer-rules.pro
  • player-ijkplayer-android/src/main/AndroidManifest.xml
  • player-ijkplayer-android/src/main/kotlin/com/miruplay/tv/player/ijk/android/MiruIjkSurfaceView.kt
  • repository-api/src/main/kotlin/com/miruplay/tv/repository/NextPlaybackSourceResolver.kt
  • repository-api/src/test/kotlin/com/miruplay/tv/repository/NextPlaybackSourceResolverTest.kt
  • settings.gradle.kts
  • third_party/ijkplayer/COPYING.LGPLv2.1
  • third_party/ijkplayer/LICENSE.OpenSSL-1.1.1w
  • third_party/ijkplayer/LICENSE.libyuv
  • third_party/ijkplayer/NOTICE
  • third_party/ijkplayer/README.md
  • ui-design/src/main/kotlin/com/miruplay/tv/design/MiruPlayComposeKeyProfile.kt
  • ui-design/src/main/kotlin/com/miruplay/tv/design/MiruPlayInputIntent.kt
  • ui-design/src/main/kotlin/com/miruplay/tv/design/MiruPlayKeyInput.kt
  • ui-design/src/test/kotlin/com/miruplay/tv/design/MiruPlayComposeKeyProfileTest.kt
  • ui-design/src/test/kotlin/com/miruplay/tv/design/MiruPlayInputIntentTest.kt
  • ui-tv/src/main/kotlin/com/miruplay/tv/ui/player/PlayerKeyHandling.kt
  • ui-tv/src/main/kotlin/com/miruplay/tv/ui/player/PlayerScreen.kt
  • ui-tv/src/main/kotlin/com/miruplay/tv/ui/player/PlayerViewModel.kt
  • ui-tv/src/test/kotlin/com/miruplay/tv/ui/player/PlayerInfoSanitizationTest.kt
  • ui-tv/src/test/kotlin/com/miruplay/tv/ui/player/PlayerKeyHandlingTest.kt
  • ui-tv/src/test/kotlin/com/miruplay/tv/ui/player/PlayerOptionsPanelFocusTest.kt
  • ui-tv/src/test/kotlin/com/miruplay/tv/ui/player/PlayerTimelineFocusTest.kt
  • web-control-core/src/main/kotlin/com/miruplay/tv/webcontrol/WebControlModels.kt
  • web-control-core/src/test/kotlin/com/miruplay/tv/webcontrol/WebControlSettingsRouteTest.kt
  • web-control/frontend/src/App.vue
  • web-control/src/main/kotlin/com/miruplay/tv/webcontrol/PlaybackDebugConfigMapping.kt
  • web-control/src/main/kotlin/com/miruplay/tv/webcontrol/WebControlService.kt
  • web-control/src/test/kotlin/com/miruplay/tv/webcontrol/PlaybackDebugConfigMappingTest.kt

Comment thread app/src/main/assets/third_party/ijkplayer/PROVENANCE.md Outdated
Comment thread ui-tv/src/main/kotlin/com/miruplay/tv/ui/player/PlayerScreen.kt
Comment thread ui-tv/src/main/kotlin/com/miruplay/tv/ui/player/PlayerScreen.kt Outdated
@ModerRAS
ModerRAS merged commit 4de31c8 into master Jul 28, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant