Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ability to choose what categories are skipped automatically and… #4021

Merged
merged 12 commits into from
Jun 19, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ object PreferenceKeys {
const val SKIP_BUTTONS = "skip_buttons"
const val PICTURE_IN_PICTURE = "picture_in_picture"
const val PLAYER_RESIZE_MODE = "player_resize_mode"
const val SB_SKIP_MANUALLY = "sb_skip_manually_key"
const val SB_SHOW_MARKERS = "sb_show_markers"
const val ALTERNATIVE_PLAYER_LAYOUT = "alternative_player_layout"
const val USE_HLS_OVER_DASH = "use_hls"
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/java/com/github/libretube/enums/SbSkipOptions.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.github.libretube.enums

enum class SbSkipOptions {
OFF,
MANUAL,
AUTOMATIC
}
88 changes: 21 additions & 67 deletions app/src/main/java/com/github/libretube/helpers/PlayerHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,27 @@ import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.LoadControl
import androidx.media3.ui.CaptionStyleCompat
import com.github.libretube.R
import com.github.libretube.api.obj.PipedStream
import com.github.libretube.api.obj.Segment
import com.github.libretube.api.obj.Streams
import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.enums.AudioQuality
import com.github.libretube.enums.PlayerEvent
import com.github.libretube.enums.SbSkipOptions
import kotlin.math.absoluteValue
import kotlin.math.roundToInt

object PlayerHelper {
private const val ACTION_MEDIA_CONTROL = "media_control"
const val CONTROL_TYPE = "control_type"
private val SPONSOR_CATEGORIES: Array<String> =
arrayOf(
"intro",
"selfpromo",
"interaction",
"sponsor",
"outro",
"filler",
"music_offtopic",
"preview")

/**
* Create a base64 encoded DASH stream manifest
Expand Down Expand Up @@ -69,63 +78,14 @@ object PlayerHelper {
/**
* get the categories for sponsorBlock
*/
fun getSponsorBlockCategories(): ArrayList<String> {
val categories: ArrayList<String> = arrayListOf()
if (PreferenceHelper.getBoolean(
"intro_category_key",
false,
)
) {
categories.add("intro")
}
if (PreferenceHelper.getBoolean(
"selfpromo_category_key",
false,
)
) {
categories.add("selfpromo")
}
if (PreferenceHelper.getBoolean(
"interaction_category_key",
false,
)
) {
categories.add("interaction")
}
if (PreferenceHelper.getBoolean(
"sponsors_category_key",
true,
)
) {
categories.add("sponsor")
}
if (PreferenceHelper.getBoolean(
"outro_category_key",
false,
)
) {
categories.add("outro")
}
if (PreferenceHelper.getBoolean(
"filler_category_key",
false,
)
) {
categories.add("filler")
}
if (PreferenceHelper.getBoolean(
"music_offtopic_category_key",
false,
)
) {
categories.add("music_offtopic")
}
if (PreferenceHelper.getBoolean(
"preview_category_key",
false,
)
) {
categories.add("preview")
fun getSponsorBlockCategories(): MutableMap<String, SbSkipOptions> {
val categories: MutableMap<String, SbSkipOptions> = mutableMapOf()

for (cat in SPONSOR_CATEGORIES){
val state = PreferenceHelper.getString(cat + "_category_key", "off").uppercase()
if (SbSkipOptions.valueOf(state) != SbSkipOptions.OFF){
categories[cat] = SbSkipOptions.valueOf(state)
}
}
return categories
}
Expand Down Expand Up @@ -240,12 +200,6 @@ object PlayerHelper {
true,
)

val skipSegmentsManually: Boolean
get() = PreferenceHelper.getBoolean(
PreferenceKeys.SB_SKIP_MANUALLY,
false,
)

val autoPlayEnabled: Boolean
get() = PreferenceHelper.getBoolean(
PreferenceKeys.AUTO_PLAY,
Expand Down Expand Up @@ -476,7 +430,7 @@ object PlayerHelper {
fun ExoPlayer.checkForSegments(
context: Context,
segments: List<Segment>,
skipManually: Boolean = false,
sponsorBlockConfig: MutableMap<String, SbSkipOptions>,
): Long? {
for (segment in segments) {
val segmentStart = (segment.segment[0] * 1000f).toLong()
Expand All @@ -486,7 +440,7 @@ object PlayerHelper {
if ((duration - currentPosition).absoluteValue < 500) continue

if (currentPosition in segmentStart until segmentEnd) {
if (!skipManually) {
if (sponsorBlockConfig.get(segment.category) == SbSkipOptions.AUTOMATIC) {
if (sponsorBlockNotifications) {
runCatching {
Toast.makeText(context, R.string.segment_skipped, Toast.LENGTH_SHORT)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import com.github.libretube.db.obj.WatchPosition
import com.github.libretube.extensions.TAG
import com.github.libretube.extensions.setMetadata
import com.github.libretube.extensions.toID
import com.github.libretube.enums.SbSkipOptions
import com.github.libretube.helpers.PlayerHelper
import com.github.libretube.helpers.PlayerHelper.checkForSegments
import com.github.libretube.helpers.PlayerHelper.loadPlaybackParams
Expand Down Expand Up @@ -76,6 +77,7 @@ class OnlinePlayerService : LifecycleService() {
* SponsorBlock Segment data
*/
private var segments: List<Segment> = listOf()
private var sponsorBlockConfig: MutableMap<String, SbSkipOptions> = PlayerHelper.getSponsorBlockCategories()

/**
* [Notification] for the player
Expand Down Expand Up @@ -321,11 +323,10 @@ class OnlinePlayerService : LifecycleService() {
private fun fetchSponsorBlockSegments() {
lifecycleScope.launch(Dispatchers.IO) {
runCatching {
val categories = PlayerHelper.getSponsorBlockCategories()
if (categories.isEmpty()) return@runCatching
if (sponsorBlockConfig.isEmpty()) return@runCatching
segments = RetrofitInstance.api.getSegments(
videoId,
JsonHelper.json.encodeToString(categories),
JsonHelper.json.encodeToString(sponsorBlockConfig.keys),
).segments
checkForSegments()
}
Expand All @@ -338,7 +339,7 @@ class OnlinePlayerService : LifecycleService() {
private fun checkForSegments() {
handler.postDelayed(this::checkForSegments, 100)

player?.checkForSegments(this, segments)
player?.checkForSegments(this, segments, sponsorBlockConfig)
}

private fun updateQueue() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
*/
private var segments = listOf<Segment>()
private var sponsorBlockEnabled = PlayerHelper.sponsorBlockEnabled
private var sponsorBlockConfig = PlayerHelper.getSponsorBlockCategories()

private val handler = Handler(Looper.getMainLooper())
private val mainActivity get() = activity as MainActivity
Expand Down Expand Up @@ -663,16 +664,16 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {

if (segments.isEmpty()) return

exoPlayer.checkForSegments(requireContext(), segments, PlayerHelper.skipSegmentsManually)
exoPlayer.checkForSegments(requireContext(), segments, sponsorBlockConfig)
?.let { segmentEnd ->
binding.sbSkipBtn.visibility = View.VISIBLE
binding.sbSkipBtn.setOnClickListener {
exoPlayer.seekTo(segmentEnd)
binding.sbSkipBtn.visibility = View.GONE
}
return
}

if (PlayerHelper.skipSegmentsManually) binding.sbSkipBtn.visibility = View.GONE
}

private fun playVideo() {
Expand Down Expand Up @@ -773,12 +774,11 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
private fun fetchSponsorBlockSegments() {
lifecycleScope.launch(Dispatchers.IO) {
runCatching {
val categories = PlayerHelper.getSponsorBlockCategories()
if (categories.isEmpty()) return@runCatching
if (sponsorBlockConfig.isEmpty()) return@runCatching
segments =
RetrofitInstance.api.getSegments(
videoId!!,
JsonHelper.json.encodeToString(categories),
JsonHelper.json.encodeToString(sponsorBlockConfig.keys),
).segments
if (segments.isEmpty()) return@runCatching

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.github.libretube.ui.views
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.preference.DropDownPreference
import com.github.libretube.R

class SpinnerPreference(context: Context, attrs: AttributeSet): DropDownPreference(context, attrs){

fun onCreate(parent: ViewGroup): View {
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
return inflater.inflate(R.layout.spinner_preference, parent, false)
Bnyro marked this conversation as resolved.
Show resolved Hide resolved
}

}
29 changes: 29 additions & 0 deletions app/src/main/res/layout/spinner_preference.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/widget_frame"
android:layout_width="match_parent"
android:layout_height="match_parent">


<TextView
android:id="@android:id/title"
style="@android:style/TextAppearance.DeviceDefault.SearchResult.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Title" />

<TextView
android:id="@android:id/summary"
style="@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Summary" />

<Spinner
android:id="@+id/spinner"
style="@android:style/TextAppearance.DeviceDefault.Widget"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>


</LinearLayout>
12 changes: 12 additions & 0 deletions app/src/main/res/values/array.xml
Original file line number Diff line number Diff line change
Expand Up @@ -422,4 +422,16 @@
<item>playlists</item>
</string-array>

<string-array name="sb_skip_options">
<item>@string/off</item>
<item>@string/manual</item>
<item>@string/automatic</item>
</string-array>

<string-array name="sb_skip_options_values">
<item>off</item>
<item>manual</item>
<item>automatic</item>
</string-array>

Bnyro marked this conversation as resolved.
Show resolved Hide resolved
</resources>
19 changes: 11 additions & 8 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,21 +85,21 @@
<string name="segment_skipped">Skipped segment</string>
<string name="category_segments">Segments</string>
<string name="category_sponsor">Sponsor</string>
<string name="category_sponsor_description">Paid promotion, paid referrals and direct advertisements. Not for self-promotion or free genuine shoutouts to causes, creators, websites, and products.</string>
<string name="category_sponsor_description">Paid promotion, paid referrals and direct advertisements. Not for self-promotion or free genuine shoutouts to causes, creators, websites, and products: %s</string>
Bnyro marked this conversation as resolved.
Show resolved Hide resolved
<string name="category_selfpromo">Unpaid/Self Promotion</string>
<string name="category_selfpromo_description">Similar to \"sponsor\" except for unpaid or self promotion. This includes sections about merchandise, donations, or info about who they collaborated with.</string>
<string name="category_selfpromo_description">Similar to \"sponsor\" except for unpaid or self promotion. This includes sections about merchandise, donations, or info about who they collaborated with: %s</string>
<string name="category_interaction">Interaction reminder (like and subscribe)</string>
<string name="category_interaction_description">When there is a short reminder to like, subscribe or follow in the middle of content. If long or about something specific, it should instead be self promotion.</string>
<string name="category_interaction_description">When there is a short reminder to like, subscribe or follow in the middle of content. If long or about something specific, it should instead be self promotion: %s</string>
<string name="category_intro">Intermission/Intro Animation</string>
<string name="category_intro_description">An interval without actual content. Could be a pause, static frame, repeating animation. Should not be used for transitions containing info.</string>
<string name="category_intro_description">An interval without actual content. Could be a pause, static frame, repeating animation. Should not be used for transitions containing info: %s</string>
<string name="category_outro">End cards and credits</string>
<string name="category_outro_description">Info following the ending. Not for conclusions with info.</string>
<string name="category_outro_description">Info following the ending. Not for conclusions with info: %s</string>
<string name="category_filler">Filler Tangent/Jokes</string>
<string name="category_filler_description">For tangential scenes added only for filler or humor not required to understand the main content of the video.</string>
<string name="category_filler_description">For tangential scenes added only for filler or humor not required to understand the main content of the video: %s</string>
<string name="category_music_offtopic">Music: Non-Music Section</string>
<string name="category_music_offtopic_description">Only for use in music videos. It should cover parts of the video not part of official mixes. In the end, the video should resemble the Spotify or any other mixed version as closely as possible, or reduce talking or other distractions.</string>
<string name="category_music_offtopic_description">Only for use in music videos. It should cover parts of the video not part of official mixes. In the end, the video should resemble the Spotify or any other mixed version as closely as possible, or reduce talking or other distractions: %s</string>
<string name="category_preview">Preview/Recap</string>
<string name="category_preview_description">For segments detailing future content without additional info. If it includes clips that only appear here, this is very likely the wrong category.</string>
<string name="category_preview_description">For segments detailing future content without additional info. If it includes clips that only appear here, this is very likely the wrong category: %s</string>
<string name="license">License</string>
<string name="color_accent">Accents</string>
<string name="color_red">Resting red</string>
Expand Down Expand Up @@ -419,6 +419,9 @@
<string name="change_playlist_description">Change playlist description</string>
<string name="playlist_description">Playlist description</string>
<string name="emptyPlaylistDescription">The playlist description can\'t be empty</string>
<string name="off">Off</string>
<string name="manual">Manual</string>
<string name="automatic">Automatic</string>

<!-- Backup & Restore Settings -->
<string name="import_subscriptions_from">Import subscriptions from</string>
Expand Down
Loading