Skip to content

Commit 103ae41

Browse files
committed
HLS Video Downloads
1 parent 65b4ed2 commit 103ae41

File tree

57 files changed

+2439
-1466
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+2439
-1466
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,42 @@
5757
</intent-filter>
5858
</receiver>
5959

60+
<service
61+
android:name=".download.hlsvideodownload.services.HlsVideoDownloadInternalStorageForegroundService"
62+
android:exported="false">
63+
<intent-filter>
64+
<action android:name="com.google.android.exoplayer.downloadService.action.RESTART" />
65+
<category android:name="android.intent.category.DEFAULT" />
66+
</intent-filter>
67+
</service>
68+
69+
<service
70+
android:name=".download.hlsvideodownload.services.HlsVideoDownloadSdcardStorageForegroundService"
71+
android:exported="false">
72+
<intent-filter>
73+
<action android:name="com.google.android.exoplayer.downloadService.action.RESTART" />
74+
<category android:name="android.intent.category.DEFAULT" />
75+
</intent-filter>
76+
</service>
77+
78+
<service
79+
android:name=".download.hlsvideodownload.services.HlsVideoDownloadInternalStorageBackgroundService"
80+
android:exported="false">
81+
<intent-filter>
82+
<action android:name="com.google.android.exoplayer.downloadService.action.RESTART" />
83+
<category android:name="android.intent.category.DEFAULT" />
84+
</intent-filter>
85+
</service>
86+
87+
<service
88+
android:name=".download.hlsvideodownload.services.HlsVideoDownloadSdcardStorageBackgroundService"
89+
android:exported="false">
90+
<intent-filter>
91+
<action android:name="com.google.android.exoplayer.downloadService.action.RESTART" />
92+
<category android:name="android.intent.category.DEFAULT" />
93+
</intent-filter>
94+
</service>
95+
6096
<provider
6197
android:name=".utils.FileProviderUtil"
6298
android:authorities="${applicationId}.fileprovider"

app/src/main/java/de/xikolo/App.kt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import android.webkit.WebView
66
import androidx.preference.PreferenceManager
77
import de.xikolo.config.Config
88
import de.xikolo.config.Feature
9-
import de.xikolo.download.filedownload.FileDownloadHandler
9+
import de.xikolo.download.Downloaders
1010
import de.xikolo.lanalytics.Lanalytics
1111
import de.xikolo.models.migrate.RealmSchemaMigration
1212
import de.xikolo.states.ConnectivityStateLiveData
@@ -62,7 +62,7 @@ class App : Application() {
6262
configureRealm()
6363
configureDefaultSettings()
6464
configureWebView()
65-
configureDownloader()
65+
configureDownloaders()
6666
if (Feature.SHORTCUTS) {
6767
ShortcutUtil.configureShortcuts(applicationContext)
6868
}
@@ -89,10 +89,8 @@ class App : Application() {
8989
}
9090
}
9191

92-
private fun configureDownloader() {
93-
// The initialization of Fetch takes some time when the object is initialized.
94-
// Initializing the object here makes sure the object is already initialized upon use so the UI does not hang.
95-
FileDownloadHandler
92+
private fun configureDownloaders() {
93+
Downloaders.initialize()
9694
}
9795

9896
fun syncCookieSyncManager() {

app/src/main/java/de/xikolo/config/Feature.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ import de.xikolo.utils.extensions.resExists
1111

1212
object Feature {
1313

14-
@JvmField
15-
val HLS_VIDEO = Config.DEBUG
16-
1714
@JvmField
1815
val PIP =
1916
SDK_INT >= 26 && App.instance.packageManager

app/src/main/java/de/xikolo/controllers/channels/ChannelCourseListAdapter.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import de.xikolo.utils.extensions.isBetween
2222
import de.xikolo.utils.extensions.setMarkdownText
2323
import de.xikolo.utils.extensions.videoThumbnailSize
2424
import de.xikolo.views.CustomSizeImageView
25-
import java.util.*
25+
import java.util.Date
2626

2727
class ChannelCourseListAdapter(fragment: Fragment, onCourseButtonClickListener: OnCourseButtonClickListener) : BaseCourseListAdapter<Triple<String?, VideoStream?, String?>>(fragment, onCourseButtonClickListener) {
2828

@@ -59,13 +59,19 @@ class ChannelCourseListAdapter(fragment: Fragment, onCourseButtonClickListener:
5959
holder.text.visibility = View.GONE
6060
}
6161

62-
if (stageStream?.hdUrl != null || stageStream?.sdUrl != null) {
62+
if (stageStream?.hlsUrl != null ||
63+
stageStream?.hdUrl != null ||
64+
stageStream?.sdUrl != null
65+
) {
6366
holder.videoPreview.visibility = View.VISIBLE
6467

6568
if (imageUrl != null) {
6669
GlideApp.with(fragment)
6770
.load(imageUrl)
68-
.override(holder.imageVideoThumbnail.forcedWidth, holder.imageVideoThumbnail.forcedHeight)
71+
.override(
72+
holder.imageVideoThumbnail.forcedWidth,
73+
holder.imageVideoThumbnail.forcedHeight
74+
)
6975
.into(holder.imageVideoThumbnail)
7076
}
7177

app/src/main/java/de/xikolo/controllers/channels/ChannelDetailsActivity.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ class ChannelDetailsActivity : CollapsingToolbarViewModelActivity<ChannelViewMod
5050
collapsingToolbar.setBackgroundColor(color)
5151
collapsingToolbar.setStatusBarScrimColor(color)
5252

53-
if (channel.stageStream?.hdUrl != null || channel.stageStream?.sdUrl != null) {
53+
if (channel.stageStream?.hlsUrl != null ||
54+
channel.stageStream?.hdUrl != null ||
55+
channel.stageStream?.sdUrl != null
56+
) {
5457
imageView.visibility = View.GONE
5558
lockCollapsingToolbar(channel.title)
5659
} else if (channel.imageUrl != null) {

app/src/main/java/de/xikolo/controllers/course/DescriptionFragment.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ class DescriptionFragment : ViewModelFragment<DescriptionViewModel>() {
8787
private fun showDescription(course: Course) {
8888
when {
8989
course.teaserStream != null
90-
&& (course.teaserStream.hdUrl != null || course.teaserStream.sdUrl != null) -> {
90+
&& (course.teaserStream.hlsUrl != null ||
91+
course.teaserStream.hdUrl != null ||
92+
course.teaserStream.sdUrl != null) -> {
9193
courseImage.visibility = View.GONE
9294
videoPreview.visibility = View.VISIBLE
9395

app/src/main/java/de/xikolo/controllers/dialogs/ModuleDownloadDialog.kt

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@ class ModuleDownloadDialog : BaseDialogFragment() {
1717
var listener: ItemSelectionListener? = null
1818

1919
@AutoBundleField(required = false)
20-
var hdVideo: Boolean = false
21-
22-
@AutoBundleField(required = false)
23-
var sdVideo: Boolean = false
20+
var video: Boolean = false
2421

2522
@AutoBundleField(required = false)
2623
var slides: Boolean = false
@@ -38,13 +35,12 @@ class ModuleDownloadDialog : BaseDialogFragment() {
3835
null
3936
) { _, which, isChecked ->
4037
when (which) {
41-
0 -> hdVideo = isChecked
42-
1 -> sdVideo = isChecked
43-
2 -> slides = isChecked
38+
0 -> video = isChecked
39+
1 -> slides = isChecked
4440
}
4541
}
4642
.setPositiveButton(R.string.download) { _, _ ->
47-
listener?.onSelected(this, hdVideo, sdVideo, slides)
43+
listener?.onSelected(this, video, slides)
4844
}
4945
.setNegativeButton(R.string.dialog_negative) { _, _ -> dialog?.cancel() }
5046
.setCancelable(true)
@@ -56,7 +52,7 @@ class ModuleDownloadDialog : BaseDialogFragment() {
5652
}
5753

5854
interface ItemSelectionListener {
59-
fun onSelected(dialog: DialogFragment, hdVideo: Boolean, sdVideo: Boolean, slides: Boolean)
55+
fun onSelected(dialog: DialogFragment, video: Boolean, slides: Boolean)
6056
}
6157

6258
}

app/src/main/java/de/xikolo/controllers/dialogs/StorageMigrationDialog.kt

Lines changed: 0 additions & 41 deletions
This file was deleted.

app/src/main/java/de/xikolo/controllers/downloads/DownloadsAdapter.kt

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,21 @@ import de.xikolo.App
1111
import de.xikolo.R
1212
import de.xikolo.utils.MetaSectionList
1313
import de.xikolo.utils.extensions.asFormattedFileSize
14-
import de.xikolo.utils.extensions.fileCount
15-
import de.xikolo.utils.extensions.folderSize
16-
import java.io.File
1714

18-
class DownloadsAdapter(private val callback: OnDeleteButtonClickedListener) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
15+
class DownloadsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
1916

2017
companion object {
2118
val TAG: String = DownloadsAdapter::class.java.simpleName
2219
private const val ITEM_VIEW_TYPE_HEADER = 0
2320
private const val ITEM_VIEW_TYPE_ITEM = 1
2421
}
2522

26-
private val sectionList: MetaSectionList<String, Any, List<FolderItem>> =
23+
private val sectionList: MetaSectionList<String, Any, List<DownloadCategory>> =
2724
MetaSectionList()
2825

29-
fun addItem(header: String, folder: List<FolderItem>) {
30-
if (folder.isNotEmpty()) {
31-
sectionList.add(header, folder)
26+
fun addItem(header: String, downloadCategory: List<DownloadCategory>) {
27+
if (downloadCategory.isNotEmpty()) {
28+
sectionList.add(header, downloadCategory)
3229
notifyDataSetChanged()
3330
}
3431
}
@@ -68,30 +65,34 @@ class DownloadsAdapter(private val callback: OnDeleteButtonClickedListener) : Re
6865
if (holder is HeaderViewHolder) {
6966
holder.title.text = sectionList.get(position) as String
7067
} else {
71-
val viewHolder = holder as FolderViewHolder
72-
73-
val folderItem = sectionList.get(position) as FolderItem
74-
75-
val context = App.instance
76-
77-
val dir = File(folderItem.path)
78-
viewHolder.textTitle.text = folderItem.title.replace("_".toRegex(), " ")
79-
80-
val numberOfFiles = dir.fileCount.toLong()
68+
val downloadCategory = sectionList.get(position) as DownloadCategory
8169

70+
val viewHolder = holder as FolderViewHolder
71+
viewHolder.textTitle.text = downloadCategory.title.replace("_".toRegex(), " ")
8272
viewHolder.textButtonDelete.setOnClickListener {
83-
callback.onDeleteButtonClicked(
84-
folderItem
85-
)
73+
downloadCategory.onDelete()
8674
}
8775

88-
if (numberOfFiles > 0) {
89-
viewHolder.textSubTitle.text = numberOfFiles.toString() + " " + context.getString(R.string.files) + ": " + dir.folderSize.asFormattedFileSize
90-
viewHolder.textButtonDelete.visibility = View.VISIBLE
91-
} else {
92-
viewHolder.textSubTitle.text = numberOfFiles.toString() + " " + context.getString(R.string.files)
93-
viewHolder.textButtonDelete.visibility = View.GONE
94-
}
76+
viewHolder.textSubTitle.text =
77+
when {
78+
downloadCategory.itemCount < 0 -> {
79+
viewHolder.textButtonDelete.visibility = View.VISIBLE
80+
downloadCategory.size.asFormattedFileSize
81+
}
82+
downloadCategory.itemCount == 0 -> {
83+
viewHolder.textButtonDelete.visibility = View.GONE
84+
downloadCategory.itemCount.toString() + " " +
85+
App.instance.getString(R.string.files)
86+
}
87+
else -> {
88+
viewHolder.textButtonDelete.visibility = View.VISIBLE
89+
downloadCategory.itemCount.toString() + " " +
90+
App.instance.getString(R.string.files) +
91+
if (downloadCategory.size > 0) {
92+
": " + downloadCategory.size.asFormattedFileSize
93+
} else ""
94+
}
95+
}
9596

9697
if (position == itemCount - 1 || sectionList.isHeader(position + 1)) {
9798
viewHolder.viewDivider.visibility = View.INVISIBLE
@@ -101,13 +102,12 @@ class DownloadsAdapter(private val callback: OnDeleteButtonClickedListener) : Re
101102
}
102103
}
103104

104-
class FolderItem(val title: String, val path: String)
105-
106-
interface OnDeleteButtonClickedListener {
107-
108-
fun onDeleteButtonClicked(item: FolderItem)
109-
110-
}
105+
data class DownloadCategory(
106+
val title: String,
107+
val size: Long,
108+
val itemCount: Int,
109+
val onDelete: () -> Unit
110+
)
111111

112112
internal class FolderViewHolder(view: View) : RecyclerView.ViewHolder(view) {
113113

0 commit comments

Comments
 (0)