diff --git a/app/src/main/java/com/github/libretube/api/ExternalApi.kt b/app/src/main/java/com/github/libretube/api/ExternalApi.kt index b1958050c..84a0b596c 100644 --- a/app/src/main/java/com/github/libretube/api/ExternalApi.kt +++ b/app/src/main/java/com/github/libretube/api/ExternalApi.kt @@ -1,14 +1,17 @@ package com.github.libretube.api import com.github.libretube.api.obj.DeArrowBody +import com.github.libretube.api.obj.DeArrowContent import com.github.libretube.api.obj.PipedConfig import com.github.libretube.api.obj.PipedInstance +import com.github.libretube.api.obj.SegmentData import com.github.libretube.api.obj.SubmitSegmentResponse import com.github.libretube.api.obj.VoteInfo import com.github.libretube.obj.update.UpdateInfo import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.POST +import retrofit2.http.Path import retrofit2.http.Query import retrofit2.http.Url @@ -43,6 +46,13 @@ interface ExternalApi { @Query("description") description: String = "" ): List + @GET("$SB_API_URL/api/skipSegments/{videoId}") + suspend fun getSegments( + @Path("videoId") videoId: String, + @Query("category") category: List, + @Query("actionType") actionType: List? = null + ): List + @POST("$SB_API_URL/api/branding") suspend fun submitDeArrow(@Body body: DeArrowBody) @@ -55,4 +65,7 @@ interface ExternalApi { @Query("userID") userID: String, @Query("type") score: Int ) + + @GET("$SB_API_URL/api/branding/{videoId}") + suspend fun getDeArrowContent(@Path("videoId") videoId: String): Map } diff --git a/app/src/main/java/com/github/libretube/api/MediaServiceRepository.kt b/app/src/main/java/com/github/libretube/api/MediaServiceRepository.kt index c3123e2ae..f50707a16 100644 --- a/app/src/main/java/com/github/libretube/api/MediaServiceRepository.kt +++ b/app/src/main/java/com/github/libretube/api/MediaServiceRepository.kt @@ -17,8 +17,8 @@ interface MediaServiceRepository { suspend fun getComments(videoId: String): CommentsPage suspend fun getSegments( videoId: String, - category: String, - actionType: String? = null + category: List, + actionType: List? = null ): SegmentData suspend fun getDeArrowContent(videoIds: String): Map diff --git a/app/src/main/java/com/github/libretube/api/NewPipeMediaServiceRepository.kt b/app/src/main/java/com/github/libretube/api/NewPipeMediaServiceRepository.kt index fa431de91..f8b6e0329 100644 --- a/app/src/main/java/com/github/libretube/api/NewPipeMediaServiceRepository.kt +++ b/app/src/main/java/com/github/libretube/api/NewPipeMediaServiceRepository.kt @@ -20,6 +20,8 @@ import com.github.libretube.api.obj.StreamItem.Companion.TYPE_PLAYLIST import com.github.libretube.api.obj.StreamItem.Companion.TYPE_STREAM import com.github.libretube.api.obj.Streams import com.github.libretube.api.obj.Subtitle +import com.github.libretube.extensions.parallelMap +import com.github.libretube.extensions.sha256Sum import com.github.libretube.extensions.toID import com.github.libretube.helpers.NewPipeExtractorInstance import com.github.libretube.helpers.PlayerHelper @@ -321,13 +323,32 @@ class NewPipeMediaServiceRepository : MediaServiceRepository { } override suspend fun getSegments( - videoId: String, - category: String, - actionType: String? - ): SegmentData = SegmentData() + videoId: String, category: List, actionType: List? + ): SegmentData = RetrofitInstance.externalApi.getSegments( + // use hashed video id for privacy + // https://wiki.sponsor.ajay.app/w/API_Docs#GET_/api/skipSegments/:sha256HashPrefix + videoId.sha256Sum().substring(0, 4), category, actionType + ).first { it.videoID == videoId } override suspend fun getDeArrowContent(videoIds: String): Map = - emptyMap() + videoIds.split(',').chunked(25).flatMap { + it.parallelMap { videoId -> + runCatching { + RetrofitInstance.externalApi.getDeArrowContent( + // use hashed video id for privacy + // https://wiki.sponsor.ajay.app/w/API_Docs/DeArrow#GET_/api/branding/:sha256HashPrefix + videoId.sha256Sum().substring(0, 4) + ) + }.getOrNull() + } + }.filterNotNull().reduce { acc, map -> acc + map }.mapValues { (videoId, value) -> + value.copy( + thumbnails = value.thumbnails.map { thumbnail -> + thumbnail.takeIf { it.original } ?: thumbnail.copy( + thumbnail = "${DEARROW_THUMBNAIL_URL}?videoID=$videoId&time=${thumbnail.timestamp}" + ) + }) + } override suspend fun getSearchResults(searchQuery: String, filter: String): SearchResult { val queryHandler = NewPipeExtractorInstance.extractor.searchQHFactory.fromQuery( @@ -481,4 +502,8 @@ class NewPipeMediaServiceRepository : MediaServiceRepository { comments = commentsInfo.items.map { it.toComment() } ) } + + companion object { + private const val DEARROW_THUMBNAIL_URL = "https://dearrow-thumb.ajay.app/api/v1/getThumbnail" + } } diff --git a/app/src/main/java/com/github/libretube/api/PipedMediaServiceRepository.kt b/app/src/main/java/com/github/libretube/api/PipedMediaServiceRepository.kt index c1b9c1a92..77d45fb4e 100644 --- a/app/src/main/java/com/github/libretube/api/PipedMediaServiceRepository.kt +++ b/app/src/main/java/com/github/libretube/api/PipedMediaServiceRepository.kt @@ -13,6 +13,7 @@ import com.github.libretube.api.obj.StreamItem import com.github.libretube.api.obj.Streams import com.github.libretube.constants.PreferenceKeys import com.github.libretube.helpers.PreferenceHelper +import kotlinx.serialization.encodeToString import retrofit2.HttpException open class PipedMediaServiceRepository : MediaServiceRepository { @@ -36,9 +37,13 @@ open class PipedMediaServiceRepository : MediaServiceRepository { override suspend fun getSegments( videoId: String, - category: String, - actionType: String? - ): SegmentData = api.getSegments(videoId, category, actionType) + category: List, + actionType: List? + ): SegmentData = api.getSegments( + videoId, + JsonHelper.json.encodeToString(category), + JsonHelper.json.encodeToString(actionType) + ) override suspend fun getDeArrowContent(videoIds: String): Map = api.getDeArrowContent(videoIds) diff --git a/app/src/main/java/com/github/libretube/extensions/ShaSum.kt b/app/src/main/java/com/github/libretube/extensions/ShaSum.kt new file mode 100644 index 000000000..7750f2ed9 --- /dev/null +++ b/app/src/main/java/com/github/libretube/extensions/ShaSum.kt @@ -0,0 +1,11 @@ +package com.github.libretube.extensions + +import java.security.MessageDigest + +/** + * Calculates the SHA-256 hash of the String and returns the result in hexadecimal. + */ +@OptIn(ExperimentalStdlibApi::class) +fun String.sha256Sum(): String = MessageDigest.getInstance("SHA-256") + .digest(this.toByteArray()) + .toHexString() diff --git a/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt b/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt index 59fc5f8bc..938220638 100644 --- a/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt +++ b/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt @@ -209,8 +209,8 @@ open class OnlinePlayerService : AbstractPlayerService() { if (sponsorBlockConfig.isEmpty()) return@runCatching sponsorBlockSegments = MediaServiceRepository.instance.getSegments( videoId, - JsonHelper.json.encodeToString(sponsorBlockConfig.keys), - """["skip","mute","full","poi","chapter"]""" + sponsorBlockConfig.keys.toList(), + listOf("skip","mute","full","poi","chapter") ).segments withContext(Dispatchers.Main) { diff --git a/app/src/main/java/com/github/libretube/ui/dialogs/SubmitSegmentDialog.kt b/app/src/main/java/com/github/libretube/ui/dialogs/SubmitSegmentDialog.kt index ce5fb7061..70d7349c3 100644 --- a/app/src/main/java/com/github/libretube/ui/dialogs/SubmitSegmentDialog.kt +++ b/app/src/main/java/com/github/libretube/ui/dialogs/SubmitSegmentDialog.kt @@ -147,7 +147,7 @@ class SubmitSegmentDialog : DialogFragment() { private suspend fun fetchSegments() { val categories = resources.getStringArray(R.array.sponsorBlockSegments).toList() segments = try { - MediaServiceRepository.instance.getSegments(videoId, JsonHelper.json.encodeToString(categories)).segments + MediaServiceRepository.instance.getSegments(videoId, categories).segments } catch (e: Exception) { Log.e(TAG(), e.toString()) return