forked from jellyfin/jellyfin-android
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Most of the proposed changes in the files listed below have been shamelessly copied from the Android TV implementation in jellyfin/jellyfin-androidtv#4052. Authorship of these changes belongs to nielsvanvelzen. app/src/main/java/org/jellyfin/mobile/player/PlayerViewModel.kt app/src/main/java/org/jellyfin/mobile/player/mediasegments/MediaSegmentAction.kt app/src/main/java/org/jellyfin/mobile/player/mediasegments/MediaSegmentRepository.kt
- Loading branch information
1 parent
2bd932d
commit 9ca99c7
Showing
10 changed files
with
249 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
export class MediaSegmentsPlugin { | ||
SETTING_PREFIX = 'segmentTypeAction'; | ||
|
||
constructor({ events, appSettings, dashboard }) { | ||
this.appSettings = appSettings; | ||
this.dashboard = dashboard; | ||
|
||
// FIXME: for some reason I need to write a lambda here. | ||
// otherwise `this` in onSettingsChanged refers to the Events class | ||
events.on(appSettings, 'change', (e, name) => { this.onSettingsChanged(e, name); }); | ||
} | ||
|
||
getSettingId(type) { | ||
return `${this.SETTING_PREFIX}__${type}`; | ||
} | ||
|
||
getSettingValue(id) { | ||
// FIXME: get userId from somewhere else | ||
var userId = this.dashboard.getCurrentUserId(); | ||
|
||
return this.appSettings.get(id, userId); | ||
} | ||
|
||
// Update media segment action | ||
onSettingsChanged(e, name) { | ||
if (name.startsWith(this.SETTING_PREFIX)) { | ||
var type = name.slice(this.SETTING_PREFIX.length + 2); | ||
var action = this.getSettingValue(this.getSettingId(type)); | ||
|
||
if (type != null && action != null) { | ||
MediaSegments.setSegmentTypeAction(type, action); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
app/src/main/java/org/jellyfin/mobile/bridge/MediaSegments.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package org.jellyfin.mobile.bridge | ||
|
||
import android.content.Context | ||
import android.webkit.JavascriptInterface | ||
import org.jellyfin.mobile.player.mediasegments.MediaSegmentAction | ||
import org.jellyfin.mobile.player.mediasegments.MediaSegmentRepository | ||
import org.jellyfin.sdk.model.api.MediaSegmentType | ||
import org.koin.core.component.KoinComponent | ||
import org.koin.core.component.get | ||
|
||
@Suppress("unused") | ||
class MediaSegments(private val context: Context) : KoinComponent { | ||
private val mediaSegmentRepository: MediaSegmentRepository = get() | ||
|
||
@JavascriptInterface | ||
fun setSegmentTypeAction(typeString: String, actionString: String) { | ||
val type: MediaSegmentType = when(typeString) { | ||
"Intro" -> MediaSegmentType.INTRO | ||
"Outro" -> MediaSegmentType.OUTRO | ||
"Preview" -> MediaSegmentType.PREVIEW | ||
"Recap" -> MediaSegmentType.RECAP | ||
"Commercial" -> MediaSegmentType.COMMERCIAL | ||
else -> return | ||
} | ||
|
||
val action: MediaSegmentAction = when(actionString) { | ||
"None" -> MediaSegmentAction.NOTHING | ||
"Skip" -> MediaSegmentAction.SKIP | ||
"AskToSkip" -> MediaSegmentAction.ASK_TO_SKIP | ||
else -> return | ||
} | ||
|
||
mediaSegmentRepository.setDefaultSegmentTypeAction(type, action) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
app/src/main/java/org/jellyfin/mobile/player/mediasegments/MediaSegmentAction.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.jellyfin.mobile.player.mediasegments | ||
|
||
enum class MediaSegmentAction { | ||
/** | ||
* Don't take any action for this segment. | ||
*/ | ||
NOTHING, | ||
|
||
/** | ||
* Seek to the end of this segment (endTicks). If the duration of this segment is shorter than 1 second it should do nothing to avoid | ||
* lag. The skip action will only execute when playing over the segment start, not when seeking into the segment block. | ||
*/ | ||
SKIP, | ||
|
||
/** | ||
* Ask the user if they want to skip this segment. When the user agrees this behaves like [SKIP]. Confirmation should only be asked for | ||
* segments with a duration of at least 3 seconds to avoid UI flickering. | ||
*/ | ||
ASK_TO_SKIP, | ||
} |
86 changes: 86 additions & 0 deletions
86
app/src/main/java/org/jellyfin/mobile/player/mediasegments/MediaSegmentRepository.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package org.jellyfin.mobile.player.mediasegments | ||
|
||
import org.jellyfin.mobile.app.AppPreferences | ||
import org.jellyfin.sdk.api.client.ApiClient | ||
import org.jellyfin.sdk.api.client.extensions.mediaSegmentsApi | ||
import org.jellyfin.sdk.api.operations.MediaSegmentsApi | ||
import org.jellyfin.sdk.model.api.BaseItemDto | ||
import org.jellyfin.sdk.model.api.MediaSegmentDto | ||
import org.jellyfin.sdk.model.api.MediaSegmentType | ||
import org.koin.core.component.KoinComponent | ||
import org.koin.core.component.get | ||
import org.koin.core.component.inject | ||
|
||
fun Map<MediaSegmentType, MediaSegmentAction>.toMediaSegmentActionsString() = | ||
map { "${it.key.serialName}=${it.value.name}" } | ||
.joinToString(",") | ||
|
||
class MediaSegmentRepository : KoinComponent { | ||
companion object { | ||
/** | ||
* All media segments currently supported by the app. | ||
*/ | ||
val SupportedTypes = listOf( | ||
MediaSegmentType.INTRO, | ||
MediaSegmentType.OUTRO, | ||
MediaSegmentType.PREVIEW, | ||
MediaSegmentType.RECAP, | ||
MediaSegmentType.COMMERCIAL, | ||
) | ||
} | ||
|
||
private val appPreferences: AppPreferences by inject() | ||
private val apiClient: ApiClient = get() | ||
private val mediaSegmentsApi: MediaSegmentsApi = apiClient.mediaSegmentsApi | ||
|
||
private val mediaTypeActions = mutableMapOf<MediaSegmentType, MediaSegmentAction>() | ||
|
||
init { | ||
restoreMediaTypeActions() | ||
} | ||
|
||
private fun restoreMediaTypeActions() { | ||
val restoredMediaTypeActions = appPreferences.mediaSegmentActions | ||
.split(",") | ||
.mapNotNull { | ||
runCatching { | ||
val (type, action) = it.split('=', limit = 2) | ||
MediaSegmentType.fromName(type) to MediaSegmentAction.valueOf(action) | ||
}.getOrNull() | ||
} | ||
|
||
mediaTypeActions.clear() | ||
mediaTypeActions.putAll(restoredMediaTypeActions) | ||
} | ||
|
||
private fun saveMediaTypeActions() { | ||
appPreferences.mediaSegmentActions = mediaTypeActions.toMediaSegmentActionsString() | ||
} | ||
|
||
fun getDefaultSegmentTypeAction(type: MediaSegmentType): MediaSegmentAction { | ||
// Always return no action for unsupported types | ||
if (!SupportedTypes.contains(type)) return MediaSegmentAction.NOTHING | ||
|
||
return mediaTypeActions.getOrDefault(type, MediaSegmentAction.NOTHING) | ||
} | ||
|
||
fun setDefaultSegmentTypeAction(type: MediaSegmentType, action: MediaSegmentAction) { | ||
// Don't allow modifying actions for unsupported types | ||
if (!SupportedTypes.contains(type)) return | ||
|
||
mediaTypeActions[type] = action | ||
saveMediaTypeActions() | ||
} | ||
|
||
fun getMediaSegmentAction(segment: MediaSegmentDto): MediaSegmentAction { | ||
// TODO: check media segment duration like in ATV | ||
return getDefaultSegmentTypeAction(segment.type) | ||
} | ||
|
||
suspend fun getSegmentsForItem(item: BaseItemDto): List<MediaSegmentDto> = runCatching { | ||
mediaSegmentsApi.getItemSegments( | ||
itemId = item.id, | ||
includeSegmentTypes = SupportedTypes, | ||
).content.items | ||
}.getOrDefault(emptyList()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters