Merge pull request #223 from janisslsm/sponsorblock-integration

SponsorBlock Integration
This commit is contained in:
Bnyro 2022-05-16 16:18:45 +02:00 committed by GitHub
commit 87fdf964cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 250 additions and 8 deletions

View File

@ -45,6 +45,13 @@ class MainActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
RetrofitInstance.url = sharedPreferences.getString("instance", "https://pipedapi.kavin.rocks/")!!
SponsorBlockSettings.sponsorBlockEnabled = sharedPreferences.getBoolean("sponsorblock_enabled_key", false)
SponsorBlockSettings.introEnabled = sharedPreferences.getBoolean("intro_category_key", false)
SponsorBlockSettings.selfPromoEnabled = sharedPreferences.getBoolean("selfpromo_category_key", false)
SponsorBlockSettings.interactionEnabled = sharedPreferences.getBoolean("interaction_category_key", false)
SponsorBlockSettings.sponsorsEnabled = sharedPreferences.getBoolean("sponsors_category_key", false)
SponsorBlockSettings.outroEnabled = sharedPreferences.getBoolean("outro_category_key", false)
DynamicColors.applyToActivitiesIfAvailable(application)
val languageName = sharedPreferences.getString("language", "sys")
if (languageName != "") {

View File

@ -13,6 +13,9 @@ interface PipedApi {
@GET("comments/{videoId}")
suspend fun getComments(@Path("videoId") videoId: String): CommentsPage
@GET("sponsors/{videoId}")
suspend fun getSegments(@Path("videoId") videoId: String, @Query("category") category: String): Segments
@GET("nextpage/comments/{videoId}")
suspend fun getCommentsNextPage(@Path("videoId") videoId: String, @Query("nextpage") nextPage: String): CommentsPage

View File

@ -14,6 +14,7 @@ import android.os.Build.VERSION.SDK_INT
import android.os.Bundle
import android.os.Environment
import android.text.Html
import android.text.TextUtils
import android.util.Log
import android.view.LayoutInflater
import android.view.View
@ -35,6 +36,8 @@ import androidx.recyclerview.widget.RecyclerView
import com.github.libretube.adapters.CommentsAdapter
import com.github.libretube.adapters.TrendingAdapter
import com.github.libretube.obj.PipedStream
import com.github.libretube.obj.Segment
import com.github.libretube.obj.Segments
import com.github.libretube.obj.Subscribe
import com.google.android.exoplayer2.C
import com.google.android.exoplayer2.ExoPlayer
@ -87,6 +90,7 @@ class PlayerFragment : Fragment() {
private lateinit var motionLayout: MotionLayout
private lateinit var exoPlayer: ExoPlayer
private lateinit var mediaSource: MediaSource
private lateinit var segmentData: Segments
private lateinit var relDownloadVideo: LinearLayout
@ -270,6 +274,26 @@ class PlayerFragment : Fragment() {
}
}
private fun checkForSegments()
{
if (!exoPlayer.isPlaying || !SponsorBlockSettings.sponsorBlockEnabled) return
exoPlayerView.postDelayed(this::checkForSegments, 100)
if(segmentData.segments.isEmpty() )
return
segmentData.segments.forEach { segment: Segment ->
val segmentStart = (segment.segment!![0] * 1000.0f).toLong()
val segmentEnd = (segment.segment!![1] * 1000.0f).toLong()
val currentPosition = exoPlayer.currentPosition
if(currentPosition in segmentStart until segmentEnd) {
Toast.makeText(context,R.string.segment_skipped, Toast.LENGTH_SHORT).show()
exoPlayer.seekTo(segmentEnd);
}
}
}
private fun fetchJson(view: View) {
fun run() {
lifecycleScope.launchWhenCreated {
@ -297,6 +321,45 @@ class PlayerFragment : Fragment() {
Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show()
return@launchWhenCreated
}
if(SponsorBlockSettings.sponsorBlockEnabled) {
val categories: ArrayList<String> = arrayListOf()
if (SponsorBlockSettings.introEnabled) {
categories.add("intro")
}
if (SponsorBlockSettings.selfPromoEnabled) {
categories.add("selfpromo")
}
if (SponsorBlockSettings.interactionEnabled) {
categories.add("interaction")
}
if (SponsorBlockSettings.sponsorsEnabled) {
categories.add("sponsor")
}
if (SponsorBlockSettings.outroEnabled) {
categories.add("outro")
}
if(categories.size > 0) {
segmentData = try {
RetrofitInstance.api.getSegments(
videoId!!,
"[\"" + TextUtils.join("\",\"", categories) + "\"]"
)
} catch (e: IOException) {
println(e)
Log.e(TAG, "IOException, you might not have internet connection")
Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT)
.show()
return@launchWhenCreated
} catch (e: HttpException) {
Log.e(TAG, "HttpException, unexpected response")
Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT)
.show()
return@launchWhenCreated
}
}
}
isLoading = false
var videosNameArray: Array<CharSequence> = arrayOf()
videosNameArray += "HLS"
@ -502,6 +565,13 @@ class PlayerFragment : Fragment() {
}
// Listener for play and pause icon change
exoPlayer!!.addListener(object : com.google.android.exoplayer2.Player.Listener {
override fun onIsPlayingChanged(isPlaying: Boolean) {
if(isPlaying && SponsorBlockSettings.sponsorBlockEnabled)
{
exoPlayerView.postDelayed(this@PlayerFragment::checkForSegments, 100)
}
}
override fun onPlayerStateChanged(
playWhenReady: Boolean,
playbackState: Int

View File

@ -159,6 +159,15 @@ class SettingsActivity : AppCompatActivity(),
true
}
val sponsorblock = findPreference<Preference>("sponsorblock")
sponsorblock?.setOnPreferenceClickListener {
val newFragment = SponsorBlockSettings()
parentFragmentManager.beginTransaction()
.replace(R.id.settings, newFragment)
.commitNow()
true
}
val importFromYt = findPreference<Preference>("import_from_yt")
importFromYt?.setOnPreferenceClickListener {
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)

View File

@ -0,0 +1,55 @@
package com.github.libretube
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreferenceCompat
class SponsorBlockSettings : PreferenceFragmentCompat() {
private val TAG = "SponsorBlockDialog"
companion object {
var sponsorBlockEnabled: Boolean = false
var sponsorsEnabled: Boolean = false
var selfPromoEnabled: Boolean = false
var interactionEnabled: Boolean = false
var introEnabled: Boolean = false
var outroEnabled: Boolean = false
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.sponsorblock_settings, rootKey)
val sponsorBlockToggle = findPreference<SwitchPreferenceCompat>("sponsorblock_enabled_key")
sponsorBlockToggle?.setOnPreferenceChangeListener { _, newValue ->
sponsorBlockEnabled = newValue as Boolean
true
}
val sponsorToggle = findPreference<SwitchPreferenceCompat>("sponsors_category_key")
sponsorToggle?.setOnPreferenceChangeListener { _, newValue ->
sponsorsEnabled = newValue as Boolean
true
}
val selfPromoToggle = findPreference<SwitchPreferenceCompat>("selfpromo_category_key")
selfPromoToggle?.setOnPreferenceChangeListener { _, newValue ->
selfPromoEnabled = newValue as Boolean
true
}
val interactionToggle = findPreference<SwitchPreferenceCompat>("interaction_category_key")
interactionToggle?.setOnPreferenceChangeListener { _, newValue ->
interactionEnabled = newValue as Boolean
true
}
val introToggle = findPreference<SwitchPreferenceCompat>("intro_category_key")
introToggle?.setOnPreferenceChangeListener { _, newValue ->
introEnabled = newValue as Boolean
true
}
val outroToggle = findPreference<SwitchPreferenceCompat>("outro_category_key")
outroToggle?.setOnPreferenceChangeListener { _, newValue ->
outroEnabled = newValue as Boolean
true
}
}
}

View File

@ -0,0 +1,12 @@
package com.github.libretube.obj
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
@JsonIgnoreProperties(ignoreUnknown = true)
data class Segment(
val actionType: String?,
val category: String?,
val segment: List<Float>?
){
constructor(): this("", "", arrayListOf())
}

View File

@ -0,0 +1,10 @@
package com.github.libretube.obj
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
@JsonIgnoreProperties(ignoreUnknown = true)
data class Segments(
val segments: MutableList<Segment> = arrayListOf()
){
constructor(): this(arrayListOf())
}

View File

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="#FF000000"
android:pathData="M12,22.7994C11.55,22.7994 11.1,22.7094 10.74,22.4394 4.89,18.8394 1.29,12.6294 1.2,5.7894 1.2,4.8894 1.65,3.9894 2.46,3.5394 8.4,0.3894 15.6,0.3894 21.54,3.6294 22.35,3.9894 22.8,4.8894 22.8,5.7894 22.71,12.6294 19.11,18.8394 13.35,22.4394 12.9,22.7094 12.45,22.7994 12,22.7994ZM12,1.9194c-3.15,0 -6.3,0.81 -9.18,2.34 -0.54,0.27 -0.9,0.9 -0.9,1.53 0.09,6.57 3.51,12.51 9.18,16.02 0.54,0.36 1.26,0.36 1.8,0C18.57,18.3894 21.9,12.3594 22.08,5.7894 22.08,5.1594 21.72,4.5294 21.18,4.2594 18.3,2.7294 15.15,1.9194 12,1.9194Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M20.73,4.9794C15.24,2.0994 8.76,2.0994 3.27,4.9794 3,5.1594 2.82,5.4294 2.82,5.7894c0.09,6.48 3.51,12.06 8.73,15.3 0.27,0.18 0.63,0.18 0.9,0 5.13,-3.15 8.64,-8.82 8.73,-15.3C21.18,5.4294 21,5.1594 20.73,4.9794ZM9.66,15.1494L9.66,6.7794l7.29,4.23z"/>
</vector>

View File

@ -73,4 +73,20 @@
<string name="retry">Retry</string>
<string name="comments">Comments</string>
<string name="defaultTab">Default Tab</string>
<string name="sponsorblock">SponsorBlock</string>
<string name="sponsorblock_summary">Uses API from https://sponsor.ajay.app/</string>
<string name="segment_skipped">Skipped segment.</string>
<string name="category_header_title">SponsorBlock</string>
<string name="sponsorblock_state">Enabled</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 shoutouts to causes/creators/websites/products they like.</string>
<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 information about who they collaborated with.</string>
<string name="category_interaction">Interaction Reminder (Subscribe)</string>
<string name="category_interaction_description">When there is a short reminder to like, subscribe or follow them in the middle of content. If it is long or about something specific, it should be under self promotion instead.</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. This should not be used for transitions containing information.</string>
<string name="category_outro">Endcards/Credits</string>
<string name="category_outro_description">Credits or when the YouTube endcards appear. Not for conclusions with information.</string>
</resources>

View File

@ -71,14 +71,21 @@
android:icon="@drawable/ic_theme"
/>
<ListPreference
app:title="@string/defaultTab"
app:key="default_tab"
app:entries="@array/tabs"
app:entryValues="@array/tabsValue"
app:defaultValue="home"
android:icon="@drawable/ic_home"
/>
<androidx.preference.Preference
app:title="@string/sponsorblock"
app:key="sponsorblock"
app:summary="@string/sponsorblock_summary"
android:icon="@drawable/ic_sponsorblock"
/>
<ListPreference
app:title="@string/defaultTab"
app:key="default_tab"
app:entries="@array/tabs"
app:entryValues="@array/tabsValue"
app:defaultValue="home"
android:icon="@drawable/ic_home"
/>
<ListPreference
app:title="@string/defres"

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="@string/category_header_title">
<SwitchPreferenceCompat
app:key="sponsorblock_enabled_key"
app:title="@string/sponsorblock_state"/>
</PreferenceCategory>
<PreferenceCategory app:title="@string/category_segments">
<SwitchPreferenceCompat
app:key="sponsors_category_key"
app:title="@string/category_sponsor"
app:summary="@string/category_sponsor_description"/>
<SwitchPreferenceCompat
app:key="selfpromo_category_key"
app:title="@string/category_selfpromo"
app:summary="@string/category_selfpromo_description"/>
<SwitchPreferenceCompat
app:key="interaction_category_key"
app:title="@string/category_interaction"
app:summary="@string/category_interaction_description"/>
<SwitchPreferenceCompat
app:key="intro_category_key"
app:title="@string/category_intro"
app:summary="@string/category_intro_description"/>
<SwitchPreferenceCompat
app:key="outro_category_key"
app:title="@string/category_outro"
app:summary="@string/category_outro_description"/>
</PreferenceCategory>
</androidx.preference.PreferenceScreen>