Skip to content

Commit 51af8b4

Browse files
committed
feat: use online player for playing offline videos
1 parent 034981f commit 51af8b4

22 files changed

Lines changed: 593 additions & 932 deletions

app/src/main/java/com/github/libretube/api/obj/Streams.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ data class Streams(
2525
val uploaded: Long? = null,
2626

2727
val uploader: String,
28-
val uploaderUrl: String,
28+
val uploaderUrl: String?,
2929
val uploaderAvatar: String? = null,
3030
var thumbnailUrl: String,
3131
val category: String,

app/src/main/java/com/github/libretube/api/obj/Subtitle.kt

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package com.github.libretube.api.obj
22

3-
import android.content.Context
43
import android.os.Parcelable
5-
import com.github.libretube.R
64
import com.github.libretube.db.obj.DownloadItem
75
import com.github.libretube.enums.FileType
86
import com.github.libretube.helpers.ProxyHelper
@@ -19,12 +17,6 @@ data class Subtitle(
1917
val code: String? = null,
2018
val autoGenerated: Boolean? = null
2119
): Parcelable {
22-
fun getDisplayName(context: Context) = if (autoGenerated != true) {
23-
name!!
24-
} else {
25-
"$name (${context.getString(R.string.auto_generated)})"
26-
}
27-
2820
fun toDownloadItem(videoId: String) = DownloadItem(
2921
type = FileType.SUBTITLE,
3022
videoId = videoId,

app/src/main/java/com/github/libretube/db/obj/DownloadWithItems.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package com.github.libretube.db.obj
22

33
import androidx.room.Embedded
44
import androidx.room.Relation
5+
import com.github.libretube.api.obj.Streams
56
import com.github.libretube.enums.FileType
7+
import com.github.libretube.extensions.toMillis
68
import com.github.libretube.ui.fragments.DownloadTab
79

810
data class DownloadWithItems(
@@ -22,7 +24,20 @@ data class DownloadWithItems(
2224
entityColumn = "videoId"
2325
)
2426
val downloadSponsorBlockSegments: List<DownloadSponsorBlockSegment> = emptyList()
25-
)
27+
) {
28+
fun toStreams(): Streams = Streams(
29+
title = download.title,
30+
description = download.description,
31+
uploaderAvatar = null,
32+
thumbnailUrl = download.thumbnailPath?.toUri()?.toString().orEmpty(),
33+
category = "",
34+
uploader = download.uploader,
35+
uploaded = download.uploadDate?.toMillis(),
36+
duration = download.duration ?: 0,
37+
uploaderUrl = null,
38+
uploaderVerified = false
39+
)
40+
}
2641

2742
fun List<DownloadWithItems>.filterByTab(tab: DownloadTab) = filter { dl ->
2843
when (tab) {

app/src/main/java/com/github/libretube/extensions/SetMetadata.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import com.github.libretube.api.obj.Streams
1212
import com.github.libretube.constants.IntentData
1313
import com.github.libretube.db.obj.DownloadChapter
1414
import com.github.libretube.db.obj.DownloadWithItems
15-
import kotlinx.serialization.encodeToString
1615

1716
@OptIn(UnstableApi::class)
1817
fun MediaItem.Builder.setMetadata(streams: Streams, videoId: String) = apply {
@@ -32,7 +31,7 @@ fun MediaItem.Builder.setMetadata(streams: Streams, videoId: String) = apply {
3231
.setArtist(streams.uploader)
3332
.setDurationMs(streams.duration.times(1000))
3433
.setArtworkUri(streams.thumbnailUrl.toUri())
35-
.setComposer(streams.uploaderUrl.toID())
34+
.setComposer(streams.uploaderUrl.orEmpty().toID())
3635
.setExtras(extras)
3736
// send a unique timestamp to notify that the metadata changed, even if playing the same video twice
3837
.setTrackNumber(System.currentTimeMillis().mod(Int.MAX_VALUE))
@@ -44,11 +43,13 @@ fun MediaItem.Builder.setMetadata(streams: Streams, videoId: String) = apply {
4443
fun MediaItem.Builder.setMetadata(downloadWithItems: DownloadWithItems) = apply {
4544
val (download, _, downloadChapters) = downloadWithItems
4645
val chapters = downloadChapters.map(DownloadChapter::toChapterSegment)
46+
val streams = downloadWithItems.toStreams()
4747

4848
val extras = bundleOf(
4949
MediaMetadataCompat.METADATA_KEY_TITLE to download.title,
5050
MediaMetadataCompat.METADATA_KEY_ARTIST to download.uploader,
5151
IntentData.videoId to download.videoId,
52+
IntentData.streams to JsonHelper.json.encodeToString(streams),
5253
IntentData.chapters to JsonHelper.json.encodeToString(chapters)
5354
)
5455
setMediaMetadata(

app/src/main/java/com/github/libretube/helpers/NavigationHelper.kt

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import com.github.libretube.ui.activities.MainActivity
2020
import com.github.libretube.ui.activities.ZoomableImageActivity
2121
import com.github.libretube.ui.base.BaseActivity
2222
import com.github.libretube.ui.fragments.AudioPlayerFragment
23+
import com.github.libretube.ui.fragments.DownloadSortingOrder
24+
import com.github.libretube.ui.fragments.DownloadTab
2325
import com.github.libretube.ui.fragments.PlayerFragment
2426
import com.github.libretube.ui.views.SingleViewTouchableMotionLayout
2527
import com.github.libretube.util.PlayingQueue
@@ -57,8 +59,14 @@ object NavigationHelper {
5759
alreadyStarted: Boolean = false,
5860
forceVideo: Boolean = false,
5961
audioOnlyPlayerRequested: Boolean = false,
62+
downloadTab: DownloadTab? = null,
63+
downloadSortingOrder: DownloadSortingOrder? = null,
64+
shuffle: Boolean = false,
65+
isOffline: Boolean = false
6066
) {
6167
if (videoId == null) return
68+
// TODO: refactor all related methods to take [PlayerData] objects as arguments instead
69+
// of all these overcomplex amount of arguments!
6270

6371
// attempt to attach to the current media session first by using the corresponding
6472
// video/audio player instance
@@ -104,14 +112,25 @@ object NavigationHelper {
104112
if (audioOnlyPlayerRequested || (audioOnlyMode && !forceVideo)) {
105113
// in contrast to the video player, the audio player doesn't start a media service on
106114
// its own!
107-
BackgroundHelper.playOnBackground(
108-
context,
109-
videoId.toID(),
110-
timestamp,
111-
playlistId,
112-
channelId,
113-
keepQueue
114-
)
115+
if (isOffline) {
116+
BackgroundHelper.playOnBackground(
117+
context,
118+
videoId.toID(),
119+
timestamp,
120+
playlistId,
121+
channelId,
122+
keepQueue
123+
)
124+
} else {
125+
BackgroundHelper.playOnBackgroundOffline(
126+
context,
127+
videoId.toID(),
128+
playlistId,
129+
downloadTab!!,
130+
shuffle,
131+
downloadSortingOrder
132+
)
133+
}
115134

116135
openAudioPlayerFragment(context, minimizeByDefault = true)
117136
} else {
@@ -122,7 +141,11 @@ object NavigationHelper {
122141
channelId,
123142
keepQueue,
124143
timestamp,
125-
alreadyStarted
144+
alreadyStarted,
145+
shuffle,
146+
isOffline,
147+
downloadTab,
148+
downloadSortingOrder
126149
)
127150
}
128151
}
@@ -164,15 +187,19 @@ object NavigationHelper {
164187
channelId: String? = null,
165188
keepQueue: Boolean = false,
166189
timestamp: Long = 0,
167-
alreadyStarted: Boolean = false
190+
alreadyStarted: Boolean = false,
191+
shuffle: Boolean = false,
192+
isOffline: Boolean = false,
193+
downloadTab: DownloadTab? = null,
194+
downloadSortingOrder: DownloadSortingOrder? = null,
168195
) {
169196
val activity = ContextHelper.unwrapActivity<BaseActivity>(context)
170197

171198
val playerData =
172-
PlayerData(videoId, playlistId, channelId, keepQueue, timestamp)
199+
PlayerData(videoId, playlistId, channelId, keepQueue, timestamp, shuffle, isOffline, downloadTab, downloadSortingOrder)
173200
val bundle = bundleOf(
174201
IntentData.playerData to playerData,
175-
IntentData.alreadyStarted to alreadyStarted
202+
IntentData.alreadyStarted to alreadyStarted,
176203
)
177204
activity.supportFragmentManager.commitNow {
178205
replace<PlayerFragment>(R.id.container, args = bundle)

app/src/main/java/com/github/libretube/helpers/PlayerHelper.kt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ object PlayerHelper {
5959
private const val ACTION_MEDIA_CONTROL = "media_control"
6060
const val CONTROL_TYPE = "control_type"
6161
const val SPONSOR_HIGHLIGHT_CATEGORY = "poi_highlight"
62-
private const val ROLE_FLAG_AUTO_GEN_SUBTITLE = C.ROLE_FLAG_SUPPLEMENTARY
62+
const val ROLE_FLAG_AUTO_GEN_SUBTITLE = C.ROLE_FLAG_SUPPLEMENTARY
6363
private const val MINIMUM_BUFFER_DURATION = 1000 * 10 // exo default is 50s
6464
const val WATCH_POSITION_TIMER_DELAY_MS = 1000L
6565

@@ -607,6 +607,22 @@ object PlayerHelper {
607607
}
608608
}
609609

610+
private fun getTracksByType(player: Player, trackType: Int): List<Format> {
611+
val formats = mutableListOf<Format>()
612+
613+
for (trackGroup in player.currentTracks.groups) {
614+
if (trackGroup.type != trackType) continue
615+
616+
for (i in 0 until trackGroup.length) {
617+
val track = trackGroup.getTrackFormat(i)
618+
formats.add(track)
619+
}
620+
}
621+
return formats
622+
}
623+
624+
fun getCaptionTracks(player: Player) = getTracksByType(player, C.TRACK_TYPE_TEXT)
625+
610626
private fun getCurrentFormatByTrackType(player: Player, trackType: Int): Format? {
611627
for (trackGroup in player.currentTracks.groups) {
612628
if (trackGroup.type != trackType) continue
@@ -810,7 +826,7 @@ object PlayerHelper {
810826
return roleFlags or acontRoleFlags
811827
}
812828

813-
@OptIn(androidx.media3.common.util.UnstableApi::class)
829+
@OptIn(UnstableApi::class)
814830
fun getVideoStats(tracks: Tracks, videoId: String): VideoStats {
815831
val videoStats = VideoStats(videoId, "", "", "")
816832

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.github.libretube.parcelable
22

33
import android.os.Parcelable
4+
import com.github.libretube.ui.fragments.DownloadSortingOrder
5+
import com.github.libretube.ui.fragments.DownloadTab
46
import kotlinx.parcelize.Parcelize
57

68
@Parcelize
@@ -9,5 +11,9 @@ data class PlayerData(
911
val playlistId: String? = null,
1012
val channelId: String? = null,
1113
val keepQueue: Boolean = false,
12-
val timestamp: Long = 0
14+
val timestamp: Long = 0,
15+
val shuffle: Boolean = false,
16+
val isOffline: Boolean = false,
17+
val downloadTab: DownloadTab? = null,
18+
val downloadSortingOrder: DownloadSortingOrder? = null,
1319
) : Parcelable

app/src/main/java/com/github/libretube/services/OfflinePlayerService.kt

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import com.github.libretube.extensions.updateParameters
2727
import com.github.libretube.helpers.PlayerHelper
2828
import com.github.libretube.ui.activities.MainActivity
2929
import com.github.libretube.ui.activities.NoInternetActivity
30-
import com.github.libretube.ui.activities.OfflinePlayerActivity
3130
import com.github.libretube.ui.fragments.DownloadSortingOrder
3231
import com.github.libretube.ui.fragments.DownloadTab
3332
import com.github.libretube.ui.fragments.DownloadsFragmentPage.Companion.sortDownloadList
@@ -109,11 +108,7 @@ open class OfflinePlayerService : AbstractPlayerService() {
109108
}
110109

111110
override fun getIntentActivity(): Class<*> {
112-
return when {
113-
!noInternetService && isAudioOnlyPlayer -> MainActivity::class.java
114-
noInternetService && isAudioOnlyPlayer -> NoInternetActivity::class.java
115-
else -> OfflinePlayerActivity::class.java
116-
}
111+
return if (noInternetService) NoInternetActivity::class.java else MainActivity::class.java
117112
}
118113

119114
/**

0 commit comments

Comments
 (0)