Skip to content

Commit

Permalink
I FUCKING HATE EXOPLAYER SUBTITLES
Browse files Browse the repository at this point in the history
  • Loading branch information
rebelonion committed Jan 19, 2024
1 parent ea96291 commit 87a9df4
Show file tree
Hide file tree
Showing 9 changed files with 257 additions and 50 deletions.
56 changes: 53 additions & 3 deletions app/src/main/java/ani/dantotsu/download/DownloadsManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,17 @@ class DownloadsManager(private val context: Context) {
Toast.makeText(context, "Directory does not exist", Toast.LENGTH_SHORT).show()
cleanDownloads()
}
downloadsList.removeAll { it.title == title }
when (type) {
DownloadedType.Type.MANGA -> {
downloadsList.removeAll { it.title == title && it.type == DownloadedType.Type.MANGA }
}
DownloadedType.Type.ANIME -> {
downloadsList.removeAll { it.title == title && it.type == DownloadedType.Type.ANIME }
}
DownloadedType.Type.NOVEL -> {
downloadsList.removeAll { it.title == title && it.type == DownloadedType.Type.NOVEL }
}
}
saveDownloads()
}

Expand Down Expand Up @@ -126,7 +136,7 @@ class DownloadsManager(private val context: Context) {
{
val jsonString = gson.toJson(downloadsList)
val file = File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/downloads.json"
)
if (file.parentFile?.exists() == false) {
Expand Down Expand Up @@ -199,7 +209,7 @@ class DownloadsManager(private val context: Context) {
)
}
val destination = File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/${downloadedType.title}/${downloadedType.chapter}"
)
if (directory.exists()) {
Expand Down Expand Up @@ -241,6 +251,46 @@ class DownloadsManager(private val context: Context) {
const val novelLocation = "Dantotsu/Novel"
const val mangaLocation = "Dantotsu/Manga"
const val animeLocation = "Dantotsu/Anime"

fun getDirectory(context: Context, type: DownloadedType.Type, title: String, chapter: String? = null): File {
return if (type == DownloadedType.Type.MANGA) {
if (chapter != null) {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$mangaLocation/$title/$chapter"
)
} else {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$mangaLocation/$title"
)
}
} else if (type == DownloadedType.Type.ANIME) {
if (chapter != null) {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$animeLocation/$title/$chapter"
)
} else {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$animeLocation/$title"
)
}
} else {
if (chapter != null) {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$novelLocation/$title/$chapter"
)
} else {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$novelLocation/$title"
)
}
}
}
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import ani.dantotsu.download.video.ExoplayerDownloadService
import ani.dantotsu.download.video.Helper
import ani.dantotsu.logger
import ani.dantotsu.media.Media
import ani.dantotsu.media.SubtitleDownloader
import ani.dantotsu.media.anime.AnimeWatchFragment
import ani.dantotsu.parsers.Subtitle
import ani.dantotsu.parsers.Video
Expand Down Expand Up @@ -228,6 +229,17 @@ class AnimeDownloaderService : Service() {
}

saveMediaInfo(task)
task.subtitle?.let {
SubtitleDownloader.downloadSubtitle(
this@AnimeDownloaderService,
it.file.url,
DownloadedType(
task.title,
task.episode,
DownloadedType.Type.ANIME,
)
)
}
val downloadStarted =
hasDownloadStarted(downloadManager, task, 30000) // 30 seconds timeout

Expand Down Expand Up @@ -313,6 +325,7 @@ class AnimeDownloaderService : Service() {
} catch (e: Exception) {
logger("Exception while downloading file: ${e.message}")
snackString("Exception while downloading file: ${e.message}")
e.printStackTrace()
FirebaseCrashlytics.getInstance().recordException(e)
broadcastDownloadFailed(task.episode)
}
Expand Down
24 changes: 2 additions & 22 deletions app/src/main/java/ani/dantotsu/download/video/Helper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import androidx.core.content.ContextCompat.getString
import androidx.media3.common.C
import androidx.media3.common.MediaItem
import androidx.media3.common.MimeTypes
import androidx.media3.common.TrackSelectionParameters
import androidx.media3.common.util.UnstableApi
import androidx.media3.database.StandaloneDatabaseProvider
import androidx.media3.datasource.DataSource
Expand All @@ -30,6 +31,7 @@ import androidx.media3.exoplayer.offline.DownloadHelper
import androidx.media3.exoplayer.offline.DownloadManager
import androidx.media3.exoplayer.offline.DownloadService
import androidx.media3.exoplayer.scheduler.Requirements
import androidx.media3.ui.TrackSelectionDialogBuilder
import ani.dantotsu.R
import ani.dantotsu.defaultHeaders
import ani.dantotsu.download.DownloadedType
Expand Down Expand Up @@ -99,28 +101,6 @@ object Helper {
)
downloadHelper.prepare(object : DownloadHelper.Callback {
override fun onPrepared(helper: DownloadHelper) {
/*TrackSelectionDialogBuilder( TODO: use this for subtitles
context, "Select Source", helper.getTracks(0).groups
) { _, overrides ->
val params = TrackSelectionParameters.Builder(context)
overrides.forEach {
params.addOverride(it.value)
}
helper.addTrackSelection(0, params.build())
ExoplayerDownloadService
DownloadService.sendAddDownload(
context,
ExoplayerDownloadService::class.java,
helper.getDownloadRequest(null),
false
)
}.apply {
setTheme(R.style.DialogTheme)
setTrackNameProvider {
if (it.frameRate > 0f) it.height.toString() + "p" else it.height.toString() + "p (fps : N/A)"
}
build().show()
}*/
helper.getDownloadRequest(null).let {
DownloadService.sendAddDownload(
context,
Expand Down
46 changes: 43 additions & 3 deletions app/src/main/java/ani/dantotsu/media/SubtitleDownloader.kt
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
package ani.dantotsu.media

import android.content.Context
import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.parsers.SubtitleType
import ani.dantotsu.snackString
import eu.kanade.tachiyomi.network.NetworkHelper
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.Request
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.File

class SubtitleDownloader {

companion object {
//doesn't really download the subtitles -\_(o_o)_/-
suspend fun downloadSubtitles(context: Context, url: String): SubtitleType =
suspend fun loadSubtitleType(context: Context, url: String): SubtitleType =
withContext(Dispatchers.IO) {
// Initialize the NetworkHelper instance. Replace this line based on how you usually initialize it
val networkHelper = Injekt.get<NetworkHelper>()
Expand All @@ -29,8 +33,8 @@ class SubtitleDownloader {


val subtitleType = when {
responseBody.contains("[Script Info]") == true -> SubtitleType.ASS
responseBody.contains("WEBVTT") == true -> SubtitleType.VTT
responseBody.contains("[Script Info]") -> SubtitleType.ASS
responseBody.contains("WEBVTT") -> SubtitleType.VTT
else -> SubtitleType.SRT
}

Expand All @@ -39,5 +43,41 @@ class SubtitleDownloader {
return@withContext SubtitleType.UNKNOWN
}
}

//actually downloads lol
suspend fun downloadSubtitle(context: Context, url: String, downloadedType: DownloadedType) {
try {
val directory = DownloadsManager.getDirectory(context, downloadedType.type, downloadedType.title, downloadedType.chapter)
if (!directory.exists()) { //just in case
directory.mkdirs()
}
val type = loadSubtitleType(context, url)
val subtiteFile = File(directory, "subtitle.${type}")
if (subtiteFile.exists()) {
subtiteFile.delete()
}
subtiteFile.createNewFile()

val client = Injekt.get<NetworkHelper>().client
val request = Request.Builder().url(url).build()
val reponse = client.newCall(request).execute()

if (!reponse.isSuccessful) {
snackString("Failed to download subtitle")
return
}

reponse.body.byteStream().use { input ->
subtiteFile.outputStream().use { output ->
input.copyTo(output)
}
}
} catch (e: Exception) {
snackString("Failed to download subtitle")
e.printStackTrace()
return
}

}
}
}
26 changes: 20 additions & 6 deletions app/src/main/java/ani/dantotsu/media/anime/ExoplayerView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ import androidx.media3.common.*
import androidx.media3.common.C.AUDIO_CONTENT_TYPE_MOVIE
import androidx.media3.common.C.TRACK_TYPE_VIDEO
import androidx.media3.common.util.UnstableApi
import androidx.media3.common.util.Util
import androidx.media3.datasource.DataSource
import androidx.media3.datasource.DefaultDataSourceFactory
import androidx.media3.datasource.HttpDataSource
import androidx.media3.datasource.cache.CacheDataSource
import androidx.media3.datasource.okhttp.OkHttpDataSource
Expand Down Expand Up @@ -1284,7 +1286,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
if (subtitle?.type == SubtitleType.UNKNOWN) {
val context = this
runBlocking {
val type = SubtitleDownloader.downloadSubtitles(context, subtitle!!.file.url)
val type = SubtitleDownloader.loadSubtitleType(context, subtitle!!.file.url)
val fileUri = Uri.parse(subtitle!!.file.url)
sub = MediaItem.SubtitleConfiguration
.Builder(fileUri)
Expand All @@ -1302,8 +1304,9 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
}
println("sub: $sub")
} else {
val subUri = Uri.parse((subtitle!!.file.url))
sub = MediaItem.SubtitleConfiguration
.Builder(Uri.parse(subtitle!!.file.url))
.Builder(subUri)
.setSelectionFlags(C.SELECTION_FLAG_FORCED)
.setMimeType(
when (subtitle?.type) {
Expand Down Expand Up @@ -1338,9 +1341,14 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
}
dataSource
}
val dafuckDataSourceFactory = DefaultDataSourceFactory(this, Util.getUserAgent(this, R.string.app_name.toString()))
cacheFactory = CacheDataSource.Factory().apply {
setCache(Helper.getSimpleCache(this@ExoplayerView))
setUpstreamDataSourceFactory(dataSourceFactory)
if (ext.server.offline) {
setUpstreamDataSourceFactory(dafuckDataSourceFactory)
} else {
setUpstreamDataSourceFactory(dataSourceFactory)
}
setCacheWriteDataSinkFactory(null)
}

Expand Down Expand Up @@ -1374,7 +1382,14 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
}
builder.build()
} else {
downloadedMediaItem
val addedSubsDownloadedMediaItem = downloadedMediaItem.buildUpon()
if (sub != null) {
val listofnotnullsubs = immutableListOf(sub).filterNotNull()
val addLanguage = listofnotnullsubs[0].buildUpon().setLanguage("en").build()
addedSubsDownloadedMediaItem.setSubtitleConfigurations(immutableListOf(addLanguage))
episode.selectedSubtitle = 0
}
addedSubsDownloadedMediaItem.build()
}


Expand Down Expand Up @@ -1635,7 +1650,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
if (isInitialized) {
if (exoPlayer.currentPosition.toFloat() / exoPlayer.duration > settings.watchPercentage) {
preloading = true
nextEpisode(false) { i -> //TODO: make sure this works for offline episodes
nextEpisode(false) { i ->
val ep = episodes[episodeArr[currentEpisodeIndex + i]] ?: return@nextEpisode
val selected = media.selected ?: return@nextEpisode
lifecycleScope.launch(Dispatchers.IO) {
Expand Down Expand Up @@ -1806,7 +1821,6 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
}

super.onDestroy()
Glide.with(this).clear(exoPlay)
finishAndRemoveTask()
}

Expand Down
Loading

0 comments on commit 87a9df4

Please sign in to comment.