mirror of
https://github.com/rebelonion/Dantotsu.git
synced 2026-01-31 00:51:02 +00:00
Merge branch 'dev' of https://github.com/JohnVictoryz/Dantotsu into dev
This commit is contained in:
@@ -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)
|
||||||
@@ -174,6 +167,7 @@ fun initActivity(a: Activity) {
|
|||||||
navBarHeight = insets.bottom
|
navBarHeight = insets.bottom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (a !is MainActivity) a.setNavigationTheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Activity.hideSystemBars() {
|
fun Activity.hideSystemBars() {
|
||||||
@@ -185,11 +179,11 @@ fun Activity.hideSystemBars() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun Activity.setNavigationTheme() {
|
fun Activity.setNavigationTheme() {
|
||||||
val a = TypedValue()
|
val tv = TypedValue()
|
||||||
theme.resolveAttribute(android.R.attr.colorBackground, a, true)
|
theme.resolveAttribute(android.R.attr.colorBackground, tv, true)
|
||||||
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && a.isColorType)
|
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && tv.isColorType)
|
||||||
|| (a.type >= TypedValue.TYPE_FIRST_COLOR_INT && a.type <= TypedValue.TYPE_LAST_COLOR_INT)) {
|
|| (tv.type >= TypedValue.TYPE_FIRST_COLOR_INT && tv.type <= TypedValue.TYPE_LAST_COLOR_INT)) {
|
||||||
window.navigationBarColor = a.data
|
window.navigationBarColor = tv.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,7 +300,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 +755,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 +897,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 +936,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
|
||||||
@@ -1117,7 +1111,7 @@ fun logToFile(context: Context, message: String) {
|
|||||||
* Builds the markwon instance with all the plugins
|
* Builds the markwon instance with all the plugins
|
||||||
* @return the markwon instance
|
* @return the markwon instance
|
||||||
*/
|
*/
|
||||||
fun buildMarkwon(activity: Activity, userInputContent: Boolean = true): Markwon {
|
fun buildMarkwon(activity: Context, userInputContent: Boolean = true): Markwon {
|
||||||
val markwon = Markwon.builder(activity)
|
val markwon = Markwon.builder(activity)
|
||||||
.usePlugin(object : AbstractMarkwonPlugin() {
|
.usePlugin(object : AbstractMarkwonPlugin() {
|
||||||
override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
|
override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
|
||||||
|
|||||||
@@ -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) Logger.log("Anilist Query: ${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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import ani.dantotsu.others.MalScraper
|
|||||||
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 kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
@@ -464,7 +465,8 @@ class AnilistQueries {
|
|||||||
}, recommendationPlannedQueryManga: ${recommendationPlannedQuery("MANGA")}"""
|
}, recommendationPlannedQueryManga: ${recommendationPlannedQuery("MANGA")}"""
|
||||||
query += """}""".trimEnd(',')
|
query += """}""".trimEnd(',')
|
||||||
|
|
||||||
val response = executeQuery<Query.HomePageMedia>(query)
|
val response = executeQuery<Query.HomePageMedia>(query, show = true)
|
||||||
|
Logger.log(response.toString())
|
||||||
val returnMap = mutableMapOf<String, ArrayList<Media>>()
|
val returnMap = mutableMapOf<String, ArrayList<Media>>()
|
||||||
fun current(type: String) {
|
fun current(type: String) {
|
||||||
val subMap = mutableMapOf<Int, Media>()
|
val subMap = mutableMapOf<Int, Media>()
|
||||||
@@ -750,7 +752,7 @@ class AnilistQueries {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return if (!genres.isNullOrEmpty() && tags != null) {
|
return if (!genres.isNullOrEmpty() && tags != null) {
|
||||||
Anilist.genres = genres
|
Anilist.genres = genres?.sortedBy { it }?.toMutableList() as ArrayList<String>
|
||||||
Anilist.tags = tags
|
Anilist.tags = tags
|
||||||
true
|
true
|
||||||
} else false
|
} else false
|
||||||
@@ -1350,10 +1352,10 @@ Page(page:$page,perPage:50) {
|
|||||||
|
|
||||||
suspend fun getFeed(userId: Int?, global: Boolean = false, page: Int = 1): FeedResponse? {
|
suspend fun getFeed(userId: Int?, global: Boolean = false, page: Int = 1): FeedResponse? {
|
||||||
val filter = if (userId != null) "userId:$userId,"
|
val filter = if (userId != null) "userId:$userId,"
|
||||||
else if (global) "isFollowing:false,"
|
else if (global) "isFollowing:false,type:TEXT,"
|
||||||
else "isFollowing:true,"
|
else "isFollowing:true,type_not:MESSAGE,"
|
||||||
val res = executeQuery<FeedResponse>(
|
val res = executeQuery<FeedResponse>(
|
||||||
"""{Page(page:$page,perPage:$ITEMS_PER_PAGE){activities(${filter}sort:ID_DESC){__typename ... on TextActivity{id userId type replyCount text(asHtml:true)siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on ListActivity{id userId type replyCount status progress siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}media{id title{english romaji native userPreferred}bannerImage coverImage{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on MessageActivity{id recipientId messengerId type replyCount message(asHtml:true)isLocked isSubscribed isLiked isPrivate siteUrl createdAt recipient{id name bannerImage avatar{medium large}}messenger{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}}}}"""
|
"""{Page(page:$page,perPage:$ITEMS_PER_PAGE){activities(${filter}sort:ID_DESC){__typename ... on TextActivity{id userId type replyCount text(asHtml:true)siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on ListActivity{id userId type replyCount status progress siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}media{id title{english romaji native userPreferred}bannerImage coverImage{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on MessageActivity{id recipientId messengerId type replyCount likeCount message(asHtml:true)isLocked isSubscribed isLiked isPrivate siteUrl createdAt recipient{id name bannerImage avatar{medium large}}messenger{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}}}}"""
|
||||||
)
|
)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -70,13 +70,13 @@ data class Activity(
|
|||||||
@SerialName("media")
|
@SerialName("media")
|
||||||
val media: Media?,
|
val media: Media?,
|
||||||
@SerialName("replies")
|
@SerialName("replies")
|
||||||
val replies: List<Reply>?,
|
val replies: List<ActivityReply>?,
|
||||||
@SerialName("likes")
|
@SerialName("likes")
|
||||||
val likes: List<User>?,
|
val likes: List<User>?,
|
||||||
) : java.io.Serializable
|
) : java.io.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Reply(
|
data class ActivityReply(
|
||||||
@SerialName("id")
|
@SerialName("id")
|
||||||
val id: Int,
|
val id: Int,
|
||||||
@SerialName("userId")
|
@SerialName("userId")
|
||||||
|
|||||||
@@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,11 +67,12 @@ class GenreActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun loadLocalGenres(): ArrayList<String>? {
|
private fun loadLocalGenres(): ArrayList<String>? {
|
||||||
val genres = PrefManager.getVal<Set<String>>(PrefName.GenresList)
|
val genres = PrefManager.getVal<Set<String>>(PrefName.GenresList)
|
||||||
.toMutableList() as ArrayList<String>?
|
.toMutableList()
|
||||||
return if (genres.isNullOrEmpty()) {
|
return if (genres.isEmpty()) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
genres
|
//sort alphabetically
|
||||||
|
genres.sort().let { genres as ArrayList<String> }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -559,6 +559,8 @@ class AnimeWatchFragment : Fragment() {
|
|||||||
super.onResume()
|
super.onResume()
|
||||||
binding.mediaInfoProgressBar.visibility = progress
|
binding.mediaInfoProgressBar.visibility = progress
|
||||||
binding.animeSourceRecycler.layoutManager?.onRestoreInstanceState(state)
|
binding.animeSourceRecycler.layoutManager?.onRestoreInstanceState(state)
|
||||||
|
|
||||||
|
requireActivity().setNavigationTheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
|
|||||||
@@ -87,6 +87,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
|
||||||
@@ -1382,8 +1383,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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -601,6 +601,7 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
|
|||||||
super.onResume()
|
super.onResume()
|
||||||
binding.mediaInfoProgressBar.visibility = progress
|
binding.mediaInfoProgressBar.visibility = progress
|
||||||
binding.animeSourceRecycler.layoutManager?.onRestoreInstanceState(state)
|
binding.animeSourceRecycler.layoutManager?.onRestoreInstanceState(state)
|
||||||
|
|
||||||
requireActivity().setNavigationTheme()
|
requireActivity().setNavigationTheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import ani.dantotsu.media.MediaAdaptor
|
|||||||
import ani.dantotsu.media.user.ListActivity
|
import ani.dantotsu.media.user.ListActivity
|
||||||
import ani.dantotsu.setSlideIn
|
import ani.dantotsu.setSlideIn
|
||||||
import ani.dantotsu.setSlideUp
|
import ani.dantotsu.setSlideUp
|
||||||
import ani.dantotsu.util.ColorEditor.Companion.toCssColor
|
import ani.dantotsu.util.AniMarkdown.Companion.getFullAniHTML
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@@ -72,8 +72,8 @@ class ProfileFragment : Fragment() {
|
|||||||
binding.profileUserBio.settings.loadWithOverviewMode = true
|
binding.profileUserBio.settings.loadWithOverviewMode = true
|
||||||
binding.profileUserBio.settings.useWideViewPort = true
|
binding.profileUserBio.settings.useWideViewPort = true
|
||||||
binding.profileUserBio.setInitialScale(1)
|
binding.profileUserBio.setInitialScale(1)
|
||||||
val styledHtml = styled(
|
val styledHtml = getFullAniHTML(
|
||||||
convertMarkdownToHtml(user.about ?: ""),
|
user.about ?: "",
|
||||||
backGroundColorTypedValue.data,
|
backGroundColorTypedValue.data,
|
||||||
textColorTypedValue.data
|
textColorTypedValue.data
|
||||||
)
|
)
|
||||||
@@ -175,16 +175,6 @@ class ProfileFragment : Fragment() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun convertMarkdownToHtml(markdown: String): String {
|
|
||||||
val regex = """\[\!\[(.*?)\]\((.*?)\)\]\((.*?)\)""".toRegex()
|
|
||||||
return regex.replace(markdown) { matchResult ->
|
|
||||||
val altText = matchResult.groupValues[1]
|
|
||||||
val imageUrl = matchResult.groupValues[2]
|
|
||||||
val linkUrl = matchResult.groupValues[3]
|
|
||||||
"""<a href="$linkUrl"><img src="$imageUrl" alt="$altText"></a>"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initRecyclerView(
|
private fun initRecyclerView(
|
||||||
mode: LiveData<ArrayList<Media>>,
|
mode: LiveData<ArrayList<Media>>,
|
||||||
container: View,
|
container: View,
|
||||||
@@ -221,56 +211,6 @@ class ProfileFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun styled(html: String, backGroundColor: Int, textColor: Int): String { //istg anilist has the worst api
|
|
||||||
//remove some of the html entities
|
|
||||||
val step1 = html.replace(" ", " ")
|
|
||||||
.replace("&", "&")
|
|
||||||
.replace("<", "<")
|
|
||||||
.replace(">", ">")
|
|
||||||
.replace(""", "\"")
|
|
||||||
.replace("'", "'")
|
|
||||||
.replace("<pre>", "")
|
|
||||||
.replace("`", "")
|
|
||||||
.replace("~", "")
|
|
||||||
|
|
||||||
val step2 = step1.replace("(?s)___(.*?)___".toRegex(), "<br><em><strong>$1</strong></em><br>")
|
|
||||||
val step3 = step2.replace("(?s)__(.*?)__".toRegex(), "<br><strong>$1</strong><br>")
|
|
||||||
|
|
||||||
|
|
||||||
return """
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, charset=UTF-8">
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
background-color: ${backGroundColor.toCssColor()};
|
|
||||||
color: ${textColor.toCssColor()};
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
max-width: 100%;
|
|
||||||
overflow-x: hidden; /* Prevent horizontal scrolling */
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto; /* Maintain aspect ratio */
|
|
||||||
}
|
|
||||||
video {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto; /* Maintain aspect ratio */
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: ${textColor.toCssColor()};
|
|
||||||
}
|
|
||||||
/* Add responsive design elements for other content as needed */
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
$step3
|
|
||||||
</body>
|
|
||||||
|
|
||||||
""".trimIndent()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance(query: Query.UserProfile): ProfileFragment {
|
fun newInstance(query: Query.UserProfile): ProfileFragment {
|
||||||
val args = Bundle().apply {
|
val args = Bundle().apply {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.buildMarkwon
|
import ani.dantotsu.buildMarkwon
|
||||||
import ani.dantotsu.connections.anilist.Anilist
|
import ani.dantotsu.connections.anilist.Anilist
|
||||||
@@ -11,10 +12,12 @@ import ani.dantotsu.connections.anilist.api.Activity
|
|||||||
import ani.dantotsu.databinding.ItemActivityBinding
|
import ani.dantotsu.databinding.ItemActivityBinding
|
||||||
import ani.dantotsu.loadImage
|
import ani.dantotsu.loadImage
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
|
import ani.dantotsu.util.AniMarkdown.Companion.getBasicAniHTML
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
import com.bumptech.glide.load.model.GlideUrl
|
import com.bumptech.glide.load.model.GlideUrl
|
||||||
import com.bumptech.glide.request.RequestOptions
|
import com.bumptech.glide.request.RequestOptions
|
||||||
|
import com.xwray.groupie.GroupieAdapter
|
||||||
import com.xwray.groupie.viewbinding.BindableItem
|
import com.xwray.groupie.viewbinding.BindableItem
|
||||||
import jp.wasabeef.glide.transformations.BlurTransformation
|
import jp.wasabeef.glide.transformations.BlurTransformation
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -28,11 +31,19 @@ class ActivityItem(
|
|||||||
val clickCallback: (Int, type: String) -> Unit
|
val clickCallback: (Int, type: String) -> Unit
|
||||||
) : BindableItem<ItemActivityBinding>() {
|
) : BindableItem<ItemActivityBinding>() {
|
||||||
private lateinit var binding: ItemActivityBinding
|
private lateinit var binding: ItemActivityBinding
|
||||||
|
private lateinit var repliesAdapter: GroupieAdapter
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun bind(viewBinding: ItemActivityBinding, position: Int) {
|
override fun bind(viewBinding: ItemActivityBinding, position: Int) {
|
||||||
binding = viewBinding
|
binding = viewBinding
|
||||||
|
|
||||||
|
repliesAdapter = GroupieAdapter()
|
||||||
|
binding.activityReplies.adapter = repliesAdapter
|
||||||
|
binding.activityReplies.layoutManager = LinearLayoutManager(
|
||||||
|
binding.root.context,
|
||||||
|
LinearLayoutManager.VERTICAL,
|
||||||
|
false
|
||||||
|
)
|
||||||
binding.activityUserName.text = activity.user?.name ?: activity.messenger?.name
|
binding.activityUserName.text = activity.user?.name ?: activity.messenger?.name
|
||||||
binding.activityUserAvatar.loadImage(activity.user?.avatar?.medium ?: activity.messenger?.avatar?.medium)
|
binding.activityUserAvatar.loadImage(activity.user?.avatar?.medium ?: activity.messenger?.avatar?.medium)
|
||||||
binding.activityTime.text = ActivityItemBuilder.getDateTime(activity.createdAt)
|
binding.activityTime.text = ActivityItemBuilder.getDateTime(activity.createdAt)
|
||||||
@@ -41,8 +52,24 @@ class ActivityItem(
|
|||||||
binding.activityLike.setColorFilter(if (activity.isLiked == true) likeColor else notLikeColor)
|
binding.activityLike.setColorFilter(if (activity.isLiked == true) likeColor else notLikeColor)
|
||||||
binding.commentRepliesContainer.visibility =
|
binding.commentRepliesContainer.visibility =
|
||||||
if (activity.replyCount > 0) View.VISIBLE else View.GONE
|
if (activity.replyCount > 0) View.VISIBLE else View.GONE
|
||||||
binding.activityLikeCount.text = (activity.likeCount?:0).toString()
|
binding.commentRepliesContainer.setOnClickListener {
|
||||||
|
when (binding.activityReplies.visibility) {
|
||||||
|
View.GONE -> {
|
||||||
|
repliesAdapter.addAll(
|
||||||
|
activity.replies?.map { ActivityReplyItem(it) } ?: emptyList()
|
||||||
|
)
|
||||||
|
binding.activityReplies.visibility = View.VISIBLE
|
||||||
|
binding.commentTotalReplies.text = "Hide replies"
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
repliesAdapter.clear()
|
||||||
|
binding.activityReplies.visibility = View.GONE
|
||||||
|
binding.commentTotalReplies.text = "View replies"
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding.activityLikeCount.text = (activity.likeCount?:0).toString()
|
||||||
binding.activityLike.setOnClickListener {
|
binding.activityLike.setOnClickListener {
|
||||||
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||||
scope.launch {
|
scope.launch {
|
||||||
@@ -96,7 +123,7 @@ class ActivityItem(
|
|||||||
binding.activityContent.visibility = View.VISIBLE
|
binding.activityContent.visibility = View.VISIBLE
|
||||||
if (!(context as android.app.Activity).isDestroyed) {
|
if (!(context as android.app.Activity).isDestroyed) {
|
||||||
val markwon = buildMarkwon(context, false)
|
val markwon = buildMarkwon(context, false)
|
||||||
markwon.setMarkdown(binding.activityContent, activity.text ?: "")
|
markwon.setMarkdown(binding.activityContent, getBasicAniHTML(activity.text ?: ""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +132,7 @@ class ActivityItem(
|
|||||||
binding.activityContent.visibility = View.VISIBLE
|
binding.activityContent.visibility = View.VISIBLE
|
||||||
if (!(context as android.app.Activity).isDestroyed) {
|
if (!(context as android.app.Activity).isDestroyed) {
|
||||||
val markwon = buildMarkwon(context, false)
|
val markwon = buildMarkwon(context, false)
|
||||||
markwon.setMarkdown(binding.activityContent, activity.message ?: "")
|
markwon.setMarkdown(binding.activityContent, getBasicAniHTML(activity.message ?: ""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package ani.dantotsu.profile.activity
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import ani.dantotsu.R
|
||||||
|
import ani.dantotsu.buildMarkwon
|
||||||
|
import ani.dantotsu.connections.anilist.api.ActivityReply
|
||||||
|
import ani.dantotsu.databinding.ItemActivityReplyBinding
|
||||||
|
import ani.dantotsu.loadImage
|
||||||
|
import ani.dantotsu.util.AniMarkdown.Companion.getBasicAniHTML
|
||||||
|
import com.xwray.groupie.viewbinding.BindableItem
|
||||||
|
|
||||||
|
class ActivityReplyItem(
|
||||||
|
private val reply: ActivityReply
|
||||||
|
) : BindableItem<ItemActivityReplyBinding>() {
|
||||||
|
private lateinit var binding: ItemActivityReplyBinding
|
||||||
|
|
||||||
|
override fun bind(viewBinding: ItemActivityReplyBinding, position: Int) {
|
||||||
|
binding = viewBinding
|
||||||
|
|
||||||
|
binding.activityUserAvatar.loadImage(reply.user.avatar?.medium)
|
||||||
|
binding.activityUserName.text = reply.user.name
|
||||||
|
binding.activityTime.text = ActivityItemBuilder.getDateTime(reply.createdAt)
|
||||||
|
binding.activityLikeCount.text = reply.likeCount.toString()
|
||||||
|
val likeColor = ContextCompat.getColor(binding.root.context, R.color.yt_red)
|
||||||
|
val notLikeColor = ContextCompat.getColor(binding.root.context, R.color.bg_opp)
|
||||||
|
binding.activityLike.setColorFilter(if (reply.isLiked) likeColor else notLikeColor)
|
||||||
|
val markwon = buildMarkwon(binding.root.context)
|
||||||
|
markwon.setMarkdown(binding.activityContent, getBasicAniHTML(reply.text))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLayout(): Int {
|
||||||
|
return R.layout.item_activity_reply
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initializeViewBinding(view: View): ItemActivityReplyBinding {
|
||||||
|
return ItemActivityReplyBinding.bind(view)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,7 @@ class FeedActivity: AppCompatActivity() {
|
|||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
navBar = binding.feedNavBar
|
navBar = binding.feedNavBar
|
||||||
navBar.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin += navBarHeight }
|
navBar.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin += navBarHeight }
|
||||||
val personalTab = navBar.createTab(R.drawable.ic_round_person_24, "Personal")
|
val personalTab = navBar.createTab(R.drawable.ic_round_person_24, "Following")
|
||||||
val globalTab = navBar.createTab(R.drawable.ic_globe_24, "Global")
|
val globalTab = navBar.createTab(R.drawable.ic_globe_24, "Global")
|
||||||
navBar.addTab(personalTab)
|
navBar.addTab(personalTab)
|
||||||
navBar.addTab(globalTab)
|
navBar.addTab(globalTab)
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -64,14 +64,17 @@ class FeedFragment : Fragment() {
|
|||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
res?.data?.page?.activities?.let { activities ->
|
res?.data?.page?.activities?.let { activities ->
|
||||||
activityList = activities
|
activityList = activities
|
||||||
adapter.update(activityList.map { ActivityItem(it) { _, _ -> } })
|
val filtered = activities.filterNot { //filter out messages that are not directed to the user
|
||||||
|
it.recipient?.id != null && it.recipient.id != Anilist.userid
|
||||||
|
}
|
||||||
|
adapter.update(filtered.map { ActivityItem(it) { _, _ -> } })
|
||||||
}
|
}
|
||||||
binding.listProgressBar.visibility = ViewGroup.GONE
|
binding.listProgressBar.visibility = ViewGroup.GONE
|
||||||
val scrollView = binding.listRecyclerView
|
val scrollView = binding.listRecyclerView
|
||||||
|
|
||||||
binding.listRecyclerView.setOnTouchListener { _, event ->
|
binding.listRecyclerView.setOnTouchListener { _, event ->
|
||||||
if (event?.action == MotionEvent.ACTION_UP) {
|
if (event?.action == MotionEvent.ACTION_UP) {
|
||||||
if (adapter.itemCount % AnilistQueries.ITEMS_PER_PAGE != 0 && !global) {
|
if (activityList.size % AnilistQueries.ITEMS_PER_PAGE != 0 && !global) {
|
||||||
snackString("No more activities")
|
snackString("No more activities")
|
||||||
} else if (!scrollView.canScrollVertically(1) && !binding.feedRefresh.isVisible
|
} else if (!scrollView.canScrollVertically(1) && !binding.feedRefresh.isVisible
|
||||||
&& binding.listRecyclerView.adapter!!.itemCount != 0 &&
|
&& binding.listRecyclerView.adapter!!.itemCount != 0 &&
|
||||||
@@ -84,7 +87,10 @@ class FeedFragment : Fragment() {
|
|||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
res?.data?.page?.activities?.let { activities ->
|
res?.data?.page?.activities?.let { activities ->
|
||||||
activityList += activities
|
activityList += activities
|
||||||
adapter.addAll(activities.map { ActivityItem(it) { _, _ -> } })
|
val filtered = activities.filterNot {
|
||||||
|
it.recipient?.id != null && it.recipient.id != Anilist.userid
|
||||||
|
}
|
||||||
|
adapter.addAll(filtered.map { ActivityItem(it) { _, _ -> } })
|
||||||
}
|
}
|
||||||
binding.feedRefresh.visibility = ViewGroup.GONE
|
binding.feedRefresh.visibility = ViewGroup.GONE
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -160,6 +160,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
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.Activity
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import android.os.Build
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
@@ -54,7 +55,10 @@ class ThemeManager(private val context: Activity) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val window = context.window
|
val window = context.window
|
||||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
|
||||||
|
}
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
||||||
window.statusBarColor = 0x00000000
|
window.statusBarColor = 0x00000000
|
||||||
context.setTheme(themeToApply)
|
context.setTheme(themeToApply)
|
||||||
@@ -137,7 +141,7 @@ class ThemeManager(private val context: Activity) {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromString(value: String): Theme {
|
fun fromString(value: String): Theme {
|
||||||
return values().find { it.theme == value } ?: PURPLE
|
return entries.find { it.theme == value } ?: PURPLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
101
app/src/main/java/ani/dantotsu/util/AniMarkdown.kt
Normal file
101
app/src/main/java/ani/dantotsu/util/AniMarkdown.kt
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package ani.dantotsu.util
|
||||||
|
|
||||||
|
import ani.dantotsu.util.ColorEditor.Companion.toCssColor
|
||||||
|
|
||||||
|
class AniMarkdown { //istg anilist has the worst api
|
||||||
|
companion object {
|
||||||
|
private fun convertNestedImageToHtml(markdown: String): String {
|
||||||
|
val regex = """\[\!\[(.*?)\]\((.*?)\)\]\((.*?)\)""".toRegex()
|
||||||
|
return regex.replace(markdown) { matchResult ->
|
||||||
|
val altText = matchResult.groupValues[1]
|
||||||
|
val imageUrl = matchResult.groupValues[2]
|
||||||
|
val linkUrl = matchResult.groupValues[3]
|
||||||
|
"""<a href="$linkUrl"><img src="$imageUrl" alt="$altText"></a>"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convertImageToHtml(markdown: String): String {
|
||||||
|
val regex = """\!\[(.*?)\]\((.*?)\)""".toRegex()
|
||||||
|
return regex.replace(markdown) { matchResult ->
|
||||||
|
val altText = matchResult.groupValues[1]
|
||||||
|
val imageUrl = matchResult.groupValues[2]
|
||||||
|
"""<img src="$imageUrl" alt="$altText">"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convertLinkToHtml(markdown: String): String {
|
||||||
|
val regex = """\[(.*?)\]\((.*?)\)""".toRegex()
|
||||||
|
return regex.replace(markdown) { matchResult ->
|
||||||
|
val linkText = matchResult.groupValues[1]
|
||||||
|
val linkUrl = matchResult.groupValues[2]
|
||||||
|
"""<a href="$linkUrl">$linkText</a>"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun replaceLeftovers(html: String): String {
|
||||||
|
return html.replace(" ", " ")
|
||||||
|
.replace("&", "&")
|
||||||
|
.replace("<", "<")
|
||||||
|
.replace(">", ">")
|
||||||
|
.replace(""", "\"")
|
||||||
|
.replace("'", "'")
|
||||||
|
.replace("<pre>", "")
|
||||||
|
.replace("`", "")
|
||||||
|
.replace("~", "")
|
||||||
|
.replace(">\n<", "><")
|
||||||
|
.replace("\n", "<br>")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun underlineToHtml(html: String): String {
|
||||||
|
return html.replace("(?s)___(.*?)___".toRegex(), "<br><em><strong>$1</strong></em><br>")
|
||||||
|
.replace("(?s)__(.*?)__".toRegex(), "<br><strong>$1</strong><br>")
|
||||||
|
.replace("(?s)[\\s]+_([^_]+)_[\\s]+".toRegex(), "<em>$1</em>")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBasicAniHTML(html: String): String {
|
||||||
|
val step0 = convertNestedImageToHtml(html)
|
||||||
|
val step1 = convertImageToHtml(step0)
|
||||||
|
val step2 = convertLinkToHtml(step1)
|
||||||
|
val step3 = replaceLeftovers(step2)
|
||||||
|
return underlineToHtml(step3)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFullAniHTML(html: String, backGroundColor: Int, textColor: Int): String {
|
||||||
|
val basicHtml = getBasicAniHTML(html)
|
||||||
|
|
||||||
|
|
||||||
|
return """
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, charset=UTF-8">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: ${backGroundColor.toCssColor()};
|
||||||
|
color: ${textColor.toCssColor()};
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow-x: hidden; /* Prevent horizontal scrolling */
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto; /* Maintain aspect ratio */
|
||||||
|
}
|
||||||
|
video {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto; /* Maintain aspect ratio */
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: ${textColor.toCssColor()};
|
||||||
|
}
|
||||||
|
/* Add responsive design elements for other content as needed */
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
$basicHtml
|
||||||
|
</body>
|
||||||
|
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
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.stackTraceToString()}\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.stackTraceToString()}\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
|
||||||
|
|||||||
@@ -110,7 +110,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="start|center_vertical"
|
android:layout_gravity="start|center_vertical"
|
||||||
android:backgroundTint="@color/bg_white"
|
android:backgroundTint="?attr/colorSurface"
|
||||||
app:cardCornerRadius="24dp">
|
app:cardCornerRadius="24dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
@@ -153,9 +153,10 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="start|center_vertical"
|
android:layout_gravity="start|bottom"
|
||||||
android:layout_marginStart="128dp"
|
android:layout_marginStart="128dp"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@@ -166,8 +167,7 @@
|
|||||||
android:fontFamily="@font/poppins_semi_bold"
|
android:fontFamily="@font/poppins_semi_bold"
|
||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
android:text="@string/anime"
|
android:text="@string/anime"
|
||||||
android:textColor="@color/bg_white"
|
android:textSize="16sp"
|
||||||
android:textSize="14sp"
|
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
@@ -175,10 +175,9 @@
|
|||||||
android:id="@+id/activityText"
|
android:id="@+id/activityText"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="15dp"
|
android:layout_marginTop="10dp"
|
||||||
android:fontFamily="@font/poppins_semi_bold"
|
android:fontFamily="@font/poppins_semi_bold"
|
||||||
android:text="@string/slogan"
|
android:text="@string/slogan"
|
||||||
android:textColor="@color/bg_white"
|
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
@@ -215,4 +214,11 @@
|
|||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/activityReplies"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_marginStart="16dp"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
104
app/src/main/res/layout/item_activity_reply.xml
Normal file
104
app/src/main/res/layout/item_activity_reply.xml
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/activityAvatarContainer"
|
||||||
|
android:layout_width="64dp"
|
||||||
|
android:layout_height="64dp"
|
||||||
|
android:layout_gravity="start|center_vertical"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:backgroundTint="@color/transparent"
|
||||||
|
app:cardCornerRadius="64dp"
|
||||||
|
app:strokeColor="@color/transparent">
|
||||||
|
|
||||||
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
|
android:id="@+id/activityUserAvatar"
|
||||||
|
android:layout_width="64dp"
|
||||||
|
android:layout_height="64dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
app:srcCompat="@drawable/ic_round_add_circle_24"
|
||||||
|
tools:ignore="ContentDescription,ImageContrastCheck"
|
||||||
|
tools:tint="@color/transparent" />
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/activityUserName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/poppins_semi_bold"
|
||||||
|
android:text="Username"
|
||||||
|
android:textSize="15sp"
|
||||||
|
tools:ignore="HardcodedText,RtlSymmetry" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/activityTime"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/poppins_semi_bold"
|
||||||
|
android:text="Wed,06 March 2024, 7:00PM"
|
||||||
|
android:textSize="14sp"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end|center"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/activityLike"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_round_favorite_24"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/activityLikeCount"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:fontFamily="@font/poppins_semi_bold"
|
||||||
|
android:textSize="15sp"
|
||||||
|
tools:text="12" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/activityContent"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:fontFamily="@font/poppins_semi_bold"
|
||||||
|
android:text="@string/lorem_ipsum"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -75,8 +75,9 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="start|center"
|
android:layout_gravity="start|bottom"
|
||||||
android:layout_marginStart="125dp"
|
android:layout_marginStart="125dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@@ -95,8 +96,8 @@
|
|||||||
android:id="@+id/notificationDate"
|
android:id="@+id/notificationDate"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="start"
|
android:layout_gravity="end"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginEnd="20dp"
|
||||||
android:fontFamily="@font/poppins_semi_bold"
|
android:fontFamily="@font/poppins_semi_bold"
|
||||||
android:text="Wed,06 March 2024, 7:00PM"
|
android:text="Wed,06 March 2024, 7:00PM"
|
||||||
android:textSize="10sp"
|
android:textSize="10sp"
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user