feat: logging to file
This commit is contained in:
parent
1028ac66cb
commit
dbce7c5b29
67 changed files with 475 additions and 324 deletions
|
@ -42,7 +42,7 @@ android {
|
||||||
buildTypes {
|
buildTypes {
|
||||||
alpha {
|
alpha {
|
||||||
applicationIdSuffix ".beta" // keep as beta by popular request
|
applicationIdSuffix ".beta" // keep as beta by popular request
|
||||||
versionNameSuffix "-alpha02"
|
versionNameSuffix "-alpha03"
|
||||||
manifestPlaceholders = [icon_placeholder: "@mipmap/ic_launcher_alpha", icon_placeholder_round: "@mipmap/ic_launcher_alpha_round"]
|
manifestPlaceholders = [icon_placeholder: "@mipmap/ic_launcher_alpha", icon_placeholder_round: "@mipmap/ic_launcher_alpha_round"]
|
||||||
debuggable System.getenv("CI") == null
|
debuggable System.getenv("CI") == null
|
||||||
isDefault true
|
isDefault true
|
||||||
|
|
|
@ -14,8 +14,18 @@ import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import ani.dantotsu.*
|
import ani.dantotsu.BuildConfig
|
||||||
|
import ani.dantotsu.Mapper
|
||||||
|
import ani.dantotsu.R
|
||||||
|
import ani.dantotsu.client
|
||||||
|
import ani.dantotsu.currContext
|
||||||
|
import ani.dantotsu.logError
|
||||||
|
import ani.dantotsu.openLinkInBrowser
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
|
import ani.dantotsu.snackString
|
||||||
|
import ani.dantotsu.toast
|
||||||
|
import ani.dantotsu.tryWithSuspend
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import io.noties.markwon.Markwon
|
import io.noties.markwon.Markwon
|
||||||
import io.noties.markwon.SoftBreakAddsNewLinePlugin
|
import io.noties.markwon.SoftBreakAddsNewLinePlugin
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -50,7 +60,7 @@ object AppUpdater {
|
||||||
res to res.substringAfter("# ").substringBefore("\n")
|
res to res.substringAfter("# ").substringBefore("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
logger("Git Version : $version")
|
Logger.log("Git Version : $version")
|
||||||
val dontShow = PrefManager.getCustomVal("dont_ask_for_update_$version", false)
|
val dontShow = PrefManager.getCustomVal("dont_ask_for_update_$version", false)
|
||||||
if (compareVersion(version) && !dontShow && !activity.isDestroyed) activity.runOnUiThread {
|
if (compareVersion(version) && !dontShow && !activity.isDestroyed) activity.runOnUiThread {
|
||||||
CustomBottomDialog.newInstance().apply {
|
CustomBottomDialog.newInstance().apply {
|
||||||
|
|
|
@ -21,6 +21,8 @@ import ani.dantotsu.parsers.novel.NovelExtensionManager
|
||||||
import ani.dantotsu.settings.SettingsActivity
|
import ani.dantotsu.settings.SettingsActivity
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
|
import ani.dantotsu.util.FinalExceptionHandler
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import com.google.android.material.color.DynamicColors
|
import com.google.android.material.color.DynamicColors
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
||||||
|
@ -83,7 +85,8 @@ class App : MultiDexApplication() {
|
||||||
}
|
}
|
||||||
crashlytics.setCustomKey("device Info", SettingsActivity.getDeviceInfo())
|
crashlytics.setCustomKey("device Info", SettingsActivity.getDeviceInfo())
|
||||||
|
|
||||||
|
Logger.init(this)
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler(FinalExceptionHandler())
|
||||||
|
|
||||||
initializeNetwork(baseContext)
|
initializeNetwork(baseContext)
|
||||||
|
|
||||||
|
@ -99,19 +102,19 @@ class App : MultiDexApplication() {
|
||||||
val animeScope = CoroutineScope(Dispatchers.Default)
|
val animeScope = CoroutineScope(Dispatchers.Default)
|
||||||
animeScope.launch {
|
animeScope.launch {
|
||||||
animeExtensionManager.findAvailableExtensions()
|
animeExtensionManager.findAvailableExtensions()
|
||||||
logger("Anime Extensions: ${animeExtensionManager.installedExtensionsFlow.first()}")
|
Logger.log("Anime Extensions: ${animeExtensionManager.installedExtensionsFlow.first()}")
|
||||||
AnimeSources.init(animeExtensionManager.installedExtensionsFlow)
|
AnimeSources.init(animeExtensionManager.installedExtensionsFlow)
|
||||||
}
|
}
|
||||||
val mangaScope = CoroutineScope(Dispatchers.Default)
|
val mangaScope = CoroutineScope(Dispatchers.Default)
|
||||||
mangaScope.launch {
|
mangaScope.launch {
|
||||||
mangaExtensionManager.findAvailableExtensions()
|
mangaExtensionManager.findAvailableExtensions()
|
||||||
logger("Manga Extensions: ${mangaExtensionManager.installedExtensionsFlow.first()}")
|
Logger.log("Manga Extensions: ${mangaExtensionManager.installedExtensionsFlow.first()}")
|
||||||
MangaSources.init(mangaExtensionManager.installedExtensionsFlow)
|
MangaSources.init(mangaExtensionManager.installedExtensionsFlow)
|
||||||
}
|
}
|
||||||
val novelScope = CoroutineScope(Dispatchers.Default)
|
val novelScope = CoroutineScope(Dispatchers.Default)
|
||||||
novelScope.launch {
|
novelScope.launch {
|
||||||
novelExtensionManager.findAvailableExtensions()
|
novelExtensionManager.findAvailableExtensions()
|
||||||
logger("Novel Extensions: ${novelExtensionManager.installedExtensionsFlow.first()}")
|
Logger.log("Novel Extensions: ${novelExtensionManager.installedExtensionsFlow.first()}")
|
||||||
NovelSources.init(novelExtensionManager.installedExtensionsFlow)
|
NovelSources.init(novelExtensionManager.installedExtensionsFlow)
|
||||||
}
|
}
|
||||||
val commentsScope = CoroutineScope(Dispatchers.Default)
|
val commentsScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
@ -138,7 +141,8 @@ class App : MultiDexApplication() {
|
||||||
try {
|
try {
|
||||||
Notifications.createChannels(this)
|
Notifications.createChannels(this)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logcat(LogPriority.ERROR, e) { "Failed to modify notification channels" }
|
Logger.log("Failed to modify notification channels")
|
||||||
|
Logger.log(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,6 @@ import android.telephony.TelephonyManager
|
||||||
import android.text.InputFilter
|
import android.text.InputFilter
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.util.Log
|
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
@ -60,6 +59,7 @@ import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.settings.saving.internal.PreferenceKeystore
|
import ani.dantotsu.settings.saving.internal.PreferenceKeystore
|
||||||
import ani.dantotsu.settings.saving.internal.PreferenceKeystore.Companion.generateSalt
|
import ani.dantotsu.settings.saving.internal.PreferenceKeystore.Companion.generateSalt
|
||||||
import ani.dantotsu.subcriptions.NotificationClickReceiver
|
import ani.dantotsu.subcriptions.NotificationClickReceiver
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.RequestBuilder
|
import com.bumptech.glide.RequestBuilder
|
||||||
import com.bumptech.glide.RequestManager
|
import com.bumptech.glide.RequestManager
|
||||||
|
@ -128,13 +128,6 @@ fun currActivity(): Activity? {
|
||||||
var loadMedia: Int? = null
|
var loadMedia: Int? = null
|
||||||
var loadIsMAL = false
|
var loadIsMAL = false
|
||||||
|
|
||||||
fun logger(e: Any?, print: Boolean = true) {
|
|
||||||
if (print)
|
|
||||||
//println(e)
|
|
||||||
Log.d("Logger", e.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun initActivity(a: Activity) {
|
fun initActivity(a: Activity) {
|
||||||
val window = a.window
|
val window = a.window
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
|
@ -306,7 +299,7 @@ class InputFilterMinMax(
|
||||||
val input = (dest.toString() + source.toString()).toDouble()
|
val input = (dest.toString() + source.toString()).toDouble()
|
||||||
if (isInRange(min, max, input)) return null
|
if (isInRange(min, max, input)) return null
|
||||||
} catch (nfe: NumberFormatException) {
|
} catch (nfe: NumberFormatException) {
|
||||||
logger(nfe.stackTraceToString())
|
Logger.log(nfe)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -761,7 +754,7 @@ fun saveImage(image: Bitmap, path: String, imageFileName: String): File? {
|
||||||
|
|
||||||
private fun scanFile(path: String, context: Context) {
|
private fun scanFile(path: String, context: Context) {
|
||||||
MediaScannerConnection.scanFile(context, arrayOf(path), null) { p, _ ->
|
MediaScannerConnection.scanFile(context, arrayOf(path), null) { p, _ ->
|
||||||
logger("Finished scanning $p")
|
Logger.log("Finished scanning $p")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -903,7 +896,7 @@ class EmptyAdapter(private val count: Int) : RecyclerView.Adapter<RecyclerView.V
|
||||||
|
|
||||||
fun toast(string: String?) {
|
fun toast(string: String?) {
|
||||||
if (string != null) {
|
if (string != null) {
|
||||||
logger(string)
|
Logger.log(string)
|
||||||
MainScope().launch {
|
MainScope().launch {
|
||||||
Toast.makeText(currActivity()?.application ?: return@launch, string, Toast.LENGTH_SHORT)
|
Toast.makeText(currActivity()?.application ?: return@launch, string, Toast.LENGTH_SHORT)
|
||||||
.show()
|
.show()
|
||||||
|
@ -942,10 +935,10 @@ fun snackString(s: String?, activity: Activity? = null, clipboard: String? = nul
|
||||||
}
|
}
|
||||||
return snackBar
|
return snackBar
|
||||||
}
|
}
|
||||||
logger(s)
|
Logger.log(s)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger(e.stackTraceToString())
|
Logger.log(e)
|
||||||
Injekt.get<CrashlyticsInterface>().logException(e)
|
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
|
|
|
@ -49,6 +49,7 @@ import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.settings.saving.SharedPreferenceBooleanLiveData
|
import ani.dantotsu.settings.saving.SharedPreferenceBooleanLiveData
|
||||||
import ani.dantotsu.subcriptions.Subscription.Companion.startSubscription
|
import ani.dantotsu.subcriptions.Subscription.Companion.startSubscription
|
||||||
import ani.dantotsu.themes.ThemeManager
|
import ani.dantotsu.themes.ThemeManager
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import com.google.android.material.snackbar.BaseTransientBottomBar
|
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
|
|
|
@ -5,6 +5,7 @@ import android.os.Build
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import ani.dantotsu.others.webview.CloudFlare
|
import ani.dantotsu.others.webview.CloudFlare
|
||||||
import ani.dantotsu.others.webview.WebViewBottomDialog
|
import ani.dantotsu.others.webview.WebViewBottomDialog
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import com.lagradost.nicehttp.Requests
|
import com.lagradost.nicehttp.Requests
|
||||||
import com.lagradost.nicehttp.ResponseParser
|
import com.lagradost.nicehttp.ResponseParser
|
||||||
import com.lagradost.nicehttp.addGenericDns
|
import com.lagradost.nicehttp.addGenericDns
|
||||||
|
@ -104,6 +105,7 @@ fun logError(e: Throwable, post: Boolean = true, snackbar: Boolean = true) {
|
||||||
toast(e.localizedMessage)
|
toast(e.localizedMessage)
|
||||||
}
|
}
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
Logger.log(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> tryWith(post: Boolean = false, snackbar: Boolean = true, call: () -> T): T? {
|
fun <T> tryWith(post: Boolean = false, snackbar: Boolean = true, call: () -> T): T? {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
import ani.dantotsu.toast
|
import ani.dantotsu.toast
|
||||||
import ani.dantotsu.tryWithSuspend
|
import ani.dantotsu.tryWithSuspend
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
|
|
||||||
object Anilist {
|
object Anilist {
|
||||||
|
@ -150,7 +151,7 @@ object Anilist {
|
||||||
cacheTime = cache ?: 10
|
cacheTime = cache ?: 10
|
||||||
)
|
)
|
||||||
val remaining = json.headers["X-RateLimit-Remaining"]?.toIntOrNull() ?: -1
|
val remaining = json.headers["X-RateLimit-Remaining"]?.toIntOrNull() ?: -1
|
||||||
Log.d("AnilistQuery", "Remaining requests: $remaining")
|
Logger.log("Remaining requests: $remaining")
|
||||||
if (json.code == 429) {
|
if (json.code == 429) {
|
||||||
val retry = json.headers["Retry-After"]?.toIntOrNull() ?: -1
|
val retry = json.headers["Retry-After"]?.toIntOrNull() ?: -1
|
||||||
val passedLimitReset = json.headers["X-RateLimit-Reset"]?.toLongOrNull() ?: 0
|
val passedLimitReset = json.headers["X-RateLimit-Reset"]?.toLongOrNull() ?: 0
|
||||||
|
@ -161,13 +162,13 @@ object Anilist {
|
||||||
toast("Rate limited. Try after $retry seconds")
|
toast("Rate limited. Try after $retry seconds")
|
||||||
throw Exception("Rate limited after $retry seconds")
|
throw Exception("Rate limited after $retry seconds")
|
||||||
}
|
}
|
||||||
if (!json.text.startsWith("{")) throw Exception(currContext()?.getString(R.string.anilist_down))
|
if (!json.text.startsWith("{")) {throw Exception(currContext()?.getString(R.string.anilist_down))}
|
||||||
if (show) println("Response : ${json.text}")
|
if (show) println("Response : ${json.text}")
|
||||||
json.parsed()
|
json.parsed()
|
||||||
} else null
|
} else null
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
if (show) snackString("Error fetching Anilist data: ${e.message}")
|
if (show) snackString("Error fetching Anilist data: ${e.message}")
|
||||||
Log.e("AnilistQuery", "Error: ${e.message}")
|
Logger.log("Anilist Query Error: ${e.message}")
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
import ani.dantotsu.tryWithSuspend
|
import ani.dantotsu.tryWithSuspend
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -99,6 +100,7 @@ class AnilistHomeViewModel : ViewModel() {
|
||||||
|
|
||||||
suspend fun initHomePage() {
|
suspend fun initHomePage() {
|
||||||
val res = Anilist.query.initHomePage()
|
val res = Anilist.query.initHomePage()
|
||||||
|
Logger.log("AnilistHomeViewModel : res=$res")
|
||||||
res["currentAnime"]?.let { animeContinue.postValue(it) }
|
res["currentAnime"]?.let { animeContinue.postValue(it) }
|
||||||
res["favoriteAnime"]?.let { animeFav.postValue(it) }
|
res["favoriteAnime"]?.let { animeFav.postValue(it) }
|
||||||
res["plannedAnime"]?.let { animePlanned.postValue(it) }
|
res["plannedAnime"]?.let { animePlanned.postValue(it) }
|
||||||
|
|
|
@ -4,7 +4,7 @@ import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import ani.dantotsu.logError
|
import ani.dantotsu.logError
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.startMainActivity
|
import ani.dantotsu.startMainActivity
|
||||||
|
@ -16,7 +16,7 @@ class Login : AppCompatActivity() {
|
||||||
|
|
||||||
ThemeManager(this).applyTheme()
|
ThemeManager(this).applyTheme()
|
||||||
val data: Uri? = intent?.data
|
val data: Uri? = intent?.data
|
||||||
logger(data.toString())
|
Logger.log(data.toString())
|
||||||
try {
|
try {
|
||||||
Anilist.token =
|
Anilist.token =
|
||||||
Regex("""(?<=access_token=).+(?=&token_type)""").find(data.toString())!!.value
|
Regex("""(?<=access_token=).+(?=&token_type)""").find(data.toString())!!.value
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
package ani.dantotsu.connections.crashlytics
|
package ani.dantotsu.connections.crashlytics
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
|
|
||||||
class CrashlyticsStub : CrashlyticsInterface {
|
class CrashlyticsStub : CrashlyticsInterface {
|
||||||
override fun initialize(context: Context) {
|
override fun initialize(context: Context) {
|
||||||
//no-op
|
//no-op
|
||||||
}
|
}
|
||||||
override fun logException(e: Throwable) {
|
override fun logException(e: Throwable) {
|
||||||
//no-op
|
Logger.log(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun log(message: String) {
|
override fun log(message: String) {
|
||||||
//no-op
|
Logger.log(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setUserId(id: String) {
|
override fun setUserId(id: String) {
|
||||||
|
|
|
@ -15,7 +15,6 @@ import android.os.Environment
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.util.Log
|
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
@ -26,6 +25,7 @@ import ani.dantotsu.connections.discord.serializers.User
|
||||||
import ani.dantotsu.isOnline
|
import ani.dantotsu.isOnline
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import com.google.gson.JsonParser
|
import com.google.gson.JsonParser
|
||||||
|
@ -274,7 +274,7 @@ class DiscordService : Service() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.message?.let { Log.d("WebSocket", "onFailure() $it") }
|
t.message?.let { Logger.log("onFailure() $it") }
|
||||||
log("WebSocket: Error, onFailure() reason: ${t.message}")
|
log("WebSocket: Error, onFailure() reason: ${t.message}")
|
||||||
client = OkHttpClient()
|
client = OkHttpClient()
|
||||||
client.newWebSocket(
|
client.newWebSocket(
|
||||||
|
@ -289,7 +289,7 @@ class DiscordService : Service() {
|
||||||
|
|
||||||
override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
|
override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
|
||||||
super.onClosing(webSocket, code, reason)
|
super.onClosing(webSocket, code, reason)
|
||||||
Log.d("WebSocket", "onClosing() $code $reason")
|
Logger.log("onClosing() $code $reason")
|
||||||
if (::heartbeatThread.isInitialized && !heartbeatThread.isInterrupted) {
|
if (::heartbeatThread.isInitialized && !heartbeatThread.isInterrupted) {
|
||||||
heartbeatThread.interrupt()
|
heartbeatThread.interrupt()
|
||||||
}
|
}
|
||||||
|
@ -297,7 +297,7 @@ class DiscordService : Service() {
|
||||||
|
|
||||||
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
|
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
|
||||||
super.onClosed(webSocket, code, reason)
|
super.onClosed(webSocket, code, reason)
|
||||||
Log.d("WebSocket", "onClosed() $code $reason")
|
Logger.log("onClosed() $code $reason")
|
||||||
if (code >= 4000) {
|
if (code >= 4000) {
|
||||||
log("WebSocket: Error, code: $code reason: $reason")
|
log("WebSocket: Error, code: $code reason: $reason")
|
||||||
client = OkHttpClient()
|
client = OkHttpClient()
|
||||||
|
@ -382,52 +382,7 @@ class DiscordService : Service() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun log(string: String) {
|
fun log(string: String) {
|
||||||
Log.d("WebSocket_Discord", string)
|
//Logger.log(string)
|
||||||
//log += "${SimpleDateFormat("HH:mm:ss").format(Calendar.getInstance().time)} $string\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
fun saveLogToFile() {
|
|
||||||
val fileName = "log_${System.currentTimeMillis()}.txt"
|
|
||||||
|
|
||||||
// ContentValues to store file metadata
|
|
||||||
val values = ContentValues().apply {
|
|
||||||
put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
|
|
||||||
put(MediaStore.MediaColumns.MIME_TYPE, "text/plain")
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
||||||
put(MediaStore.MediaColumns.RELATIVE_PATH, "Download/")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inserting the file in the MediaStore
|
|
||||||
val resolver = baseContext.contentResolver
|
|
||||||
val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
||||||
resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values)
|
|
||||||
} else {
|
|
||||||
val directory =
|
|
||||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
|
||||||
val file = File(directory, fileName)
|
|
||||||
|
|
||||||
// Make sure the Downloads directory exists
|
|
||||||
if (!directory.exists()) {
|
|
||||||
directory.mkdirs()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use FileProvider to get the URI for the file
|
|
||||||
val authority =
|
|
||||||
"${baseContext.packageName}.provider" // Adjust with your app's package name
|
|
||||||
Uri.fromFile(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writing to the file
|
|
||||||
uri?.let {
|
|
||||||
resolver.openOutputStream(it).use { outputStream ->
|
|
||||||
OutputStreamWriter(outputStream).use { writer ->
|
|
||||||
writer.write(log)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ?: run {
|
|
||||||
log("Error saving log file")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resume() {
|
fun resume() {
|
||||||
|
|
|
@ -27,7 +27,7 @@ import ani.dantotsu.download.DownloadedType
|
||||||
import ani.dantotsu.download.DownloadsManager
|
import ani.dantotsu.download.DownloadsManager
|
||||||
import ani.dantotsu.download.video.ExoplayerDownloadService
|
import ani.dantotsu.download.video.ExoplayerDownloadService
|
||||||
import ani.dantotsu.download.video.Helper
|
import ani.dantotsu.download.video.Helper
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.media.SubtitleDownloader
|
import ani.dantotsu.media.SubtitleDownloader
|
||||||
import ani.dantotsu.media.anime.AnimeWatchFragment
|
import ani.dantotsu.media.anime.AnimeWatchFragment
|
||||||
|
@ -249,7 +249,7 @@ class AnimeDownloaderService : Service() {
|
||||||
hasDownloadStarted(downloadManager, task, 30000) // 30 seconds timeout
|
hasDownloadStarted(downloadManager, task, 30000) // 30 seconds timeout
|
||||||
|
|
||||||
if (!downloadStarted) {
|
if (!downloadStarted) {
|
||||||
logger("Download failed to start")
|
Logger.log("Download failed to start")
|
||||||
builder.setContentText("${task.title} - ${task.episode} Download failed to start")
|
builder.setContentText("${task.title} - ${task.episode} Download failed to start")
|
||||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||||
snackString("${task.title} - ${task.episode} Download failed to start")
|
snackString("${task.title} - ${task.episode} Download failed to start")
|
||||||
|
@ -263,11 +263,11 @@ class AnimeDownloaderService : Service() {
|
||||||
val download = downloadManager.downloadIndex.getDownload(task.video.file.url)
|
val download = downloadManager.downloadIndex.getDownload(task.video.file.url)
|
||||||
if (download != null) {
|
if (download != null) {
|
||||||
if (download.state == androidx.media3.exoplayer.offline.Download.STATE_FAILED) {
|
if (download.state == androidx.media3.exoplayer.offline.Download.STATE_FAILED) {
|
||||||
logger("Download failed")
|
Logger.log("Download failed")
|
||||||
builder.setContentText("${task.title} - ${task.episode} Download failed")
|
builder.setContentText("${task.title} - ${task.episode} Download failed")
|
||||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||||
snackString("${task.title} - ${task.episode} Download failed")
|
snackString("${task.title} - ${task.episode} Download failed")
|
||||||
logger("Download failed: ${download.failureReason}")
|
Logger.log("Download failed: ${download.failureReason}")
|
||||||
downloadsManager.removeDownload(
|
downloadsManager.removeDownload(
|
||||||
DownloadedType(
|
DownloadedType(
|
||||||
task.title,
|
task.title,
|
||||||
|
@ -289,7 +289,7 @@ class AnimeDownloaderService : Service() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (download.state == androidx.media3.exoplayer.offline.Download.STATE_COMPLETED) {
|
if (download.state == androidx.media3.exoplayer.offline.Download.STATE_COMPLETED) {
|
||||||
logger("Download completed")
|
Logger.log("Download completed")
|
||||||
builder.setContentText("${task.title} - ${task.episode} Download completed")
|
builder.setContentText("${task.title} - ${task.episode} Download completed")
|
||||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||||
snackString("${task.title} - ${task.episode} Download completed")
|
snackString("${task.title} - ${task.episode} Download completed")
|
||||||
|
@ -309,7 +309,7 @@ class AnimeDownloaderService : Service() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (download.state == androidx.media3.exoplayer.offline.Download.STATE_STOPPED) {
|
if (download.state == androidx.media3.exoplayer.offline.Download.STATE_STOPPED) {
|
||||||
logger("Download stopped")
|
Logger.log("Download stopped")
|
||||||
builder.setContentText("${task.title} - ${task.episode} Download stopped")
|
builder.setContentText("${task.title} - ${task.episode} Download stopped")
|
||||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||||
snackString("${task.title} - ${task.episode} Download stopped")
|
snackString("${task.title} - ${task.episode} Download stopped")
|
||||||
|
@ -328,7 +328,7 @@ class AnimeDownloaderService : Service() {
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
if (e.message?.contains("Coroutine was cancelled") == false) { //wut
|
if (e.message?.contains("Coroutine was cancelled") == false) { //wut
|
||||||
logger("Exception while downloading file: ${e.message}")
|
Logger.log("Exception while downloading file: ${e.message}")
|
||||||
snackString("Exception while downloading file: ${e.message}")
|
snackString("Exception while downloading file: ${e.message}")
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
Injekt.get<CrashlyticsInterface>().logException(e)
|
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||||
|
|
|
@ -33,7 +33,7 @@ import ani.dantotsu.currContext
|
||||||
import ani.dantotsu.download.DownloadedType
|
import ani.dantotsu.download.DownloadedType
|
||||||
import ani.dantotsu.download.DownloadsManager
|
import ani.dantotsu.download.DownloadsManager
|
||||||
import ani.dantotsu.initActivity
|
import ani.dantotsu.initActivity
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.media.MediaDetailsActivity
|
import ani.dantotsu.media.MediaDetailsActivity
|
||||||
import ani.dantotsu.navBarHeight
|
import ani.dantotsu.navBarHeight
|
||||||
|
@ -318,8 +318,8 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
|
||||||
val mediaJson = media.readText()
|
val mediaJson = media.readText()
|
||||||
gson.fromJson(mediaJson, Media::class.java)
|
gson.fromJson(mediaJson, Media::class.java)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("Error loading media.json: ${e.message}")
|
Logger.log("Error loading media.json: ${e.message}")
|
||||||
logger(e.printStackTrace())
|
Logger.log(e)
|
||||||
Injekt.get<CrashlyticsInterface>().logException(e)
|
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
@ -374,8 +374,8 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
|
||||||
bannerUri
|
bannerUri
|
||||||
)
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("Error loading media.json: ${e.message}")
|
Logger.log("Error loading media.json: ${e.message}")
|
||||||
logger(e.printStackTrace())
|
Logger.log(e)
|
||||||
Injekt.get<CrashlyticsInterface>().logException(e)
|
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||||
return OfflineAnimeModel(
|
return OfflineAnimeModel(
|
||||||
"unknown",
|
"unknown",
|
||||||
|
|
|
@ -21,7 +21,7 @@ import ani.dantotsu.R
|
||||||
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
||||||
import ani.dantotsu.download.DownloadedType
|
import ani.dantotsu.download.DownloadedType
|
||||||
import ani.dantotsu.download.DownloadsManager
|
import ani.dantotsu.download.DownloadsManager
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.media.manga.ImageData
|
import ani.dantotsu.media.manga.ImageData
|
||||||
import ani.dantotsu.media.manga.MangaReadFragment.Companion.ACTION_DOWNLOAD_FAILED
|
import ani.dantotsu.media.manga.MangaReadFragment.Companion.ACTION_DOWNLOAD_FAILED
|
||||||
|
@ -251,7 +251,7 @@ class MangaDownloaderService : Service() {
|
||||||
snackString("${task.title} - ${task.chapter} Download finished")
|
snackString("${task.title} - ${task.chapter} Download finished")
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("Exception while downloading file: ${e.message}")
|
Logger.log("Exception while downloading file: ${e.message}")
|
||||||
snackString("Exception while downloading file: ${e.message}")
|
snackString("Exception while downloading file: ${e.message}")
|
||||||
Injekt.get<CrashlyticsInterface>().logException(e)
|
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||||
broadcastDownloadFailed(task.chapter)
|
broadcastDownloadFailed(task.chapter)
|
||||||
|
|
|
@ -30,7 +30,7 @@ import ani.dantotsu.currContext
|
||||||
import ani.dantotsu.download.DownloadedType
|
import ani.dantotsu.download.DownloadedType
|
||||||
import ani.dantotsu.download.DownloadsManager
|
import ani.dantotsu.download.DownloadsManager
|
||||||
import ani.dantotsu.initActivity
|
import ani.dantotsu.initActivity
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.media.MediaDetailsActivity
|
import ani.dantotsu.media.MediaDetailsActivity
|
||||||
import ani.dantotsu.navBarHeight
|
import ani.dantotsu.navBarHeight
|
||||||
|
@ -308,8 +308,8 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
||||||
val mediaJson = media.readText()
|
val mediaJson = media.readText()
|
||||||
gson.fromJson(mediaJson, Media::class.java)
|
gson.fromJson(mediaJson, Media::class.java)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("Error loading media.json: ${e.message}")
|
Logger.log("Error loading media.json: ${e.message}")
|
||||||
logger(e.printStackTrace())
|
Logger.log(e)
|
||||||
Injekt.get<CrashlyticsInterface>().logException(e)
|
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
@ -358,8 +358,8 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
||||||
bannerUri
|
bannerUri
|
||||||
)
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("Error loading media.json: ${e.message}")
|
Logger.log("Error loading media.json: ${e.message}")
|
||||||
logger(e.printStackTrace())
|
Logger.log(e)
|
||||||
Injekt.get<CrashlyticsInterface>().logException(e)
|
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||||
return OfflineMangaModel(
|
return OfflineMangaModel(
|
||||||
"unknown",
|
"unknown",
|
||||||
|
|
|
@ -20,7 +20,7 @@ import ani.dantotsu.R
|
||||||
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
||||||
import ani.dantotsu.download.DownloadedType
|
import ani.dantotsu.download.DownloadedType
|
||||||
import ani.dantotsu.download.DownloadsManager
|
import ani.dantotsu.download.DownloadsManager
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.media.novel.NovelReadFragment
|
import ani.dantotsu.media.novel.NovelReadFragment
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
|
@ -186,15 +186,15 @@ class NovelDownloaderService : Service() {
|
||||||
val contentType = response.header("Content-Type")
|
val contentType = response.header("Content-Type")
|
||||||
val contentDisposition = response.header("Content-Disposition")
|
val contentDisposition = response.header("Content-Disposition")
|
||||||
|
|
||||||
logger("Content-Type: $contentType")
|
Logger.log("Content-Type: $contentType")
|
||||||
logger("Content-Disposition: $contentDisposition")
|
Logger.log("Content-Disposition: $contentDisposition")
|
||||||
|
|
||||||
// Return true if the Content-Type or Content-Disposition indicates an EPUB file
|
// Return true if the Content-Type or Content-Disposition indicates an EPUB file
|
||||||
contentType == "application/epub+zip" ||
|
contentType == "application/epub+zip" ||
|
||||||
(contentDisposition?.contains(".epub") == true)
|
(contentDisposition?.contains(".epub") == true)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("Error checking file type: ${e.message}")
|
Logger.log("Error checking file type: ${e.message}")
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,12 +225,12 @@ class NovelDownloaderService : Service() {
|
||||||
|
|
||||||
if (!isEpubFile(task.downloadLink)) {
|
if (!isEpubFile(task.downloadLink)) {
|
||||||
if (isAlreadyDownloaded(task.originalLink)) {
|
if (isAlreadyDownloaded(task.originalLink)) {
|
||||||
logger("Already downloaded")
|
Logger.log("Already downloaded")
|
||||||
broadcastDownloadFinished(task.originalLink)
|
broadcastDownloadFinished(task.originalLink)
|
||||||
snackString("Already downloaded")
|
snackString("Already downloaded")
|
||||||
return@withContext
|
return@withContext
|
||||||
}
|
}
|
||||||
logger("Download link is not an .epub file")
|
Logger.log("Download link is not an .epub file")
|
||||||
broadcastDownloadFailed(task.originalLink)
|
broadcastDownloadFailed(task.originalLink)
|
||||||
snackString("Download link is not an .epub file")
|
snackString("Download link is not an .epub file")
|
||||||
return@withContext
|
return@withContext
|
||||||
|
@ -301,7 +301,7 @@ class NovelDownloaderService : Service() {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
val progress =
|
val progress =
|
||||||
(downloadedBytes * 100 / totalBytes).toInt()
|
(downloadedBytes * 100 / totalBytes).toInt()
|
||||||
logger("Download progress: $progress")
|
Logger.log("Download progress: $progress")
|
||||||
broadcastDownloadProgress(task.originalLink, progress)
|
broadcastDownloadProgress(task.originalLink, progress)
|
||||||
}
|
}
|
||||||
lastBroadcastUpdate = downloadedBytes
|
lastBroadcastUpdate = downloadedBytes
|
||||||
|
@ -316,7 +316,7 @@ class NovelDownloaderService : Service() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("Exception while downloading .epub inside request: ${e.message}")
|
Logger.log("Exception while downloading .epub inside request: ${e.message}")
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,7 +340,7 @@ class NovelDownloaderService : Service() {
|
||||||
snackString("${task.title} - ${task.chapter} Download finished")
|
snackString("${task.title} - ${task.chapter} Download finished")
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("Exception while downloading .epub: ${e.message}")
|
Logger.log("Exception while downloading .epub: ${e.message}")
|
||||||
snackString("Exception while downloading .epub: ${e.message}")
|
snackString("Exception while downloading .epub: ${e.message}")
|
||||||
Injekt.get<CrashlyticsInterface>().logException(e)
|
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||||
broadcastDownloadFailed(task.originalLink)
|
broadcastDownloadFailed(task.originalLink)
|
||||||
|
|
|
@ -43,6 +43,7 @@ import ani.dantotsu.parsers.SubtitleType
|
||||||
import ani.dantotsu.parsers.Video
|
import ani.dantotsu.parsers.Video
|
||||||
import ani.dantotsu.parsers.VideoType
|
import ani.dantotsu.parsers.VideoType
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
@ -157,15 +158,15 @@ object Helper {
|
||||||
finalException: Exception?
|
finalException: Exception?
|
||||||
) {
|
) {
|
||||||
if (download.state == Download.STATE_COMPLETED) {
|
if (download.state == Download.STATE_COMPLETED) {
|
||||||
Log.e("Downloader", "Download Completed")
|
Logger.log("Download Completed")
|
||||||
} else if (download.state == Download.STATE_FAILED) {
|
} else if (download.state == Download.STATE_FAILED) {
|
||||||
Log.e("Downloader", "Download Failed")
|
Logger.log("Download Failed")
|
||||||
} else if (download.state == Download.STATE_STOPPED) {
|
} else if (download.state == Download.STATE_STOPPED) {
|
||||||
Log.e("Downloader", "Download Stopped")
|
Logger.log("Download Stopped")
|
||||||
} else if (download.state == Download.STATE_QUEUED) {
|
} else if (download.state == Download.STATE_QUEUED) {
|
||||||
Log.e("Downloader", "Download Queued")
|
Logger.log("Download Queued")
|
||||||
} else if (download.state == Download.STATE_DOWNLOADING) {
|
} else if (download.state == Download.STATE_DOWNLOADING) {
|
||||||
Log.e("Downloader", "Download Downloading")
|
Logger.log("Download Downloading")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import androidx.lifecycle.ViewModel
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.connections.anilist.Anilist
|
import ani.dantotsu.connections.anilist.Anilist
|
||||||
import ani.dantotsu.currContext
|
import ani.dantotsu.currContext
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.media.anime.Episode
|
import ani.dantotsu.media.anime.Episode
|
||||||
import ani.dantotsu.media.anime.SelectorDialogFragment
|
import ani.dantotsu.media.anime.SelectorDialogFragment
|
||||||
import ani.dantotsu.media.manga.MangaChapter
|
import ani.dantotsu.media.manga.MangaChapter
|
||||||
|
@ -223,7 +223,7 @@ class MediaDetailsViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setEpisode(ep: Episode?, who: String) {
|
fun setEpisode(ep: Episode?, who: String) {
|
||||||
logger("set episode ${ep?.number} - $who", false)
|
Logger.log("set episode ${ep?.number} - $who")
|
||||||
episode.postValue(ep)
|
episode.postValue(ep)
|
||||||
MainScope().launch(Dispatchers.Main) {
|
MainScope().launch(Dispatchers.Main) {
|
||||||
episode.value = null
|
episode.value = null
|
||||||
|
@ -270,7 +270,7 @@ class MediaDetailsViewModel : ViewModel() {
|
||||||
mangaChapters
|
mangaChapters
|
||||||
|
|
||||||
suspend fun loadMangaChapters(media: Media, i: Int, invalidate: Boolean = false) {
|
suspend fun loadMangaChapters(media: Media, i: Int, invalidate: Boolean = false) {
|
||||||
logger("Loading Manga Chapters : $mangaLoaded")
|
Logger.log("Loading Manga Chapters : $mangaLoaded")
|
||||||
if (!mangaLoaded.containsKey(i) || invalidate) tryWithSuspend {
|
if (!mangaLoaded.containsKey(i) || invalidate) tryWithSuspend {
|
||||||
mangaLoaded[i] =
|
mangaLoaded[i] =
|
||||||
mangaReadSources?.loadChaptersFromMedia(i, media) ?: return@tryWithSuspend
|
mangaReadSources?.loadChaptersFromMedia(i, media) ?: return@tryWithSuspend
|
||||||
|
|
|
@ -86,6 +86,7 @@ import ani.dantotsu.settings.PlayerSettingsActivity
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.themes.ThemeManager
|
import ani.dantotsu.themes.ThemeManager
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.google.android.gms.cast.framework.CastButtonFactory
|
import com.google.android.gms.cast.framework.CastButtonFactory
|
||||||
import com.google.android.gms.cast.framework.CastContext
|
import com.google.android.gms.cast.framework.CastContext
|
||||||
|
@ -1372,8 +1373,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
|
||||||
|
|
||||||
mediaItem = if (downloadedMediaItem == null) {
|
mediaItem = if (downloadedMediaItem == null) {
|
||||||
val builder = MediaItem.Builder().setUri(video!!.file.url).setMimeType(mimeType)
|
val builder = MediaItem.Builder().setUri(video!!.file.url).setMimeType(mimeType)
|
||||||
logger("url: ${video!!.file.url}")
|
Logger.log("url: ${video!!.file.url}")
|
||||||
logger("mimeType: $mimeType")
|
Logger.log("mimeType: $mimeType")
|
||||||
|
|
||||||
if (sub != null) {
|
if (sub != null) {
|
||||||
val listofnotnullsubs = listOfNotNull(sub)
|
val listofnotnullsubs = listOfNotNull(sub)
|
||||||
|
|
|
@ -10,7 +10,7 @@ import android.os.Build
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.util.LruCache
|
import android.util.LruCache
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
|
@ -32,8 +32,8 @@ data class ImageData(
|
||||||
try {
|
try {
|
||||||
// Fetch the image
|
// Fetch the image
|
||||||
val response = httpSource.getImage(page)
|
val response = httpSource.getImage(page)
|
||||||
logger("Response: ${response.code}")
|
Logger.log("Response: ${response.code}")
|
||||||
logger("Response: ${response.message}")
|
Logger.log("Response: ${response.message}")
|
||||||
|
|
||||||
// Convert the Response to an InputStream
|
// Convert the Response to an InputStream
|
||||||
val inputStream = response.body.byteStream()
|
val inputStream = response.body.byteStream()
|
||||||
|
@ -47,7 +47,7 @@ data class ImageData(
|
||||||
return@withContext bitmap
|
return@withContext bitmap
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// Handle any exceptions
|
// Handle any exceptions
|
||||||
logger("An error occurred: ${e.message}")
|
Logger.log("An error occurred: ${e.message}")
|
||||||
snackString("An error occurred: ${e.message}")
|
snackString("An error occurred: ${e.message}")
|
||||||
return@withContext null
|
return@withContext null
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import ani.dantotsu.media.MediaDetailsViewModel
|
||||||
import ani.dantotsu.media.novel.novelreader.NovelReaderActivity
|
import ani.dantotsu.media.novel.novelreader.NovelReaderActivity
|
||||||
import ani.dantotsu.navBarHeight
|
import ani.dantotsu.navBarHeight
|
||||||
import ani.dantotsu.parsers.ShowResponse
|
import ani.dantotsu.parsers.ShowResponse
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -59,7 +60,7 @@ class NovelReadFragment : Fragment(),
|
||||||
var loaded = false
|
var loaded = false
|
||||||
|
|
||||||
override fun downloadTrigger(novelDownloadPackage: NovelDownloadPackage) {
|
override fun downloadTrigger(novelDownloadPackage: NovelDownloadPackage) {
|
||||||
Log.e("downloadTrigger", novelDownloadPackage.link)
|
Logger.log("novel link: ${novelDownloadPackage.link}")
|
||||||
val downloadTask = NovelDownloaderService.DownloadTask(
|
val downloadTask = NovelDownloaderService.DownloadTask(
|
||||||
title = media.mainName(),
|
title = media.mainName(),
|
||||||
chapter = novelDownloadPackage.novelName,
|
chapter = novelDownloadPackage.novelName,
|
||||||
|
|
|
@ -11,6 +11,7 @@ import ani.dantotsu.databinding.ItemNovelResponseBinding
|
||||||
import ani.dantotsu.parsers.ShowResponse
|
import ani.dantotsu.parsers.ShowResponse
|
||||||
import ani.dantotsu.setAnimation
|
import ani.dantotsu.setAnimation
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.load.model.GlideUrl
|
import com.bumptech.glide.load.model.GlideUrl
|
||||||
|
|
||||||
|
@ -181,7 +182,7 @@ class NovelResponseAdapter(
|
||||||
if (position != -1) {
|
if (position != -1) {
|
||||||
list[position].extra?.remove("0")
|
list[position].extra?.remove("0")
|
||||||
list[position].extra?.set("0", "Downloading: $progress%")
|
list[position].extra?.set("0", "Downloading: $progress%")
|
||||||
Log.d("NovelResponseAdapter", "updateDownloadProgress: $progress, position: $position")
|
Logger.log( "updateDownloadProgress: $progress, position: $position")
|
||||||
notifyItemChanged(position)
|
notifyItemChanged(position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package ani.dantotsu.others
|
package ani.dantotsu.others
|
||||||
|
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ class JsUnpacker(packedJS: String?) {
|
||||||
return decoded.toString()
|
return decoded.toString()
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger(e)
|
Logger.log(e)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package ani.dantotsu.others
|
||||||
|
|
||||||
import ani.dantotsu.FileUrl
|
import ani.dantotsu.FileUrl
|
||||||
import ani.dantotsu.client
|
import ani.dantotsu.client
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.media.anime.Episode
|
import ani.dantotsu.media.anime.Episode
|
||||||
import ani.dantotsu.tryWithSuspend
|
import ani.dantotsu.tryWithSuspend
|
||||||
|
@ -41,8 +41,7 @@ object Kitsu {
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getKitsuEpisodesDetails(media: Media): Map<String, Episode>? {
|
suspend fun getKitsuEpisodesDetails(media: Media): Map<String, Episode>? {
|
||||||
val print = false
|
Logger.log("Kitsu : title=${media.mainName()}")
|
||||||
logger("Kitsu : title=${media.mainName()}", print)
|
|
||||||
val query =
|
val query =
|
||||||
"""
|
"""
|
||||||
query {
|
query {
|
||||||
|
@ -70,7 +69,7 @@ query {
|
||||||
|
|
||||||
|
|
||||||
val result = getKitsuData(query) ?: return null
|
val result = getKitsuData(query) ?: return null
|
||||||
logger("Kitsu : result=$result", print)
|
//Logger.log("Kitsu : result=$result")
|
||||||
media.idKitsu = result.data?.lookupMapping?.id
|
media.idKitsu = result.data?.lookupMapping?.id
|
||||||
val a = (result.data?.lookupMapping?.episodes?.nodes ?: return null).mapNotNull { ep ->
|
val a = (result.data?.lookupMapping?.episodes?.nodes ?: return null).mapNotNull { ep ->
|
||||||
val num = ep?.number?.toString() ?: return@mapNotNull null
|
val num = ep?.number?.toString() ?: return@mapNotNull null
|
||||||
|
@ -81,7 +80,7 @@ query {
|
||||||
thumb = FileUrl[ep.thumbnail?.original?.url],
|
thumb = FileUrl[ep.thumbnail?.original?.url],
|
||||||
)
|
)
|
||||||
}.toMap()
|
}.toMap()
|
||||||
logger("Kitsu : a=$a", print)
|
//Logger.log("Kitsu : a=$a")
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import android.os.Environment
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import ani.dantotsu.FileUrl
|
import ani.dantotsu.FileUrl
|
||||||
import ani.dantotsu.currContext
|
import ani.dantotsu.currContext
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.media.anime.AnimeNameAdapter
|
import ani.dantotsu.media.anime.AnimeNameAdapter
|
||||||
import ani.dantotsu.media.manga.ImageData
|
import ani.dantotsu.media.manga.ImageData
|
||||||
import ani.dantotsu.media.manga.MangaCache
|
import ani.dantotsu.media.manga.MangaCache
|
||||||
|
@ -129,7 +129,7 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
|
||||||
val configurableSource = extension.sources[sourceLanguage] as? ConfigurableAnimeSource
|
val configurableSource = extension.sources[sourceLanguage] as? ConfigurableAnimeSource
|
||||||
?: return false
|
?: return false
|
||||||
currContext()?.let { context ->
|
currContext()?.let { context ->
|
||||||
logger("isDubAvailableSeparately: ${configurableSource.getPreferenceKey()}")
|
Logger.log("isDubAvailableSeparately: ${configurableSource.getPreferenceKey()}")
|
||||||
val sharedPreferences =
|
val sharedPreferences =
|
||||||
context.getSharedPreferences(
|
context.getSharedPreferences(
|
||||||
configurableSource.getPreferenceKey(),
|
configurableSource.getPreferenceKey(),
|
||||||
|
@ -205,7 +205,7 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
|
||||||
}
|
}
|
||||||
return sortedEpisodes.map { SEpisodeToEpisode(it) }
|
return sortedEpisodes.map { SEpisodeToEpisode(it) }
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("Exception: $e")
|
Logger.log("Exception: $e")
|
||||||
}
|
}
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
|
||||||
val videos = source.getVideoList(sEpisode)
|
val videos = source.getVideoList(sEpisode)
|
||||||
videos.map { VideoToVideoServer(it) }
|
videos.map { VideoToVideoServer(it) }
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("Exception occurred: ${e.message}")
|
Logger.log("Exception occurred: ${e.message}")
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,16 +260,16 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
|
||||||
?: return emptyList())
|
?: return emptyList())
|
||||||
return try {
|
return try {
|
||||||
val res = source.fetchSearchAnime(1, query, source.getFilterList()).awaitSingle()
|
val res = source.fetchSearchAnime(1, query, source.getFilterList()).awaitSingle()
|
||||||
logger("query: $query")
|
Logger.log("query: $query")
|
||||||
convertAnimesPageToShowResponse(res)
|
convertAnimesPageToShowResponse(res)
|
||||||
} catch (e: CloudflareBypassException) {
|
} catch (e: CloudflareBypassException) {
|
||||||
logger("Exception in search: $e")
|
Logger.log("Exception in search: $e")
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
snackString("Failed to bypass Cloudflare")
|
snackString("Failed to bypass Cloudflare")
|
||||||
}
|
}
|
||||||
emptyList()
|
emptyList()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("General exception in search: $e")
|
Logger.log("General exception in search: $e")
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,12 +358,12 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
|
||||||
val res = source.getChapterList(sManga)
|
val res = source.getChapterList(sManga)
|
||||||
val reversedRes = res.reversed()
|
val reversedRes = res.reversed()
|
||||||
val chapterList = reversedRes.map { SChapterToMangaChapter(it) }
|
val chapterList = reversedRes.map { SChapterToMangaChapter(it) }
|
||||||
logger("chapterList size: ${chapterList.size}")
|
Logger.log("chapterList size: ${chapterList.size}")
|
||||||
logger("chapterList: ${chapterList[1].title}")
|
Logger.log("chapterList: ${chapterList[1].title}")
|
||||||
logger("chapterList: ${chapterList[1].description}")
|
Logger.log("chapterList: ${chapterList[1].description}")
|
||||||
chapterList
|
chapterList
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("loadChapters Exception: $e")
|
Logger.log("loadChapters Exception: $e")
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -379,7 +379,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
|
||||||
var imageDataList: List<ImageData> = listOf()
|
var imageDataList: List<ImageData> = listOf()
|
||||||
val ret = coroutineScope {
|
val ret = coroutineScope {
|
||||||
try {
|
try {
|
||||||
logger("source.name " + source.name)
|
Logger.log("source.name " + source.name)
|
||||||
val res = source.getPageList(sChapter)
|
val res = source.getPageList(sChapter)
|
||||||
val reIndexedPages =
|
val reIndexedPages =
|
||||||
res.mapIndexed { index, page -> Page(index, page.url, page.imageUrl, page.uri) }
|
res.mapIndexed { index, page -> Page(index, page.url, page.imageUrl, page.uri) }
|
||||||
|
@ -388,7 +388,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
|
||||||
async(Dispatchers.IO) {
|
async(Dispatchers.IO) {
|
||||||
mangaCache.put(page.imageUrl ?: "", ImageData(page, source))
|
mangaCache.put(page.imageUrl ?: "", ImageData(page, source))
|
||||||
imageDataList += ImageData(page, source)
|
imageDataList += ImageData(page, source)
|
||||||
logger("put page: ${page.imageUrl}")
|
Logger.log("put page: ${page.imageUrl}")
|
||||||
pageToMangaImage(page)
|
pageToMangaImage(page)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -396,7 +396,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
|
||||||
deferreds.awaitAll()
|
deferreds.awaitAll()
|
||||||
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("loadImages Exception: $e")
|
Logger.log("loadImages Exception: $e")
|
||||||
snackString("Failed to load images: $e")
|
snackString("Failed to load images: $e")
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
|
@ -414,7 +414,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
|
||||||
|
|
||||||
return coroutineScope {
|
return coroutineScope {
|
||||||
try {
|
try {
|
||||||
logger("source.name " + source.name)
|
Logger.log("source.name " + source.name)
|
||||||
val res = source.getPageList(sChapter)
|
val res = source.getPageList(sChapter)
|
||||||
val reIndexedPages =
|
val reIndexedPages =
|
||||||
res.mapIndexed { index, page -> Page(index, page.url, page.imageUrl, page.uri) }
|
res.mapIndexed { index, page -> Page(index, page.url, page.imageUrl, page.uri) }
|
||||||
|
@ -430,7 +430,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
|
||||||
|
|
||||||
deferreds.awaitAll()
|
deferreds.awaitAll()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("loadImages Exception: $e")
|
Logger.log("loadImages Exception: $e")
|
||||||
snackString("Failed to load images: $e")
|
snackString("Failed to load images: $e")
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
|
@ -446,8 +446,8 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
|
||||||
try {
|
try {
|
||||||
// Fetch the image
|
// Fetch the image
|
||||||
val response = httpSource.getImage(page)
|
val response = httpSource.getImage(page)
|
||||||
logger("Response: ${response.code}")
|
Logger.log("Response: ${response.code}")
|
||||||
logger("Response: ${response.message}")
|
Logger.log("Response: ${response.message}")
|
||||||
|
|
||||||
// Convert the Response to an InputStream
|
// Convert the Response to an InputStream
|
||||||
val inputStream = response.body.byteStream()
|
val inputStream = response.body.byteStream()
|
||||||
|
@ -467,7 +467,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
|
||||||
return@withContext bitmap
|
return@withContext bitmap
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// Handle any exceptions
|
// Handle any exceptions
|
||||||
logger("An error occurred: ${e.message}")
|
Logger.log("An error occurred: ${e.message}")
|
||||||
return@withContext null
|
return@withContext null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -500,7 +500,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
|
||||||
inputStream.close()
|
inputStream.close()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// Handle any exceptions
|
// Handle any exceptions
|
||||||
logger("An error occurred: ${e.message}")
|
Logger.log("An error occurred: ${e.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -547,7 +547,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// Handle exception here
|
// Handle exception here
|
||||||
logger("Exception while saving image: ${e.message}")
|
Logger.log("Exception while saving image: ${e.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,16 +562,16 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
val res = source.fetchSearchManga(1, query, source.getFilterList()).awaitSingle()
|
val res = source.fetchSearchManga(1, query, source.getFilterList()).awaitSingle()
|
||||||
logger("res observable: $res")
|
Logger.log("res observable: $res")
|
||||||
convertMangasPageToShowResponse(res)
|
convertMangasPageToShowResponse(res)
|
||||||
} catch (e: CloudflareBypassException) {
|
} catch (e: CloudflareBypassException) {
|
||||||
logger("Exception in search: $e")
|
Logger.log("Exception in search: $e")
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
snackString("Failed to bypass Cloudflare")
|
snackString("Failed to bypass Cloudflare")
|
||||||
}
|
}
|
||||||
emptyList()
|
emptyList()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("General exception in search: $e")
|
Logger.log("General exception in search: $e")
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -714,7 +714,7 @@ class VideoServerPassthrough(val videoServer: VideoServer) : VideoExtractor() {
|
||||||
|
|
||||||
// If the format is still undetermined, log an error
|
// If the format is still undetermined, log an error
|
||||||
if (format == null) {
|
if (format == null) {
|
||||||
logger("Unknown video format: $videoUrl")
|
Logger.log("Unknown video format: $videoUrl")
|
||||||
format = VideoType.CONTAINER
|
format = VideoType.CONTAINER
|
||||||
}
|
}
|
||||||
val headersMap: Map<String, String> =
|
val headersMap: Map<String, String> =
|
||||||
|
@ -746,7 +746,7 @@ class VideoServerPassthrough(val videoServer: VideoServer) : VideoExtractor() {
|
||||||
|
|
||||||
private fun headRequest(fileName: String, networkHelper: NetworkHelper): VideoType? {
|
private fun headRequest(fileName: String, networkHelper: NetworkHelper): VideoType? {
|
||||||
return try {
|
return try {
|
||||||
logger("attempting head request for $fileName")
|
Logger.log("attempting head request for $fileName")
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
.url(fileName)
|
.url(fileName)
|
||||||
.head()
|
.head()
|
||||||
|
@ -771,13 +771,13 @@ class VideoServerPassthrough(val videoServer: VideoServer) : VideoExtractor() {
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger("failed head request for $fileName")
|
Logger.log("failed head request for $fileName")
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("Exception in headRequest: $e")
|
Logger.log("Exception in headRequest: $e")
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ package ani.dantotsu.parsers
|
||||||
import ani.dantotsu.FileUrl
|
import ani.dantotsu.FileUrl
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.currContext
|
import ani.dantotsu.currContext
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||||
|
@ -59,11 +59,11 @@ abstract class BaseParser {
|
||||||
saveShowResponse(mediaObj.id, response, true)
|
saveShowResponse(mediaObj.id, response, true)
|
||||||
} else {
|
} else {
|
||||||
setUserText("Searching : ${mediaObj.mainName()}")
|
setUserText("Searching : ${mediaObj.mainName()}")
|
||||||
logger("Searching : ${mediaObj.mainName()}")
|
Logger.log("Searching : ${mediaObj.mainName()}")
|
||||||
val results = search(mediaObj.mainName())
|
val results = search(mediaObj.mainName())
|
||||||
//log all results
|
//log all results
|
||||||
results.forEach {
|
results.forEach {
|
||||||
logger("Result: ${it.name}")
|
Logger.log("Result: ${it.name}")
|
||||||
}
|
}
|
||||||
val sortedResults = if (results.isNotEmpty()) {
|
val sortedResults = if (results.isNotEmpty()) {
|
||||||
results.sortedByDescending {
|
results.sortedByDescending {
|
||||||
|
@ -83,7 +83,7 @@ abstract class BaseParser {
|
||||||
) < 100
|
) < 100
|
||||||
) {
|
) {
|
||||||
setUserText("Searching : ${mediaObj.nameRomaji}")
|
setUserText("Searching : ${mediaObj.nameRomaji}")
|
||||||
logger("Searching : ${mediaObj.nameRomaji}")
|
Logger.log("Searching : ${mediaObj.nameRomaji}")
|
||||||
val romajiResults = search(mediaObj.nameRomaji)
|
val romajiResults = search(mediaObj.nameRomaji)
|
||||||
val sortedRomajiResults = if (romajiResults.isNotEmpty()) {
|
val sortedRomajiResults = if (romajiResults.isNotEmpty()) {
|
||||||
romajiResults.sortedByDescending {
|
romajiResults.sortedByDescending {
|
||||||
|
@ -96,10 +96,10 @@ abstract class BaseParser {
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
val closestRomaji = sortedRomajiResults.firstOrNull()
|
val closestRomaji = sortedRomajiResults.firstOrNull()
|
||||||
logger("Closest match from RomajiResults: ${closestRomaji?.name ?: "None"}")
|
Logger.log("Closest match from RomajiResults: ${closestRomaji?.name ?: "None"}")
|
||||||
|
|
||||||
response = if (response == null) {
|
response = if (response == null) {
|
||||||
logger("No exact match found in results. Using closest match from RomajiResults.")
|
Logger.log("No exact match found in results. Using closest match from RomajiResults.")
|
||||||
closestRomaji
|
closestRomaji
|
||||||
} else {
|
} else {
|
||||||
val romajiRatio = FuzzySearch.ratio(
|
val romajiRatio = FuzzySearch.ratio(
|
||||||
|
@ -110,14 +110,14 @@ abstract class BaseParser {
|
||||||
response.name.lowercase(),
|
response.name.lowercase(),
|
||||||
mediaObj.mainName().lowercase()
|
mediaObj.mainName().lowercase()
|
||||||
)
|
)
|
||||||
logger("Fuzzy ratio for closest match in results: $mainNameRatio for ${response.name.lowercase()}")
|
Logger.log("Fuzzy ratio for closest match in results: $mainNameRatio for ${response.name.lowercase()}")
|
||||||
logger("Fuzzy ratio for closest match in RomajiResults: $romajiRatio for ${closestRomaji?.name?.lowercase() ?: "None"}")
|
Logger.log("Fuzzy ratio for closest match in RomajiResults: $romajiRatio for ${closestRomaji?.name?.lowercase() ?: "None"}")
|
||||||
|
|
||||||
if (romajiRatio > mainNameRatio) {
|
if (romajiRatio > mainNameRatio) {
|
||||||
logger("RomajiResults has a closer match. Replacing response.")
|
Logger.log("RomajiResults has a closer match. Replacing response.")
|
||||||
closestRomaji
|
closestRomaji
|
||||||
} else {
|
} else {
|
||||||
logger("Results has a closer or equal match. Keeping existing response.")
|
Logger.log("Results has a closer or equal match. Keeping existing response.")
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package ani.dantotsu.parsers
|
package ani.dantotsu.parsers
|
||||||
|
|
||||||
import ani.dantotsu.Lazier
|
import ani.dantotsu.Lazier
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.media.anime.Episode
|
import ani.dantotsu.media.anime.Episode
|
||||||
import ani.dantotsu.media.manga.MangaChapter
|
import ani.dantotsu.media.manga.MangaChapter
|
||||||
|
@ -96,7 +96,7 @@ abstract class MangaReadSources : BaseSources() {
|
||||||
}
|
}
|
||||||
//must be downloaded
|
//must be downloaded
|
||||||
if (show.sManga == null) {
|
if (show.sManga == null) {
|
||||||
logger("sManga is null")
|
Logger.log("sManga is null")
|
||||||
}
|
}
|
||||||
if (parser is OfflineMangaParser && show.sManga == null) {
|
if (parser is OfflineMangaParser && show.sManga == null) {
|
||||||
tryWithSuspend(true) {
|
tryWithSuspend(true) {
|
||||||
|
@ -106,11 +106,11 @@ abstract class MangaReadSources : BaseSources() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger("Parser is not an instance of OfflineMangaParser")
|
Logger.log("Parser is not an instance of OfflineMangaParser")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
logger("map size ${map.size}")
|
Logger.log("map size ${map.size}")
|
||||||
return map
|
return map
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import ani.dantotsu.parsers.novel.DynamicNovelParser
|
||||||
import ani.dantotsu.parsers.novel.NovelExtension
|
import ani.dantotsu.parsers.novel.NovelExtension
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
|
|
||||||
|
@ -47,8 +48,8 @@ object NovelSources : NovelReadSources() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createParsersFromExtensions(extensions: List<NovelExtension.Installed>): List<Lazier<BaseParser>> {
|
private fun createParsersFromExtensions(extensions: List<NovelExtension.Installed>): List<Lazier<BaseParser>> {
|
||||||
Log.d("NovelSources", "createParsersFromExtensions")
|
Logger.log("createParsersFromExtensions")
|
||||||
Log.d("NovelSources", extensions.toString())
|
Logger.log(extensions.toString())
|
||||||
return extensions.map { extension ->
|
return extensions.map { extension ->
|
||||||
val name = extension.name
|
val name = extension.name
|
||||||
Lazier({ DynamicNovelParser(extension) }, name)
|
Lazier({ DynamicNovelParser(extension) }, name)
|
||||||
|
|
|
@ -3,7 +3,7 @@ package ani.dantotsu.parsers
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import ani.dantotsu.currContext
|
import ani.dantotsu.currContext
|
||||||
import ani.dantotsu.download.DownloadsManager
|
import ani.dantotsu.download.DownloadsManager
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.media.manga.MangaNameAdapter
|
import ani.dantotsu.media.manga.MangaNameAdapter
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
@ -68,7 +68,7 @@ class OfflineMangaParser : MangaParser() {
|
||||||
matchResult?.groups?.get(1)?.value?.toIntOrNull() ?: Int.MAX_VALUE
|
matchResult?.groups?.get(1)?.value?.toIntOrNull() ?: Int.MAX_VALUE
|
||||||
}
|
}
|
||||||
for (image in images) {
|
for (image in images) {
|
||||||
logger("imageNumber: ${image.url.url}")
|
Logger.log("imageNumber: ${image.url.url}")
|
||||||
}
|
}
|
||||||
return images
|
return images
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package ani.dantotsu.parsers
|
package ani.dantotsu.parsers
|
||||||
|
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
|
|
||||||
class StringMatcher {
|
class StringMatcher {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -54,10 +54,10 @@ class StringMatcher {
|
||||||
val closestShowAndIndex = closestShow(target, shows)
|
val closestShowAndIndex = closestShow(target, shows)
|
||||||
val closestIndex = closestShowAndIndex.second
|
val closestIndex = closestShowAndIndex.second
|
||||||
if (closestIndex == -1) {
|
if (closestIndex == -1) {
|
||||||
logger("No closest show found for $target")
|
Logger.log("No closest show found for $target")
|
||||||
return shows // Return original list if no closest show found
|
return shows // Return original list if no closest show found
|
||||||
}
|
}
|
||||||
logger("Closest show found for $target is ${closestShowAndIndex.first.name}")
|
Logger.log("Closest show found for $target is ${closestShowAndIndex.first.name}")
|
||||||
return listOf(shows[closestIndex]) + shows.subList(0, closestIndex) + shows.subList(
|
return listOf(shows[closestIndex]) + shows.subList(0, closestIndex) + shows.subList(
|
||||||
closestIndex + 1,
|
closestIndex + 1,
|
||||||
shows.size
|
shows.size
|
||||||
|
|
|
@ -2,7 +2,7 @@ package ani.dantotsu.parsers.novel
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateNotifier
|
import eu.kanade.tachiyomi.extension.ExtensionUpdateNotifier
|
||||||
|
@ -14,9 +14,7 @@ import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
import eu.kanade.tachiyomi.network.parseAs
|
import eu.kanade.tachiyomi.network.parseAs
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import logcat.LogPriority
|
|
||||||
import tachiyomi.core.util.lang.withIOContext
|
import tachiyomi.core.util.lang.withIOContext
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import kotlin.time.Duration.Companion.days
|
import kotlin.time.Duration.Companion.days
|
||||||
|
@ -41,20 +39,20 @@ class NovelExtensionGithubApi {
|
||||||
.newCall(GET("${REPO_URL_PREFIX}index.min.json"))
|
.newCall(GET("${REPO_URL_PREFIX}index.min.json"))
|
||||||
.awaitSuccess()
|
.awaitSuccess()
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
logcat(LogPriority.ERROR, e) { "Failed to get extensions from GitHub" }
|
Logger.log("Failed to get extensions from GitHub")
|
||||||
requiresFallbackSource = true
|
requiresFallbackSource = true
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val response = githubResponse ?: run {
|
val response = githubResponse ?: run {
|
||||||
logger("using fallback source")
|
Logger.log("using fallback source")
|
||||||
networkService.client
|
networkService.client
|
||||||
.newCall(GET("${FALLBACK_REPO_URL_PREFIX}index.min.json"))
|
.newCall(GET("${FALLBACK_REPO_URL_PREFIX}index.min.json"))
|
||||||
.awaitSuccess()
|
.awaitSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
logger("response: $response")
|
Logger.log("response: $response")
|
||||||
|
|
||||||
val extensions = with(json) {
|
val extensions = with(json) {
|
||||||
response
|
response
|
||||||
|
@ -67,7 +65,7 @@ class NovelExtensionGithubApi {
|
||||||
/*if (extensions.size < 10) { //TODO: uncomment when more extensions are added
|
/*if (extensions.size < 10) { //TODO: uncomment when more extensions are added
|
||||||
throw Exception()
|
throw Exception()
|
||||||
}*/
|
}*/
|
||||||
logger("extensions: $extensions")
|
Logger.log("extensions: $extensions")
|
||||||
extensions
|
extensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package ani.dantotsu.parsers.novel
|
||||||
import android.os.FileObserver
|
import android.os.FileObserver
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import ani.dantotsu.parsers.novel.FileObserver.fileObserver
|
import ani.dantotsu.parsers.novel.FileObserver.fileObserver
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,24 +23,24 @@ class NovelExtensionFileObserver(private val listener: Listener, private val pat
|
||||||
|
|
||||||
|
|
||||||
override fun onEvent(event: Int, file: String?) {
|
override fun onEvent(event: Int, file: String?) {
|
||||||
Log.e("NovelExtensionFileObserver", "Event: $event")
|
Logger.log("Event: $event")
|
||||||
if (file == null) return
|
if (file == null) return
|
||||||
|
|
||||||
val fullPath = File(path, file)
|
val fullPath = File(path, file)
|
||||||
|
|
||||||
when (event) {
|
when (event) {
|
||||||
CREATE -> {
|
CREATE -> {
|
||||||
Log.e("NovelExtensionFileObserver", "File created: $fullPath")
|
Logger.log("File created: $fullPath")
|
||||||
listener.onExtensionFileCreated(fullPath)
|
listener.onExtensionFileCreated(fullPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
DELETE -> {
|
DELETE -> {
|
||||||
Log.e("NovelExtensionFileObserver", "File deleted: $fullPath")
|
Logger.log("File deleted: $fullPath")
|
||||||
listener.onExtensionFileDeleted(fullPath)
|
listener.onExtensionFileDeleted(fullPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
MODIFY -> {
|
MODIFY -> {
|
||||||
Log.e("NovelExtensionFileObserver", "File modified: $fullPath")
|
Logger.log("File modified: $fullPath")
|
||||||
listener.onExtensionFileModified(fullPath)
|
listener.onExtensionFileModified(fullPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,12 @@ import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import com.jakewharton.rxrelay.PublishRelay
|
import com.jakewharton.rxrelay.PublishRelay
|
||||||
import eu.kanade.tachiyomi.extension.InstallStep
|
import eu.kanade.tachiyomi.extension.InstallStep
|
||||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||||
import logcat.LogPriority
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
|
@ -77,12 +76,12 @@ internal class NovelExtensionInstaller(private val context: Context) {
|
||||||
val fileToDelete = File("$sourcePath/${url.toUri().lastPathSegment}")
|
val fileToDelete = File("$sourcePath/${url.toUri().lastPathSegment}")
|
||||||
if (fileToDelete.exists()) {
|
if (fileToDelete.exists()) {
|
||||||
if (fileToDelete.delete()) {
|
if (fileToDelete.delete()) {
|
||||||
Log.i("Install APK", "APK file deleted successfully.")
|
Logger.log("APK file deleted successfully.")
|
||||||
} else {
|
} else {
|
||||||
Log.e("Install APK", "Failed to delete APK file.")
|
Logger.log("Failed to delete APK file.")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.e("Install APK", "APK file not found.")
|
Logger.log("APK file not found.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the receiver after removing (and unregistering) the previous download
|
// Register the receiver after removing (and unregistering) the previous download
|
||||||
|
@ -161,7 +160,7 @@ internal class NovelExtensionInstaller(private val context: Context) {
|
||||||
|
|
||||||
// Check if source path is obtained correctly
|
// Check if source path is obtained correctly
|
||||||
if (sourcePath == null) {
|
if (sourcePath == null) {
|
||||||
Log.e("Install APK", "Source APK path not found.")
|
Logger.log("Source APK path not found.")
|
||||||
downloadsRelay.call(downloadId to InstallStep.Error)
|
downloadsRelay.call(downloadId to InstallStep.Error)
|
||||||
return InstallStep.Error
|
return InstallStep.Error
|
||||||
}
|
}
|
||||||
|
@ -172,14 +171,14 @@ internal class NovelExtensionInstaller(private val context: Context) {
|
||||||
destinationDir.mkdirs()
|
destinationDir.mkdirs()
|
||||||
}
|
}
|
||||||
if (destinationDir?.setWritable(true) == false) {
|
if (destinationDir?.setWritable(true) == false) {
|
||||||
Log.e("Install APK", "Failed to set destinationDir to writable.")
|
Logger.log("Failed to set destinationDir to writable.")
|
||||||
downloadsRelay.call(downloadId to InstallStep.Error)
|
downloadsRelay.call(downloadId to InstallStep.Error)
|
||||||
return InstallStep.Error
|
return InstallStep.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the file to the new location
|
// Copy the file to the new location
|
||||||
copyFileToInternalStorage(sourcePath, destinationPath)
|
copyFileToInternalStorage(sourcePath, destinationPath)
|
||||||
Log.i("Install APK", "APK moved to $destinationPath")
|
Logger.log("APK moved to $destinationPath")
|
||||||
downloadsRelay.call(downloadId to InstallStep.Installed)
|
downloadsRelay.call(downloadId to InstallStep.Installed)
|
||||||
return InstallStep.Installed
|
return InstallStep.Installed
|
||||||
}
|
}
|
||||||
|
@ -198,9 +197,9 @@ internal class NovelExtensionInstaller(private val context: Context) {
|
||||||
val fileToDelete = File(apkPath)
|
val fileToDelete = File(apkPath)
|
||||||
//give write permission to the file
|
//give write permission to the file
|
||||||
if (fileToDelete.exists() && !fileToDelete.canWrite()) {
|
if (fileToDelete.exists() && !fileToDelete.canWrite()) {
|
||||||
Log.i("Uninstall APK", "File is not writable. Giving write permission.")
|
Logger.log("File is not writable. Giving write permission.")
|
||||||
val a = fileToDelete.setWritable(true)
|
val a = fileToDelete.setWritable(true)
|
||||||
Log.i("Uninstall APK", "Success: $a")
|
Logger.log("Success: $a")
|
||||||
}
|
}
|
||||||
//set the directory to writable
|
//set the directory to writable
|
||||||
val destinationDir = File(apkPath).parentFile
|
val destinationDir = File(apkPath).parentFile
|
||||||
|
@ -208,27 +207,27 @@ internal class NovelExtensionInstaller(private val context: Context) {
|
||||||
destinationDir.mkdirs()
|
destinationDir.mkdirs()
|
||||||
}
|
}
|
||||||
val s = destinationDir?.setWritable(true)
|
val s = destinationDir?.setWritable(true)
|
||||||
Log.i("Uninstall APK", "Success destinationDir: $s")
|
Logger.log("Success destinationDir: $s")
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
try {
|
try {
|
||||||
Files.delete(fileToDelete.toPath())
|
Files.delete(fileToDelete.toPath())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("Uninstall APK", "Failed to delete APK file.")
|
Logger.log("Failed to delete APK file.")
|
||||||
Log.e("Uninstall APK", e.toString())
|
Logger.log(e)
|
||||||
snackString("Failed to delete APK file.")
|
snackString("Failed to delete APK file.")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (fileToDelete.exists()) {
|
if (fileToDelete.exists()) {
|
||||||
if (fileToDelete.delete()) {
|
if (fileToDelete.delete()) {
|
||||||
Log.i("Uninstall APK", "APK file deleted successfully.")
|
Logger.log("APK file deleted successfully.")
|
||||||
snackString("APK file deleted successfully.")
|
snackString("APK file deleted successfully.")
|
||||||
} else {
|
} else {
|
||||||
Log.e("Uninstall APK", "Failed to delete APK file.")
|
Logger.log("Failed to delete APK file.")
|
||||||
snackString("Failed to delete APK file.")
|
snackString("Failed to delete APK file.")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.e("Uninstall APK", "APK file not found.")
|
Logger.log("APK file not found.")
|
||||||
snackString("APK file not found.")
|
snackString("APK file not found.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -242,9 +241,9 @@ internal class NovelExtensionInstaller(private val context: Context) {
|
||||||
//delete the file if it already exists
|
//delete the file if it already exists
|
||||||
if (destination.exists()) {
|
if (destination.exists()) {
|
||||||
if (destination.delete()) {
|
if (destination.delete()) {
|
||||||
Log.i("File Copy", "File deleted successfully.")
|
Logger.log("File deleted successfully.")
|
||||||
} else {
|
} else {
|
||||||
Log.e("File Copy", "Failed to delete file.")
|
Logger.log("Failed to delete file.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +261,7 @@ internal class NovelExtensionInstaller(private val context: Context) {
|
||||||
outputChannel?.close()
|
outputChannel?.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i("File Copy", "File copied to internal storage.")
|
Logger.log("File copied to internal storage.")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getRealPathFromURI(context: Context, contentUri: Uri): String? {
|
private fun getRealPathFromURI(context: Context, contentUri: Uri): String? {
|
||||||
|
@ -350,7 +349,7 @@ internal class NovelExtensionInstaller(private val context: Context) {
|
||||||
|
|
||||||
// Set next installation step
|
// Set next installation step
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
logcat(LogPriority.ERROR) { "Couldn't locate downloaded APK" }
|
Logger.log("Couldn't locate downloaded APK")
|
||||||
downloadsRelay.call(id to InstallStep.Error)
|
downloadsRelay.call(id to InstallStep.Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -371,7 +370,7 @@ internal class NovelExtensionInstaller(private val context: Context) {
|
||||||
val uri = Uri.parse(localUri)
|
val uri = Uri.parse(localUri)
|
||||||
val path = uri.path
|
val path = uri.path
|
||||||
val pkgName = path?.substring(path.lastIndexOf('/') + 1)?.removeSuffix(".apk")
|
val pkgName = path?.substring(path.lastIndexOf('/') + 1)?.removeSuffix(".apk")
|
||||||
Log.i("Install APK", "Package name: $pkgName")
|
Logger.log("Package name: $pkgName")
|
||||||
return pkgName ?: ""
|
return pkgName ?: ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.parsers.NovelInterface
|
import ani.dantotsu.parsers.NovelInterface
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
import dalvik.system.PathClassLoader
|
import dalvik.system.PathClassLoader
|
||||||
|
@ -26,21 +26,20 @@ internal object NovelExtensionLoader {
|
||||||
val installDir = context.getExternalFilesDir(null)?.absolutePath + "/extensions/novel/"
|
val installDir = context.getExternalFilesDir(null)?.absolutePath + "/extensions/novel/"
|
||||||
val results = mutableListOf<NovelLoadResult>()
|
val results = mutableListOf<NovelLoadResult>()
|
||||||
//the number of files
|
//the number of files
|
||||||
Log.e("NovelExtensionLoader", "Loading extensions from $installDir")
|
Logger.log("Loading extensions from $installDir")
|
||||||
Log.e(
|
Logger.log(
|
||||||
"NovelExtensionLoader",
|
|
||||||
"Loading extensions from ${File(installDir).listFiles()?.size}"
|
"Loading extensions from ${File(installDir).listFiles()?.size}"
|
||||||
)
|
)
|
||||||
File(installDir).setWritable(false)
|
File(installDir).setWritable(false)
|
||||||
File(installDir).listFiles()?.forEach {
|
File(installDir).listFiles()?.forEach {
|
||||||
//set the file to read only
|
//set the file to read only
|
||||||
it.setWritable(false)
|
it.setWritable(false)
|
||||||
Log.e("NovelExtensionLoader", "Loading extension ${it.name}")
|
Logger.log("Loading extension ${it.name}")
|
||||||
val extension = loadExtension(context, it)
|
val extension = loadExtension(context, it)
|
||||||
if (extension is NovelLoadResult.Success) {
|
if (extension is NovelLoadResult.Success) {
|
||||||
results.add(extension)
|
results.add(extension)
|
||||||
} else {
|
} else {
|
||||||
logger("Failed to load extension ${it.name}")
|
Logger.log("Failed to load extension ${it.name}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return results
|
return results
|
||||||
|
@ -62,7 +61,7 @@ internal object NovelExtensionLoader {
|
||||||
context.packageManager.getPackageArchiveInfo(path, 0)
|
context.packageManager.getPackageArchiveInfo(path, 0)
|
||||||
} catch (error: Exception) {
|
} catch (error: Exception) {
|
||||||
// Unlikely, but the package may have been uninstalled at this point
|
// Unlikely, but the package may have been uninstalled at this point
|
||||||
logger("Failed to load extension $pkgName")
|
Logger.log("Failed to load extension $pkgName")
|
||||||
return NovelLoadResult.Error(Exception("Failed to load extension"))
|
return NovelLoadResult.Error(Exception("Failed to load extension"))
|
||||||
}
|
}
|
||||||
return loadExtension(context, File(path))
|
return loadExtension(context, File(path))
|
||||||
|
@ -88,8 +87,8 @@ internal object NovelExtensionLoader {
|
||||||
val signatureHash = getSignatureHash(packageInfo)
|
val signatureHash = getSignatureHash(packageInfo)
|
||||||
|
|
||||||
if ((signatureHash == null) || !signatureHash.contains(officialSignature)) {
|
if ((signatureHash == null) || !signatureHash.contains(officialSignature)) {
|
||||||
logger("Package ${packageInfo.packageName} isn't signed")
|
Logger.log("Package ${packageInfo.packageName} isn't signed")
|
||||||
logger("signatureHash: $signatureHash")
|
Logger.log("signatureHash: $signatureHash")
|
||||||
snackString("Package ${packageInfo.packageName} isn't signed")
|
snackString("Package ${packageInfo.packageName} isn't signed")
|
||||||
//return NovelLoadResult.Error(Exception("Extension not signed"))
|
//return NovelLoadResult.Error(Exception("Extension not signed"))
|
||||||
}
|
}
|
||||||
|
@ -128,12 +127,12 @@ internal object NovelExtensionLoader {
|
||||||
|
|
||||||
private fun loadSources(context: Context, file: File, className: String): List<NovelInterface> {
|
private fun loadSources(context: Context, file: File, className: String): List<NovelInterface> {
|
||||||
return try {
|
return try {
|
||||||
Log.e("NovelExtensionLoader", "isFileWritable: ${file.canWrite()}")
|
Logger.log("isFileWritable: ${file.canWrite()}")
|
||||||
if (file.canWrite()) {
|
if (file.canWrite()) {
|
||||||
val a = file.setWritable(false)
|
val a = file.setWritable(false)
|
||||||
Log.e("NovelExtensionLoader", "success: $a")
|
Logger.log("success: $a")
|
||||||
}
|
}
|
||||||
Log.e("NovelExtensionLoader", "isFileWritable: ${file.canWrite()}")
|
Logger.log("isFileWritable: ${file.canWrite()}")
|
||||||
val classLoader = PathClassLoader(file.absolutePath, null, context.classLoader)
|
val classLoader = PathClassLoader(file.absolutePath, null, context.classLoader)
|
||||||
val className =
|
val className =
|
||||||
"some.random.novelextensions.${className.lowercase(Locale.getDefault())}.$className"
|
"some.random.novelextensions.${className.lowercase(Locale.getDefault())}.$className"
|
||||||
|
|
|
@ -2,7 +2,7 @@ package ani.dantotsu.parsers.novel
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
import eu.kanade.tachiyomi.extension.InstallStep
|
import eu.kanade.tachiyomi.extension.InstallStep
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
@ -70,7 +70,7 @@ class NovelExtensionManager(private val context: Context) {
|
||||||
val extensions: List<NovelExtension.Available> = try {
|
val extensions: List<NovelExtension.Available> = try {
|
||||||
api.findExtensions()
|
api.findExtensions()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger("Error finding extensions: ${e.message}")
|
Logger.log("Error finding extensions: ${e.message}")
|
||||||
withUIContext { snackString("Failed to get Novel extensions list") }
|
withUIContext { snackString("Failed to get Novel extensions list") }
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import ani.dantotsu.connections.anilist.Anilist
|
||||||
import ani.dantotsu.connections.anilist.AnilistQueries
|
import ani.dantotsu.connections.anilist.AnilistQueries
|
||||||
import ani.dantotsu.connections.anilist.api.Activity
|
import ani.dantotsu.connections.anilist.api.Activity
|
||||||
import ani.dantotsu.databinding.FragmentFeedBinding
|
import ani.dantotsu.databinding.FragmentFeedBinding
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.profile.ProfileActivity
|
import ani.dantotsu.profile.ProfileActivity
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
import com.xwray.groupie.GroupieAdapter
|
import com.xwray.groupie.GroupieAdapter
|
||||||
|
|
|
@ -25,7 +25,7 @@ import androidx.viewpager2.widget.ViewPager2
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
||||||
import ani.dantotsu.databinding.FragmentAnimeExtensionsBinding
|
import ani.dantotsu.databinding.FragmentAnimeExtensionsBinding
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.others.LanguageMapper
|
import ani.dantotsu.others.LanguageMapper
|
||||||
import ani.dantotsu.parsers.AnimeSources
|
import ani.dantotsu.parsers.AnimeSources
|
||||||
import ani.dantotsu.settings.extensionprefs.AnimeSourcePreferencesFragment
|
import ani.dantotsu.settings.extensionprefs.AnimeSourcePreferencesFragment
|
||||||
|
@ -146,7 +146,7 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
},
|
},
|
||||||
{ error ->
|
{ error ->
|
||||||
Injekt.get<CrashlyticsInterface>().logException(error)
|
Injekt.get<CrashlyticsInterface>().logException(error)
|
||||||
Log.e("AnimeExtensionsAdapter", "Error: ", error) // Log the error
|
Logger.log(error) // Log the error
|
||||||
val builder = NotificationCompat.Builder(
|
val builder = NotificationCompat.Builder(
|
||||||
context,
|
context,
|
||||||
Notifications.CHANNEL_DOWNLOADER_ERROR
|
Notifications.CHANNEL_DOWNLOADER_ERROR
|
||||||
|
|
|
@ -32,6 +32,7 @@ import ani.dantotsu.settings.extensionprefs.MangaSourcePreferencesFragment
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import com.google.android.material.tabs.TabLayout
|
import com.google.android.material.tabs.TabLayout
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
|
@ -143,7 +144,7 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
},
|
},
|
||||||
{ error ->
|
{ error ->
|
||||||
Injekt.get<CrashlyticsInterface>().logException(error)
|
Injekt.get<CrashlyticsInterface>().logException(error)
|
||||||
Log.e("MangaExtensionsAdapter", "Error: ", error) // Log the error
|
Logger.log(error) // Log the error
|
||||||
val builder = NotificationCompat.Builder(
|
val builder = NotificationCompat.Builder(
|
||||||
context,
|
context,
|
||||||
Notifications.CHANNEL_DOWNLOADER_ERROR
|
Notifications.CHANNEL_DOWNLOADER_ERROR
|
||||||
|
|
|
@ -30,6 +30,7 @@ import ani.dantotsu.parsers.novel.NovelExtensionManager
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
|
@ -72,7 +73,7 @@ class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
},
|
},
|
||||||
{ error ->
|
{ error ->
|
||||||
Injekt.get<CrashlyticsInterface>().logException(error)
|
Injekt.get<CrashlyticsInterface>().logException(error)
|
||||||
Log.e("NovelExtensionsAdapter", "Error: ", error) // Log the error
|
Logger.log(error) // Log the error
|
||||||
val builder = NotificationCompat.Builder(
|
val builder = NotificationCompat.Builder(
|
||||||
context,
|
context,
|
||||||
Notifications.CHANNEL_DOWNLOADER_ERROR
|
Notifications.CHANNEL_DOWNLOADER_ERROR
|
||||||
|
@ -216,7 +217,7 @@ class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
val view = LayoutInflater.from(parent.context)
|
val view = LayoutInflater.from(parent.context)
|
||||||
.inflate(R.layout.item_extension, parent, false)
|
.inflate(R.layout.item_extension, parent, false)
|
||||||
Log.d("NovelExtensionsAdapter", "onCreateViewHolder: $view")
|
Logger.log("onCreateViewHolder: $view")
|
||||||
return ViewHolder(view)
|
return ViewHolder(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,6 @@ class NovelExtensionsFragment : Fragment(),
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
viewModel.pagerFlow.collectLatest { pagingData ->
|
viewModel.pagerFlow.collectLatest { pagingData ->
|
||||||
Log.d("NovelExtensionsFragment", "collectLatest")
|
|
||||||
adapter.submitData(pagingData)
|
adapter.submitData(pagingData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ import ani.dantotsu.download.video.ExoplayerDownloadService
|
||||||
import ani.dantotsu.downloadsPermission
|
import ani.dantotsu.downloadsPermission
|
||||||
import ani.dantotsu.initActivity
|
import ani.dantotsu.initActivity
|
||||||
import ani.dantotsu.loadImage
|
import ani.dantotsu.loadImage
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.navBarHeight
|
import ani.dantotsu.navBarHeight
|
||||||
import ani.dantotsu.openLinkInBrowser
|
import ani.dantotsu.openLinkInBrowser
|
||||||
import ani.dantotsu.others.AppUpdater
|
import ani.dantotsu.others.AppUpdater
|
||||||
|
@ -730,6 +730,16 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
|
||||||
binding.settingsShareUsername.isChecked = false
|
binding.settingsShareUsername.isChecked = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.settingsLogToFile.isChecked = PrefManager.getVal(PrefName.LogToFile)
|
||||||
|
binding.settingsLogToFile.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
PrefManager.setVal(PrefName.LogToFile, isChecked)
|
||||||
|
restartApp()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.settingsShareLog.setOnClickListener {
|
||||||
|
Logger.shareLog(this)
|
||||||
|
}
|
||||||
|
|
||||||
binding.settingsAccountHelp.setOnClickListener {
|
binding.settingsAccountHelp.setOnClickListener {
|
||||||
val title = getString(R.string.account_help)
|
val title = getString(R.string.account_help)
|
||||||
val full = getString(R.string.full_account_help)
|
val full = getString(R.string.full_account_help)
|
||||||
|
@ -884,7 +894,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
|
||||||
if (dialogTag == "colorPicker") {
|
if (dialogTag == "colorPicker") {
|
||||||
val color = extras.getInt(SimpleColorDialog.COLOR)
|
val color = extras.getInt(SimpleColorDialog.COLOR)
|
||||||
PrefManager.setVal(PrefName.CustomThemeInt, color)
|
PrefManager.setVal(PrefName.CustomThemeInt, color)
|
||||||
logger("Custom Theme: $color")
|
Logger.log("Custom Theme: $color")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -61,11 +61,7 @@ class AnimeSourcePreferencesFragment : PreferenceFragmentCompat() {
|
||||||
pref.isIconSpaceReserved = false
|
pref.isIconSpaceReserved = false
|
||||||
if (pref is DialogPreference) {
|
if (pref is DialogPreference) {
|
||||||
pref.dialogTitle = pref.title
|
pref.dialogTitle = pref.title
|
||||||
//println("pref.dialogTitle: ${pref.dialogTitle}") //TODO: could be useful for dub/sub selection
|
|
||||||
}
|
}
|
||||||
/*for (entry in sharedPreferences.all.entries) {
|
|
||||||
Log.d("Preferences", "Key: ${entry.key}, Value: ${entry.value}")
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// Apply incognito IME for EditTextPreference
|
// Apply incognito IME for EditTextPreference
|
||||||
if (pref is EditTextPreference) {
|
if (pref is EditTextPreference) {
|
||||||
|
|
|
@ -159,6 +159,7 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
|
||||||
FirstComment(Pref(Location.Irrelevant, Boolean::class, true)),
|
FirstComment(Pref(Location.Irrelevant, Boolean::class, true)),
|
||||||
CommentAuthResponse(Pref(Location.Irrelevant, AuthResponse::class, "")),
|
CommentAuthResponse(Pref(Location.Irrelevant, AuthResponse::class, "")),
|
||||||
CommentTokenExpiry(Pref(Location.Irrelevant, Long::class, 0L)),
|
CommentTokenExpiry(Pref(Location.Irrelevant, Long::class, 0L)),
|
||||||
|
LogToFile(Pref(Location.Irrelevant, Boolean::class, false)),
|
||||||
|
|
||||||
//Protected
|
//Protected
|
||||||
DiscordToken(Pref(Location.Protected, String::class, "")),
|
DiscordToken(Pref(Location.Protected, String::class, "")),
|
||||||
|
|
|
@ -7,7 +7,7 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import ani.dantotsu.currContext
|
import ani.dantotsu.currContext
|
||||||
import ani.dantotsu.isOnline
|
import ani.dantotsu.isOnline
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.subcriptions.Subscription.Companion.defaultTime
|
import ani.dantotsu.subcriptions.Subscription.Companion.defaultTime
|
||||||
|
@ -22,7 +22,7 @@ class AlarmReceiver : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
when (intent?.action) {
|
when (intent?.action) {
|
||||||
Intent.ACTION_BOOT_COMPLETED -> tryWith(true) {
|
Intent.ACTION_BOOT_COMPLETED -> tryWith(true) {
|
||||||
logger("Starting Dantotsu Subscription Service on Boot")
|
Logger.log("Starting Dantotsu Subscription Service on Boot")
|
||||||
context?.startSubscription()
|
context?.startSubscription()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import ani.dantotsu.parsers.Episode
|
||||||
import ani.dantotsu.parsers.MangaChapter
|
import ani.dantotsu.parsers.MangaChapter
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
@ -27,7 +28,7 @@ class Subscription {
|
||||||
alreadyStarted = true
|
alreadyStarted = true
|
||||||
SubscriptionWorker.enqueue(this)
|
SubscriptionWorker.enqueue(this)
|
||||||
AlarmReceiver.alarm(this)
|
AlarmReceiver.alarm(this)
|
||||||
} else logger("Already Subscribed")
|
} else Logger.log("Already Subscribed")
|
||||||
}
|
}
|
||||||
|
|
||||||
private var currentlyPerforming = false
|
private var currentlyPerforming = false
|
||||||
|
|
146
app/src/main/java/ani/dantotsu/util/Logger.kt
Normal file
146
app/src/main/java/ani/dantotsu/util/Logger.kt
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
package ani.dantotsu.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
|
import ani.dantotsu.BuildConfig
|
||||||
|
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
||||||
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
|
import ani.dantotsu.snackString
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.io.File
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
|
object Logger {
|
||||||
|
var file: File? = null
|
||||||
|
private val loggerExecutor = Executors.newSingleThreadExecutor()
|
||||||
|
|
||||||
|
fun init(context: Context) {
|
||||||
|
try {
|
||||||
|
if (!PrefManager.getVal<Boolean>(PrefName.LogToFile) || file != null) return
|
||||||
|
file = File(context.getExternalFilesDir(null), "log.txt")
|
||||||
|
if (file?.exists() == true) {
|
||||||
|
val oldFile = File(context.getExternalFilesDir(null), "old_log.txt")
|
||||||
|
file?.copyTo(oldFile, true)
|
||||||
|
} else {
|
||||||
|
file?.createNewFile()
|
||||||
|
}
|
||||||
|
file?.writeText("log started\n")
|
||||||
|
file?.appendText("date/time: ${Date()}\n")
|
||||||
|
file?.appendText("device: ${android.os.Build.MODEL}\n")
|
||||||
|
file?.appendText("os version: ${android.os.Build.VERSION.RELEASE}\n")
|
||||||
|
file?.appendText(
|
||||||
|
"app version: ${
|
||||||
|
context.packageManager.getPackageInfo(
|
||||||
|
context.packageName,
|
||||||
|
0
|
||||||
|
).versionName
|
||||||
|
}\n"
|
||||||
|
)
|
||||||
|
file?.appendText(
|
||||||
|
"app version code: ${
|
||||||
|
context.packageManager.getPackageInfo(
|
||||||
|
context.packageName,
|
||||||
|
0
|
||||||
|
).versionCode
|
||||||
|
}\n"
|
||||||
|
)
|
||||||
|
file?.appendText("sdk version: ${android.os.Build.VERSION.SDK_INT}\n")
|
||||||
|
file?.appendText("manufacturer: ${android.os.Build.MANUFACTURER}\n")
|
||||||
|
file?.appendText("brand: ${android.os.Build.BRAND}\n")
|
||||||
|
file?.appendText("product: ${android.os.Build.PRODUCT}\n")
|
||||||
|
file?.appendText("device: ${android.os.Build.DEVICE}\n")
|
||||||
|
file?.appendText("hardware: ${android.os.Build.HARDWARE}\n")
|
||||||
|
file?.appendText("host: ${android.os.Build.HOST}\n")
|
||||||
|
file?.appendText("id: ${android.os.Build.ID}\n")
|
||||||
|
file?.appendText("type: ${android.os.Build.TYPE}\n")
|
||||||
|
file?.appendText("user: ${android.os.Build.USER}\n")
|
||||||
|
file?.appendText("tags: ${android.os.Build.TAGS}\n")
|
||||||
|
file?.appendText("time: ${android.os.Build.TIME}\n")
|
||||||
|
file?.appendText("radio: ${android.os.Build.RADIO}\n")
|
||||||
|
file?.appendText("bootloader: ${android.os.Build.BOOTLOADER}\n")
|
||||||
|
file?.appendText("board: ${android.os.Build.BOARD}\n")
|
||||||
|
file?.appendText("fingerprint: ${android.os.Build.FINGERPRINT}\n")
|
||||||
|
file?.appendText("supported_abis: ${android.os.Build.SUPPORTED_ABIS.joinToString()}\n")
|
||||||
|
file?.appendText("supported_32_bit_abis: ${android.os.Build.SUPPORTED_32_BIT_ABIS.joinToString()}\n")
|
||||||
|
file?.appendText("supported_64_bit_abis: ${android.os.Build.SUPPORTED_64_BIT_ABIS.joinToString()}\n")
|
||||||
|
file?.appendText("is emulator: ${android.os.Build.FINGERPRINT.contains("generic")}\n")
|
||||||
|
file?.appendText("--------------------------------\n")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||||
|
file = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun log(message: String) {
|
||||||
|
val trace = Thread.currentThread().stackTrace[3]
|
||||||
|
loggerExecutor.execute {
|
||||||
|
if (file == null) println(message)
|
||||||
|
else {
|
||||||
|
val className = trace.className
|
||||||
|
val methodName = trace.methodName
|
||||||
|
val lineNumber = trace.lineNumber
|
||||||
|
file?.appendText("date/time: ${Date()} | $className.$methodName($lineNumber)\n")
|
||||||
|
file?.appendText("message: $message\n-\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun log(e: Exception) {
|
||||||
|
loggerExecutor.execute {
|
||||||
|
if (file == null) e.printStackTrace() else {
|
||||||
|
file?.appendText("---------------------------Exception---------------------------\n")
|
||||||
|
file?.appendText("date/time: ${Date()} | ${e.message}\n")
|
||||||
|
file?.appendText("trace: ${e.stackTrace}\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun log(e: Throwable) {
|
||||||
|
loggerExecutor.execute {
|
||||||
|
if (file == null) e.printStackTrace() else {
|
||||||
|
file?.appendText("---------------------------Exception---------------------------\n")
|
||||||
|
file?.appendText("date/time: ${Date()} | ${e.message}\n")
|
||||||
|
file?.appendText("trace: ${e.stackTrace}\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun shareLog(context: Context) {
|
||||||
|
if (file == null) {
|
||||||
|
snackString("No log file found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val oldFile = File(context.getExternalFilesDir(null), "old_log.txt")
|
||||||
|
val fileToUse = if (oldFile.exists()) {
|
||||||
|
file?.readText()?.let { oldFile.appendText(it) }
|
||||||
|
oldFile
|
||||||
|
} else {
|
||||||
|
file
|
||||||
|
}
|
||||||
|
val shareIntent = Intent(Intent.ACTION_SEND)
|
||||||
|
shareIntent.type = "text/plain"
|
||||||
|
shareIntent.putExtra(
|
||||||
|
Intent.EXTRA_STREAM,
|
||||||
|
FileProvider.getUriForFile(context, "${BuildConfig.APPLICATION_ID}.provider", fileToUse!!)
|
||||||
|
)
|
||||||
|
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "Log file")
|
||||||
|
shareIntent.putExtra(Intent.EXTRA_TEXT, "Log file")
|
||||||
|
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
context.startActivity(Intent.createChooser(shareIntent, "Share log file"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FinalExceptionHandler : Thread.UncaughtExceptionHandler {
|
||||||
|
private val defaultUEH: Thread.UncaughtExceptionHandler? =
|
||||||
|
Thread.getDefaultUncaughtExceptionHandler()
|
||||||
|
|
||||||
|
override fun uncaughtException(t: Thread, e: Throwable) {
|
||||||
|
Logger.log(e)
|
||||||
|
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||||
|
defaultUEH?.uncaughtException(t, e)
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import android.graphics.BitmapFactory
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import android.widget.RemoteViewsService
|
import android.widget.RemoteViewsService
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
@ -19,7 +19,7 @@ class CurrentlyAiringRemoteViewsFactory(private val context: Context, intent: In
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
// 4 items for testing
|
// 4 items for testing
|
||||||
widgetItems.clear()
|
widgetItems.clear()
|
||||||
logger("CurrentlyAiringRemoteViewsFactory onCreate")
|
Logger.log("CurrentlyAiringRemoteViewsFactory onCreate")
|
||||||
widgetItems = List(4) {
|
widgetItems = List(4) {
|
||||||
WidgetItem(
|
WidgetItem(
|
||||||
"Show $it",
|
"Show $it",
|
||||||
|
@ -31,7 +31,7 @@ class CurrentlyAiringRemoteViewsFactory(private val context: Context, intent: In
|
||||||
|
|
||||||
override fun onDataSetChanged() {
|
override fun onDataSetChanged() {
|
||||||
// 4 items for testing
|
// 4 items for testing
|
||||||
logger("CurrentlyAiringRemoteViewsFactory onDataSetChanged")
|
Logger.log("CurrentlyAiringRemoteViewsFactory onDataSetChanged")
|
||||||
widgetItems.clear()
|
widgetItems.clear()
|
||||||
widgetItems.add(
|
widgetItems.add(
|
||||||
WidgetItem(
|
WidgetItem(
|
||||||
|
@ -79,7 +79,7 @@ class CurrentlyAiringRemoteViewsFactory(private val context: Context, intent: In
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getViewAt(position: Int): RemoteViews {
|
override fun getViewAt(position: Int): RemoteViews {
|
||||||
logger("CurrentlyAiringRemoteViewsFactory getViewAt")
|
Logger.log("CurrentlyAiringRemoteViewsFactory getViewAt")
|
||||||
val item = widgetItems[position]
|
val item = widgetItems[position]
|
||||||
val rv = RemoteViews(context.packageName, R.layout.item_currently_airing_widget).apply {
|
val rv = RemoteViews(context.packageName, R.layout.item_currently_airing_widget).apply {
|
||||||
setTextViewText(R.id.text_show_title, item.title)
|
setTextViewText(R.id.text_show_title, item.title)
|
||||||
|
|
|
@ -2,11 +2,11 @@ package ani.dantotsu.widgets
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.widget.RemoteViewsService
|
import android.widget.RemoteViewsService
|
||||||
import ani.dantotsu.logger
|
import ani.dantotsu.util.Logger
|
||||||
|
|
||||||
class CurrentlyAiringRemoteViewsService : RemoteViewsService() {
|
class CurrentlyAiringRemoteViewsService : RemoteViewsService() {
|
||||||
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
|
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
|
||||||
logger("CurrentlyAiringRemoteViewsFactory onGetViewFactory")
|
Logger.log("CurrentlyAiringRemoteViewsFactory onGetViewFactory")
|
||||||
return CurrentlyAiringRemoteViewsFactory(applicationContext, intent)
|
return CurrentlyAiringRemoteViewsFactory(applicationContext, intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.extension.anime
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.tachiyomi.extension.InstallStep
|
import eu.kanade.tachiyomi.extension.InstallStep
|
||||||
import eu.kanade.tachiyomi.extension.anime.api.AnimeExtensionGithubApi
|
import eu.kanade.tachiyomi.extension.anime.api.AnimeExtensionGithubApi
|
||||||
|
@ -16,11 +17,9 @@ import eu.kanade.tachiyomi.util.preference.plusAssign
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import logcat.LogPriority
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import tachiyomi.core.util.lang.launchNow
|
import tachiyomi.core.util.lang.launchNow
|
||||||
import tachiyomi.core.util.lang.withUIContext
|
import tachiyomi.core.util.lang.withUIContext
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
import tachiyomi.domain.source.anime.model.AnimeSourceData
|
import tachiyomi.domain.source.anime.model.AnimeSourceData
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
@ -120,7 +119,7 @@ class AnimeExtensionManager(
|
||||||
val extensions: List<AnimeExtension.Available> = try {
|
val extensions: List<AnimeExtension.Available> = try {
|
||||||
api.findExtensions()
|
api.findExtensions()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logcat(LogPriority.ERROR, e)
|
Logger.log(e)
|
||||||
withUIContext { snackString("Failed to get extensions list") }
|
withUIContext { snackString("Failed to get extensions list") }
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package eu.kanade.tachiyomi.extension.anime.api
|
package eu.kanade.tachiyomi.extension.anime.api
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateNotifier
|
import eu.kanade.tachiyomi.extension.ExtensionUpdateNotifier
|
||||||
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
||||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||||
|
@ -13,11 +14,9 @@ import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
import eu.kanade.tachiyomi.network.parseAs
|
import eu.kanade.tachiyomi.network.parseAs
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import logcat.LogPriority
|
|
||||||
import tachiyomi.core.preference.Preference
|
import tachiyomi.core.preference.Preference
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
import tachiyomi.core.util.lang.withIOContext
|
import tachiyomi.core.util.lang.withIOContext
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import kotlin.time.Duration.Companion.days
|
import kotlin.time.Duration.Companion.days
|
||||||
|
@ -45,7 +44,7 @@ internal class AnimeExtensionGithubApi {
|
||||||
.newCall(GET("${REPO_URL_PREFIX}index.min.json"))
|
.newCall(GET("${REPO_URL_PREFIX}index.min.json"))
|
||||||
.awaitSuccess()
|
.awaitSuccess()
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
logcat(LogPriority.ERROR, e) { "Failed to get extensions from GitHub" }
|
Logger.log("Failed to get extensions from GitHub")
|
||||||
requiresFallbackSource = true
|
requiresFallbackSource = true
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,11 @@ import android.content.pm.PackageInstaller
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.tachiyomi.extension.InstallStep
|
import eu.kanade.tachiyomi.extension.InstallStep
|
||||||
import eu.kanade.tachiyomi.util.lang.use
|
import eu.kanade.tachiyomi.util.lang.use
|
||||||
import eu.kanade.tachiyomi.util.system.getParcelableExtraCompat
|
import eu.kanade.tachiyomi.util.system.getParcelableExtraCompat
|
||||||
import eu.kanade.tachiyomi.util.system.getUriSize
|
import eu.kanade.tachiyomi.util.system.getUriSize
|
||||||
import logcat.LogPriority
|
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
|
|
||||||
class PackageInstallerInstallerAnime(private val service: Service) : InstallerAnime(service) {
|
class PackageInstallerInstallerAnime(private val service: Service) : InstallerAnime(service) {
|
||||||
|
|
||||||
|
@ -30,7 +29,7 @@ class PackageInstallerInstallerAnime(private val service: Service) : InstallerAn
|
||||||
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
|
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
|
||||||
val userAction = intent.getParcelableExtraCompat<Intent>(Intent.EXTRA_INTENT)
|
val userAction = intent.getParcelableExtraCompat<Intent>(Intent.EXTRA_INTENT)
|
||||||
if (userAction == null) {
|
if (userAction == null) {
|
||||||
logcat(LogPriority.ERROR) { "Fatal error for $intent" }
|
Logger.log("Fatal error for $intent")
|
||||||
continueQueue(InstallStep.Error)
|
continueQueue(InstallStep.Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -89,11 +88,8 @@ class PackageInstallerInstallerAnime(private val service: Service) : InstallerAn
|
||||||
session.commit(intentSender)
|
session.commit(intentSender)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logcat(
|
Logger.log(e)
|
||||||
LogPriority.ERROR,
|
Logger.log("Failed to install extension ${entry.downloadId} ${entry.uri}")
|
||||||
e
|
|
||||||
) { "Failed to install extension ${entry.downloadId} ${entry.uri}" }
|
|
||||||
logcat(LogPriority.ERROR) { "Exception: $e" }
|
|
||||||
snackString("Failed to install extension ${entry.downloadId} ${entry.uri}")
|
snackString("Failed to install extension ${entry.downloadId} ${entry.uri}")
|
||||||
activeSession?.let { (_, sessionId) ->
|
activeSession?.let { (_, sessionId) ->
|
||||||
packageInstaller.abandonSession(sessionId)
|
packageInstaller.abandonSession(sessionId)
|
||||||
|
|
|
@ -5,15 +5,14 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeLoadResult
|
import eu.kanade.tachiyomi.extension.anime.model.AnimeLoadResult
|
||||||
import kotlinx.coroutines.CoroutineStart
|
import kotlinx.coroutines.CoroutineStart
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import logcat.LogPriority
|
|
||||||
import tachiyomi.core.util.lang.launchNow
|
import tachiyomi.core.util.lang.launchNow
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast receiver that listens for the system's packages installed, updated or removed, and only
|
* Broadcast receiver that listens for the system's packages installed, updated or removed, and only
|
||||||
|
@ -103,7 +102,7 @@ internal class AnimeExtensionInstallReceiver(private val listener: Listener) :
|
||||||
private suspend fun getExtensionFromIntent(context: Context, intent: Intent?): AnimeLoadResult {
|
private suspend fun getExtensionFromIntent(context: Context, intent: Intent?): AnimeLoadResult {
|
||||||
val pkgName = getPackageNameFromIntent(intent)
|
val pkgName = getPackageNameFromIntent(intent)
|
||||||
if (pkgName == null) {
|
if (pkgName == null) {
|
||||||
logcat(LogPriority.WARN) { "Package name not found" }
|
Logger.log("Package name not found")
|
||||||
return AnimeLoadResult.Error
|
return AnimeLoadResult.Error
|
||||||
}
|
}
|
||||||
return GlobalScope.async(Dispatchers.Default, CoroutineStart.DEFAULT) {
|
return GlobalScope.async(Dispatchers.Default, CoroutineStart.DEFAULT) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.extension.anime.installer.InstallerAnime
|
import eu.kanade.tachiyomi.extension.anime.installer.InstallerAnime
|
||||||
|
@ -15,8 +16,6 @@ import eu.kanade.tachiyomi.extension.anime.installer.PackageInstallerInstallerAn
|
||||||
import eu.kanade.tachiyomi.extension.anime.util.AnimeExtensionInstaller.Companion.EXTRA_DOWNLOAD_ID
|
import eu.kanade.tachiyomi.extension.anime.util.AnimeExtensionInstaller.Companion.EXTRA_DOWNLOAD_ID
|
||||||
import eu.kanade.tachiyomi.util.system.getSerializableExtraCompat
|
import eu.kanade.tachiyomi.util.system.getSerializableExtraCompat
|
||||||
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
||||||
import logcat.LogPriority
|
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
|
|
||||||
class AnimeExtensionInstallService : Service() {
|
class AnimeExtensionInstallService : Service() {
|
||||||
|
|
||||||
|
@ -60,7 +59,7 @@ class AnimeExtensionInstallService : Service() {
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
logcat(LogPriority.ERROR) { "Not implemented for installer $installerUsed" }
|
Logger.log("Not implemented for installer $installerUsed")
|
||||||
stopSelf()
|
stopSelf()
|
||||||
return START_NOT_STICKY
|
return START_NOT_STICKY
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,16 +10,15 @@ import android.os.Environment
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import com.jakewharton.rxrelay.PublishRelay
|
import com.jakewharton.rxrelay.PublishRelay
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.tachiyomi.extension.InstallStep
|
import eu.kanade.tachiyomi.extension.InstallStep
|
||||||
import eu.kanade.tachiyomi.extension.anime.installer.InstallerAnime
|
import eu.kanade.tachiyomi.extension.anime.installer.InstallerAnime
|
||||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||||
import logcat.LogPriority
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
@ -248,7 +247,7 @@ internal class AnimeExtensionInstaller(private val context: Context) {
|
||||||
|
|
||||||
// Set next installation step
|
// Set next installation step
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
logcat(LogPriority.ERROR) { "Couldn't locate downloaded APK" }
|
Logger.log("Couldn't locate downloaded APK")
|
||||||
downloadsRelay.call(id to InstallStep.Error)
|
downloadsRelay.call(id to InstallStep.Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import android.content.pm.PackageInfo
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.core.content.pm.PackageInfoCompat
|
import androidx.core.content.pm.PackageInfoCompat
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import dalvik.system.PathClassLoader
|
import dalvik.system.PathClassLoader
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.tachiyomi.animesource.AnimeCatalogueSource
|
import eu.kanade.tachiyomi.animesource.AnimeCatalogueSource
|
||||||
|
@ -17,8 +18,6 @@ import eu.kanade.tachiyomi.util.lang.Hash
|
||||||
import eu.kanade.tachiyomi.util.system.getApplicationIcon
|
import eu.kanade.tachiyomi.util.system.getApplicationIcon
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import logcat.LogPriority
|
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,11 +90,11 @@ internal object AnimeExtensionLoader {
|
||||||
context.packageManager.getPackageInfo(pkgName, PACKAGE_FLAGS)
|
context.packageManager.getPackageInfo(pkgName, PACKAGE_FLAGS)
|
||||||
} catch (error: PackageManager.NameNotFoundException) {
|
} catch (error: PackageManager.NameNotFoundException) {
|
||||||
// Unlikely, but the package may have been uninstalled at this point
|
// Unlikely, but the package may have been uninstalled at this point
|
||||||
logcat(LogPriority.ERROR, error)
|
Logger.log(error)
|
||||||
return AnimeLoadResult.Error
|
return AnimeLoadResult.Error
|
||||||
}
|
}
|
||||||
if (!isPackageAnExtension(pkgInfo)) {
|
if (!isPackageAnExtension(pkgInfo)) {
|
||||||
logcat(LogPriority.WARN) { "Tried to load a package that wasn't a extension ($pkgName)" }
|
Logger.log("Tried to load a package that wasn't a extension ($pkgName)")
|
||||||
return AnimeLoadResult.Error
|
return AnimeLoadResult.Error
|
||||||
}
|
}
|
||||||
return loadExtension(context, pkgName, pkgInfo)
|
return loadExtension(context, pkgName, pkgInfo)
|
||||||
|
@ -119,7 +118,7 @@ internal object AnimeExtensionLoader {
|
||||||
pkgManager.getApplicationInfo(pkgName, PackageManager.GET_META_DATA)
|
pkgManager.getApplicationInfo(pkgName, PackageManager.GET_META_DATA)
|
||||||
} catch (error: PackageManager.NameNotFoundException) {
|
} catch (error: PackageManager.NameNotFoundException) {
|
||||||
// Unlikely, but the package may have been uninstalled at this point
|
// Unlikely, but the package may have been uninstalled at this point
|
||||||
logcat(LogPriority.ERROR, error)
|
Logger.log(error)
|
||||||
return AnimeLoadResult.Error
|
return AnimeLoadResult.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,24 +127,23 @@ internal object AnimeExtensionLoader {
|
||||||
val versionCode = PackageInfoCompat.getLongVersionCode(pkgInfo)
|
val versionCode = PackageInfoCompat.getLongVersionCode(pkgInfo)
|
||||||
|
|
||||||
if (versionName.isNullOrEmpty()) {
|
if (versionName.isNullOrEmpty()) {
|
||||||
logcat(LogPriority.WARN) { "Missing versionName for extension $extName" }
|
Logger.log("Missing versionName for extension $extName")
|
||||||
return AnimeLoadResult.Error
|
return AnimeLoadResult.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate lib version
|
// Validate lib version
|
||||||
val libVersion = versionName.substringBeforeLast('.').toDoubleOrNull()
|
val libVersion = versionName.substringBeforeLast('.').toDoubleOrNull()
|
||||||
if (libVersion == null || libVersion < LIB_VERSION_MIN || libVersion > LIB_VERSION_MAX) {
|
if (libVersion == null || libVersion < LIB_VERSION_MIN || libVersion > LIB_VERSION_MAX) {
|
||||||
logcat(LogPriority.WARN) {
|
Logger.log("Lib version is $libVersion, while only versions " +
|
||||||
"Lib version is $libVersion, while only versions " +
|
|
||||||
"$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed"
|
"$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed"
|
||||||
}
|
)
|
||||||
return AnimeLoadResult.Error
|
return AnimeLoadResult.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
val signatureHash = getSignatureHash(pkgInfo)
|
val signatureHash = getSignatureHash(pkgInfo)
|
||||||
|
|
||||||
if (signatureHash == null) {
|
if (signatureHash == null) {
|
||||||
logcat(LogPriority.WARN) { "Package $pkgName isn't signed" }
|
Logger.log("Package $pkgName isn't signed")
|
||||||
return AnimeLoadResult.Error
|
return AnimeLoadResult.Error
|
||||||
} else if (signatureHash !in trustedSignatures) {
|
} else if (signatureHash !in trustedSignatures) {
|
||||||
val extension = AnimeExtension.Untrusted(
|
val extension = AnimeExtension.Untrusted(
|
||||||
|
@ -156,13 +154,13 @@ internal object AnimeExtensionLoader {
|
||||||
libVersion,
|
libVersion,
|
||||||
signatureHash
|
signatureHash
|
||||||
)
|
)
|
||||||
logcat(LogPriority.WARN, message = { "Extension $pkgName isn't trusted" })
|
Logger.log("Extension $pkgName isn't trusted")
|
||||||
return AnimeLoadResult.Untrusted(extension)
|
return AnimeLoadResult.Untrusted(extension)
|
||||||
}
|
}
|
||||||
|
|
||||||
val isNsfw = appInfo.metaData.getInt(METADATA_NSFW) == 1
|
val isNsfw = appInfo.metaData.getInt(METADATA_NSFW) == 1
|
||||||
if (!loadNsfwSource && isNsfw) {
|
if (!loadNsfwSource && isNsfw) {
|
||||||
logcat(LogPriority.WARN) { "NSFW extension $pkgName not allowed" }
|
Logger.log("NSFW extension $pkgName not allowed")
|
||||||
return AnimeLoadResult.Error
|
return AnimeLoadResult.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +187,7 @@ internal object AnimeExtensionLoader {
|
||||||
else -> throw Exception("Unknown source class type! ${obj.javaClass}")
|
else -> throw Exception("Unknown source class type! ${obj.javaClass}")
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
logcat(LogPriority.ERROR, e) { "Extension load error: $extName ($it)" }
|
Logger.log("Extension load error: $extName ($it)")
|
||||||
return AnimeLoadResult.Error
|
return AnimeLoadResult.Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.extension.manga
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.tachiyomi.extension.InstallStep
|
import eu.kanade.tachiyomi.extension.InstallStep
|
||||||
import eu.kanade.tachiyomi.extension.manga.api.MangaExtensionGithubApi
|
import eu.kanade.tachiyomi.extension.manga.api.MangaExtensionGithubApi
|
||||||
|
@ -16,11 +17,9 @@ import eu.kanade.tachiyomi.util.preference.plusAssign
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import logcat.LogPriority
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import tachiyomi.core.util.lang.launchNow
|
import tachiyomi.core.util.lang.launchNow
|
||||||
import tachiyomi.core.util.lang.withUIContext
|
import tachiyomi.core.util.lang.withUIContext
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
import tachiyomi.domain.source.manga.model.MangaSourceData
|
import tachiyomi.domain.source.manga.model.MangaSourceData
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
@ -117,7 +116,7 @@ class MangaExtensionManager(
|
||||||
val extensions: List<MangaExtension.Available> = try {
|
val extensions: List<MangaExtension.Available> = try {
|
||||||
api.findExtensions()
|
api.findExtensions()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logcat(LogPriority.ERROR, e)
|
Logger.log(e)
|
||||||
withUIContext { snackString("Failed to get manga extensions") }
|
withUIContext { snackString("Failed to get manga extensions") }
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package eu.kanade.tachiyomi.extension.manga.api
|
package eu.kanade.tachiyomi.extension.manga.api
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateNotifier
|
import eu.kanade.tachiyomi.extension.ExtensionUpdateNotifier
|
||||||
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
|
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
|
||||||
import eu.kanade.tachiyomi.extension.manga.model.AvailableMangaSources
|
import eu.kanade.tachiyomi.extension.manga.model.AvailableMangaSources
|
||||||
|
@ -13,11 +14,9 @@ import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
import eu.kanade.tachiyomi.network.parseAs
|
import eu.kanade.tachiyomi.network.parseAs
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import logcat.LogPriority
|
|
||||||
import tachiyomi.core.preference.Preference
|
import tachiyomi.core.preference.Preference
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
import tachiyomi.core.util.lang.withIOContext
|
import tachiyomi.core.util.lang.withIOContext
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import kotlin.time.Duration.Companion.days
|
import kotlin.time.Duration.Companion.days
|
||||||
|
@ -45,7 +44,7 @@ internal class MangaExtensionGithubApi {
|
||||||
.newCall(GET("${REPO_URL_PREFIX}index.min.json"))
|
.newCall(GET("${REPO_URL_PREFIX}index.min.json"))
|
||||||
.awaitSuccess()
|
.awaitSuccess()
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
logcat(LogPriority.ERROR, e) { "Failed to get extensions from GitHub" }
|
Logger.log("Failed to get extensions from GitHub")
|
||||||
requiresFallbackSource = true
|
requiresFallbackSource = true
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,11 @@ import android.content.pm.PackageInstaller
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.tachiyomi.extension.InstallStep
|
import eu.kanade.tachiyomi.extension.InstallStep
|
||||||
import eu.kanade.tachiyomi.util.lang.use
|
import eu.kanade.tachiyomi.util.lang.use
|
||||||
import eu.kanade.tachiyomi.util.system.getParcelableExtraCompat
|
import eu.kanade.tachiyomi.util.system.getParcelableExtraCompat
|
||||||
import eu.kanade.tachiyomi.util.system.getUriSize
|
import eu.kanade.tachiyomi.util.system.getUriSize
|
||||||
import logcat.LogPriority
|
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
|
|
||||||
class PackageInstallerInstallerManga(private val service: Service) : InstallerManga(service) {
|
class PackageInstallerInstallerManga(private val service: Service) : InstallerManga(service) {
|
||||||
|
|
||||||
|
@ -30,7 +29,7 @@ class PackageInstallerInstallerManga(private val service: Service) : InstallerMa
|
||||||
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
|
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
|
||||||
val userAction = intent.getParcelableExtraCompat<Intent>(Intent.EXTRA_INTENT)
|
val userAction = intent.getParcelableExtraCompat<Intent>(Intent.EXTRA_INTENT)
|
||||||
if (userAction == null) {
|
if (userAction == null) {
|
||||||
logcat(LogPriority.ERROR) { "Fatal error for $intent" }
|
Logger.log("Fatal error for $intent")
|
||||||
continueQueue(InstallStep.Error)
|
continueQueue(InstallStep.Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -89,8 +88,8 @@ class PackageInstallerInstallerManga(private val service: Service) : InstallerMa
|
||||||
session.commit(intentSender)
|
session.commit(intentSender)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logcat(LogPriority.ERROR) { "Failed to install extension ${entry.downloadId} ${entry.uri}" }
|
Logger.log("Failed to install extension ${entry.downloadId} ${entry.uri}")
|
||||||
logcat(LogPriority.ERROR) { "Exception: $e" }
|
Logger.log(e)
|
||||||
snackString("Failed to install extension ${entry.downloadId} ${entry.uri}")
|
snackString("Failed to install extension ${entry.downloadId} ${entry.uri}")
|
||||||
activeSession?.let { (_, sessionId) ->
|
activeSession?.let { (_, sessionId) ->
|
||||||
packageInstaller.abandonSession(sessionId)
|
packageInstaller.abandonSession(sessionId)
|
||||||
|
|
|
@ -5,15 +5,14 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
||||||
import eu.kanade.tachiyomi.extension.manga.model.MangaLoadResult
|
import eu.kanade.tachiyomi.extension.manga.model.MangaLoadResult
|
||||||
import kotlinx.coroutines.CoroutineStart
|
import kotlinx.coroutines.CoroutineStart
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import logcat.LogPriority
|
|
||||||
import tachiyomi.core.util.lang.launchNow
|
import tachiyomi.core.util.lang.launchNow
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast receiver that listens for the system's packages installed, updated or removed, and only
|
* Broadcast receiver that listens for the system's packages installed, updated or removed, and only
|
||||||
|
@ -103,7 +102,7 @@ internal class MangaExtensionInstallReceiver(private val listener: Listener) :
|
||||||
private suspend fun getExtensionFromIntent(context: Context, intent: Intent?): MangaLoadResult {
|
private suspend fun getExtensionFromIntent(context: Context, intent: Intent?): MangaLoadResult {
|
||||||
val pkgName = getPackageNameFromIntent(intent)
|
val pkgName = getPackageNameFromIntent(intent)
|
||||||
if (pkgName == null) {
|
if (pkgName == null) {
|
||||||
logcat(LogPriority.WARN) { "Package name not found" }
|
Logger.log("Package name not found")
|
||||||
return MangaLoadResult.Error
|
return MangaLoadResult.Error
|
||||||
}
|
}
|
||||||
return GlobalScope.async(Dispatchers.Default, CoroutineStart.DEFAULT) {
|
return GlobalScope.async(Dispatchers.Default, CoroutineStart.DEFAULT) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.extension.manga.installer.InstallerManga
|
import eu.kanade.tachiyomi.extension.manga.installer.InstallerManga
|
||||||
|
@ -15,8 +16,6 @@ import eu.kanade.tachiyomi.extension.manga.installer.PackageInstallerInstallerMa
|
||||||
import eu.kanade.tachiyomi.extension.manga.util.MangaExtensionInstaller.Companion.EXTRA_DOWNLOAD_ID
|
import eu.kanade.tachiyomi.extension.manga.util.MangaExtensionInstaller.Companion.EXTRA_DOWNLOAD_ID
|
||||||
import eu.kanade.tachiyomi.util.system.getSerializableExtraCompat
|
import eu.kanade.tachiyomi.util.system.getSerializableExtraCompat
|
||||||
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
||||||
import logcat.LogPriority
|
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
|
|
||||||
class MangaExtensionInstallService : Service() {
|
class MangaExtensionInstallService : Service() {
|
||||||
|
|
||||||
|
@ -60,7 +59,7 @@ class MangaExtensionInstallService : Service() {
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
logcat(LogPriority.ERROR) { "Not implemented for installer $installerUsed" }
|
Logger.log("Not implemented for installer $installerUsed")
|
||||||
stopSelf()
|
stopSelf()
|
||||||
return START_NOT_STICKY
|
return START_NOT_STICKY
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,16 +10,15 @@ import android.os.Environment
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import com.jakewharton.rxrelay.PublishRelay
|
import com.jakewharton.rxrelay.PublishRelay
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.tachiyomi.extension.InstallStep
|
import eu.kanade.tachiyomi.extension.InstallStep
|
||||||
import eu.kanade.tachiyomi.extension.manga.installer.InstallerManga
|
import eu.kanade.tachiyomi.extension.manga.installer.InstallerManga
|
||||||
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
||||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||||
import logcat.LogPriority
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
@ -245,7 +244,7 @@ internal class MangaExtensionInstaller(private val context: Context) {
|
||||||
|
|
||||||
// Set next installation step
|
// Set next installation step
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
logcat(LogPriority.ERROR) { "Couldn't locate downloaded APK" }
|
Logger.log("Couldn't locate downloaded APK")
|
||||||
downloadsRelay.call(id to InstallStep.Error)
|
downloadsRelay.call(id to InstallStep.Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import android.content.pm.PackageInfo
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.core.content.pm.PackageInfoCompat
|
import androidx.core.content.pm.PackageInfoCompat
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import dalvik.system.PathClassLoader
|
import dalvik.system.PathClassLoader
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
||||||
|
@ -17,8 +18,6 @@ import eu.kanade.tachiyomi.util.lang.Hash
|
||||||
import eu.kanade.tachiyomi.util.system.getApplicationIcon
|
import eu.kanade.tachiyomi.util.system.getApplicationIcon
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import logcat.LogPriority
|
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,11 +90,11 @@ internal object MangaExtensionLoader {
|
||||||
context.packageManager.getPackageInfo(pkgName, PACKAGE_FLAGS)
|
context.packageManager.getPackageInfo(pkgName, PACKAGE_FLAGS)
|
||||||
} catch (error: PackageManager.NameNotFoundException) {
|
} catch (error: PackageManager.NameNotFoundException) {
|
||||||
// Unlikely, but the package may have been uninstalled at this point
|
// Unlikely, but the package may have been uninstalled at this point
|
||||||
logcat(LogPriority.ERROR, error)
|
Logger.log(error)
|
||||||
return MangaLoadResult.Error
|
return MangaLoadResult.Error
|
||||||
}
|
}
|
||||||
if (!isPackageAnExtension(pkgInfo)) {
|
if (!isPackageAnExtension(pkgInfo)) {
|
||||||
logcat(LogPriority.WARN) { "Tried to load a package that wasn't a extension ($pkgName)" }
|
Logger.log("Tried to load a package that wasn't a extension ($pkgName)")
|
||||||
return MangaLoadResult.Error
|
return MangaLoadResult.Error
|
||||||
}
|
}
|
||||||
return loadMangaExtension(context, pkgName, pkgInfo)
|
return loadMangaExtension(context, pkgName, pkgInfo)
|
||||||
|
@ -119,7 +118,7 @@ internal object MangaExtensionLoader {
|
||||||
pkgManager.getApplicationInfo(pkgName, PackageManager.GET_META_DATA)
|
pkgManager.getApplicationInfo(pkgName, PackageManager.GET_META_DATA)
|
||||||
} catch (error: PackageManager.NameNotFoundException) {
|
} catch (error: PackageManager.NameNotFoundException) {
|
||||||
// Unlikely, but the package may have been uninstalled at this point
|
// Unlikely, but the package may have been uninstalled at this point
|
||||||
logcat(LogPriority.ERROR, error)
|
Logger.log(error)
|
||||||
return MangaLoadResult.Error
|
return MangaLoadResult.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,17 +128,16 @@ internal object MangaExtensionLoader {
|
||||||
val versionCode = PackageInfoCompat.getLongVersionCode(pkgInfo)
|
val versionCode = PackageInfoCompat.getLongVersionCode(pkgInfo)
|
||||||
|
|
||||||
if (versionName.isNullOrEmpty()) {
|
if (versionName.isNullOrEmpty()) {
|
||||||
logcat(LogPriority.WARN) { "Missing versionName for extension $extName" }
|
Logger.log("Missing versionName for extension $extName")
|
||||||
return MangaLoadResult.Error
|
return MangaLoadResult.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate lib version
|
// Validate lib version
|
||||||
val libVersion = versionName.substringBeforeLast('.').toDoubleOrNull()
|
val libVersion = versionName.substringBeforeLast('.').toDoubleOrNull()
|
||||||
if (libVersion == null || libVersion < LIB_VERSION_MIN || libVersion > LIB_VERSION_MAX) {
|
if (libVersion == null || libVersion < LIB_VERSION_MIN || libVersion > LIB_VERSION_MAX) {
|
||||||
logcat(LogPriority.WARN) {
|
Logger.log("Lib version is $libVersion, while only versions " +
|
||||||
"Lib version is $libVersion, while only versions " +
|
|
||||||
"$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed"
|
"$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed"
|
||||||
}
|
)
|
||||||
return MangaLoadResult.Error
|
return MangaLoadResult.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,18 +145,18 @@ internal object MangaExtensionLoader {
|
||||||
|
|
||||||
/* temporarily disabling signature check TODO: remove?
|
/* temporarily disabling signature check TODO: remove?
|
||||||
if (signatureHash == null) {
|
if (signatureHash == null) {
|
||||||
logcat(LogPriority.WARN) { "Package $pkgName isn't signed" }
|
Logger.log("Package $pkgName isn't signed")
|
||||||
return MangaLoadResult.Error
|
return MangaLoadResult.Error
|
||||||
} else if (signatureHash !in trustedSignatures) {
|
} else if (signatureHash !in trustedSignatures) {
|
||||||
val extension = MangaExtension.Untrusted(extName, pkgName, versionName, versionCode, libVersion, signatureHash)
|
val extension = MangaExtension.Untrusted(extName, pkgName, versionName, versionCode, libVersion, signatureHash)
|
||||||
logcat(LogPriority.WARN) { "Extension $pkgName isn't trusted" }
|
Logger.log("Extension $pkgName isn't trusted")
|
||||||
return MangaLoadResult.Untrusted(extension)
|
return MangaLoadResult.Untrusted(extension)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
val isNsfw = appInfo.metaData.getInt(METADATA_NSFW) == 1
|
val isNsfw = appInfo.metaData.getInt(METADATA_NSFW) == 1
|
||||||
if (!loadNsfwSource && isNsfw) {
|
if (!loadNsfwSource && isNsfw) {
|
||||||
logcat(LogPriority.WARN) { "NSFW extension $pkgName not allowed" }
|
Logger.log("NSFW extension $pkgName not allowed")
|
||||||
return MangaLoadResult.Error
|
return MangaLoadResult.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +183,7 @@ internal object MangaExtensionLoader {
|
||||||
else -> throw Exception("Unknown source class type! ${obj.javaClass}")
|
else -> throw Exception("Unknown source class type! ${obj.javaClass}")
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
logcat(LogPriority.ERROR, e) { "Extension load error: $extName ($it)" }
|
Logger.log("Extension load error: $extName ($it)")
|
||||||
return MangaLoadResult.Error
|
return MangaLoadResult.Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,9 @@ import androidx.core.graphics.blue
|
||||||
import androidx.core.graphics.green
|
import androidx.core.graphics.green
|
||||||
import androidx.core.graphics.red
|
import androidx.core.graphics.red
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
import eu.kanade.tachiyomi.util.lang.truncateCenter
|
import eu.kanade.tachiyomi.util.lang.truncateCenter
|
||||||
import logcat.LogPriority
|
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
@ -47,7 +46,7 @@ fun Context.copyToClipboard(label: String, content: String) {
|
||||||
toast("Copied to clipboard: " + content.truncateCenter(50))
|
toast("Copied to clipboard: " + content.truncateCenter(50))
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
logcat(LogPriority.ERROR, e)
|
Logger.log(e)
|
||||||
toast("Failed to copy to clipboard")
|
toast("Failed to copy to clipboard")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,7 @@ package eu.kanade.tachiyomi.util.system
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import logcat.LogPriority
|
import ani.dantotsu.util.Logger
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
|
|
||||||
object DeviceUtil {
|
object DeviceUtil {
|
||||||
|
|
||||||
|
@ -72,7 +71,7 @@ object DeviceUtil {
|
||||||
.getDeclaredMethod("get", String::class.java)
|
.getDeclaredMethod("get", String::class.java)
|
||||||
.invoke(null, key) as String
|
.invoke(null, key) as String
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logcat(LogPriority.WARN, e) { "Unable to use SystemProperties.get()" }
|
Logger.log("Unable to use SystemProperties.get()")
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,7 @@ import android.content.pm.PackageManager
|
||||||
import android.webkit.CookieManager
|
import android.webkit.CookieManager
|
||||||
import android.webkit.WebSettings
|
import android.webkit.WebSettings
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import logcat.LogPriority
|
import ani.dantotsu.util.Logger
|
||||||
import tachiyomi.core.util.system.logcat
|
|
||||||
|
|
||||||
object WebViewUtil {
|
object WebViewUtil {
|
||||||
const val SPOOF_PACKAGE_NAME = "org.chromium.chrome"
|
const val SPOOF_PACKAGE_NAME = "org.chromium.chrome"
|
||||||
|
@ -20,7 +19,7 @@ object WebViewUtil {
|
||||||
// is not installed
|
// is not installed
|
||||||
CookieManager.getInstance()
|
CookieManager.getInstance()
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
logcat(LogPriority.ERROR, e)
|
Logger.log(e)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -989,6 +989,52 @@
|
||||||
app:showText="false"
|
app:showText="false"
|
||||||
app:thumbTint="@color/button_switch_track" />
|
app:thumbTint="@color/button_switch_track" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.materialswitch.MaterialSwitch
|
||||||
|
android:id="@+id/settingsLogToFile"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:checked="false"
|
||||||
|
android:drawableStart="@drawable/ic_round_edit_note_24"
|
||||||
|
android:drawablePadding="16dp"
|
||||||
|
android:elegantTextHeight="true"
|
||||||
|
android:fontFamily="@font/poppins_bold"
|
||||||
|
android:minHeight="64dp"
|
||||||
|
android:text="@string/log_to_file"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
android:textColor="?attr/colorOnBackground"
|
||||||
|
app:cornerRadius="0dp"
|
||||||
|
app:drawableTint="?attr/colorPrimary"
|
||||||
|
app:showText="false"
|
||||||
|
app:thumbTint="@color/button_switch_track" />
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:alpha="0.58"
|
||||||
|
android:fontFamily="@font/poppins_bold"
|
||||||
|
android:text="@string/logging_warning" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/settingsShareLog"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:src="@drawable/ic_round_share_24"
|
||||||
|
android:padding="16dp" />
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</ani.dantotsu.others.Xpandable>
|
</ani.dantotsu.others.Xpandable>
|
||||||
|
|
||||||
<ani.dantotsu.others.Xpandable
|
<ani.dantotsu.others.Xpandable
|
||||||
|
|
|
@ -692,5 +692,7 @@ Et magni quasi vel nemo omnis et voluptate quisquam vel corporis fuga ut consequ
|
||||||
|
|
||||||
Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exercitationem adipisci quo nemo aliquam ea numquam beatae. Eum Quis dolore aut quia accusantium sed vero autem vel quaerat eaque et beatae dicta non delectus galisum non ullam nulla.
|
Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exercitationem adipisci quo nemo aliquam ea numquam beatae. Eum Quis dolore aut quia accusantium sed vero autem vel quaerat eaque et beatae dicta non delectus galisum non ullam nulla.
|
||||||
</string>
|
</string>
|
||||||
|
<string name="log_to_file">Log to File</string>
|
||||||
|
<string name="logging_warning">Logging to a file will slow down the app. Only enable if you are experiencing issues.</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue