feat: logging to file

This commit is contained in:
rebelonion 2024-03-11 03:01:08 -05:00
parent 1028ac66cb
commit dbce7c5b29
67 changed files with 475 additions and 324 deletions

View file

@ -21,6 +21,8 @@ import ani.dantotsu.parsers.novel.NovelExtensionManager
import ani.dantotsu.settings.SettingsActivity
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.util.FinalExceptionHandler
import ani.dantotsu.util.Logger
import com.google.android.material.color.DynamicColors
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
@ -83,7 +85,8 @@ class App : MultiDexApplication() {
}
crashlytics.setCustomKey("device Info", SettingsActivity.getDeviceInfo())
Logger.init(this)
Thread.setDefaultUncaughtExceptionHandler(FinalExceptionHandler())
initializeNetwork(baseContext)
@ -99,19 +102,19 @@ class App : MultiDexApplication() {
val animeScope = CoroutineScope(Dispatchers.Default)
animeScope.launch {
animeExtensionManager.findAvailableExtensions()
logger("Anime Extensions: ${animeExtensionManager.installedExtensionsFlow.first()}")
Logger.log("Anime Extensions: ${animeExtensionManager.installedExtensionsFlow.first()}")
AnimeSources.init(animeExtensionManager.installedExtensionsFlow)
}
val mangaScope = CoroutineScope(Dispatchers.Default)
mangaScope.launch {
mangaExtensionManager.findAvailableExtensions()
logger("Manga Extensions: ${mangaExtensionManager.installedExtensionsFlow.first()}")
Logger.log("Manga Extensions: ${mangaExtensionManager.installedExtensionsFlow.first()}")
MangaSources.init(mangaExtensionManager.installedExtensionsFlow)
}
val novelScope = CoroutineScope(Dispatchers.Default)
novelScope.launch {
novelExtensionManager.findAvailableExtensions()
logger("Novel Extensions: ${novelExtensionManager.installedExtensionsFlow.first()}")
Logger.log("Novel Extensions: ${novelExtensionManager.installedExtensionsFlow.first()}")
NovelSources.init(novelExtensionManager.installedExtensionsFlow)
}
val commentsScope = CoroutineScope(Dispatchers.Default)
@ -138,7 +141,8 @@ class App : MultiDexApplication() {
try {
Notifications.createChannels(this)
} catch (e: Exception) {
logcat(LogPriority.ERROR, e) { "Failed to modify notification channels" }
Logger.log("Failed to modify notification channels")
Logger.log(e)
}
}

View file

@ -28,7 +28,6 @@ import android.telephony.TelephonyManager
import android.text.InputFilter
import android.text.Spanned
import android.util.AttributeSet
import android.util.Log
import android.util.TypedValue
import android.view.*
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.Companion.generateSalt
import ani.dantotsu.subcriptions.NotificationClickReceiver
import ani.dantotsu.util.Logger
import com.bumptech.glide.Glide
import com.bumptech.glide.RequestBuilder
import com.bumptech.glide.RequestManager
@ -128,13 +128,6 @@ fun currActivity(): Activity? {
var loadMedia: Int? = null
var loadIsMAL = false
fun logger(e: Any?, print: Boolean = true) {
if (print)
//println(e)
Log.d("Logger", e.toString())
}
fun initActivity(a: Activity) {
val window = a.window
WindowCompat.setDecorFitsSystemWindows(window, false)
@ -306,7 +299,7 @@ class InputFilterMinMax(
val input = (dest.toString() + source.toString()).toDouble()
if (isInRange(min, max, input)) return null
} catch (nfe: NumberFormatException) {
logger(nfe.stackTraceToString())
Logger.log(nfe)
}
return ""
}
@ -761,7 +754,7 @@ fun saveImage(image: Bitmap, path: String, imageFileName: String): File? {
private fun scanFile(path: String, context: Context) {
MediaScannerConnection.scanFile(context, arrayOf(path), null) { p, _ ->
logger("Finished scanning $p")
Logger.log("Finished scanning $p")
}
}
@ -903,7 +896,7 @@ class EmptyAdapter(private val count: Int) : RecyclerView.Adapter<RecyclerView.V
fun toast(string: String?) {
if (string != null) {
logger(string)
Logger.log(string)
MainScope().launch {
Toast.makeText(currActivity()?.application ?: return@launch, string, Toast.LENGTH_SHORT)
.show()
@ -942,10 +935,10 @@ fun snackString(s: String?, activity: Activity? = null, clipboard: String? = nul
}
return snackBar
}
logger(s)
Logger.log(s)
}
} catch (e: Exception) {
logger(e.stackTraceToString())
Logger.log(e)
Injekt.get<CrashlyticsInterface>().logException(e)
}
return null

View file

@ -49,6 +49,7 @@ import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.settings.saving.SharedPreferenceBooleanLiveData
import ani.dantotsu.subcriptions.Subscription.Companion.startSubscription
import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.util.Logger
import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar
import eu.kanade.domain.source.service.SourcePreferences

View file

@ -5,6 +5,7 @@ import android.os.Build
import androidx.fragment.app.FragmentActivity
import ani.dantotsu.others.webview.CloudFlare
import ani.dantotsu.others.webview.WebViewBottomDialog
import ani.dantotsu.util.Logger
import com.lagradost.nicehttp.Requests
import com.lagradost.nicehttp.ResponseParser
import com.lagradost.nicehttp.addGenericDns
@ -104,6 +105,7 @@ fun logError(e: Throwable, post: Boolean = true, snackbar: Boolean = true) {
toast(e.localizedMessage)
}
e.printStackTrace()
Logger.log(e)
}
fun <T> tryWith(post: Boolean = false, snackbar: Boolean = true, call: () -> T): T? {

View file

@ -14,6 +14,7 @@ import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
import ani.dantotsu.toast
import ani.dantotsu.tryWithSuspend
import ani.dantotsu.util.Logger
import java.util.Calendar
object Anilist {
@ -150,7 +151,7 @@ object Anilist {
cacheTime = cache ?: 10
)
val remaining = json.headers["X-RateLimit-Remaining"]?.toIntOrNull() ?: -1
Log.d("AnilistQuery", "Remaining requests: $remaining")
Logger.log("Remaining requests: $remaining")
if (json.code == 429) {
val retry = json.headers["Retry-After"]?.toIntOrNull() ?: -1
val passedLimitReset = json.headers["X-RateLimit-Reset"]?.toLongOrNull() ?: 0
@ -161,13 +162,13 @@ object Anilist {
toast("Rate limited. Try 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}")
json.parsed()
} else null
} catch (e: Exception) {
if (show) snackString("Error fetching Anilist data: ${e.message}")
Log.e("AnilistQuery", "Error: ${e.message}")
Logger.log("Anilist Query Error: ${e.message}")
null
}
}

View file

@ -15,6 +15,7 @@ import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
import ani.dantotsu.tryWithSuspend
import ani.dantotsu.util.Logger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -99,6 +100,7 @@ class AnilistHomeViewModel : ViewModel() {
suspend fun initHomePage() {
val res = Anilist.query.initHomePage()
Logger.log("AnilistHomeViewModel : res=$res")
res["currentAnime"]?.let { animeContinue.postValue(it) }
res["favoriteAnime"]?.let { animeFav.postValue(it) }
res["plannedAnime"]?.let { animePlanned.postValue(it) }

View file

@ -4,7 +4,7 @@ import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import ani.dantotsu.logError
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.startMainActivity
@ -16,7 +16,7 @@ class Login : AppCompatActivity() {
ThemeManager(this).applyTheme()
val data: Uri? = intent?.data
logger(data.toString())
Logger.log(data.toString())
try {
Anilist.token =
Regex("""(?<=access_token=).+(?=&token_type)""").find(data.toString())!!.value

View file

@ -1,17 +1,18 @@
package ani.dantotsu.connections.crashlytics
import android.content.Context
import ani.dantotsu.util.Logger
class CrashlyticsStub : CrashlyticsInterface {
override fun initialize(context: Context) {
//no-op
}
override fun logException(e: Throwable) {
//no-op
Logger.log(e)
}
override fun log(message: String) {
//no-op
Logger.log(message)
}
override fun setUserId(id: String) {

View file

@ -15,7 +15,6 @@ import android.os.Environment
import android.os.IBinder
import android.os.PowerManager
import android.provider.MediaStore
import android.util.Log
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
@ -26,6 +25,7 @@ import ani.dantotsu.connections.discord.serializers.User
import ani.dantotsu.isOnline
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.util.Logger
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import com.google.gson.JsonParser
@ -274,7 +274,7 @@ class DiscordService : Service() {
return
}
}
t.message?.let { Log.d("WebSocket", "onFailure() $it") }
t.message?.let { Logger.log("onFailure() $it") }
log("WebSocket: Error, onFailure() reason: ${t.message}")
client = OkHttpClient()
client.newWebSocket(
@ -289,7 +289,7 @@ class DiscordService : Service() {
override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
super.onClosing(webSocket, code, reason)
Log.d("WebSocket", "onClosing() $code $reason")
Logger.log("onClosing() $code $reason")
if (::heartbeatThread.isInitialized && !heartbeatThread.isInterrupted) {
heartbeatThread.interrupt()
}
@ -297,7 +297,7 @@ class DiscordService : Service() {
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
super.onClosed(webSocket, code, reason)
Log.d("WebSocket", "onClosed() $code $reason")
Logger.log("onClosed() $code $reason")
if (code >= 4000) {
log("WebSocket: Error, code: $code reason: $reason")
client = OkHttpClient()
@ -382,52 +382,7 @@ class DiscordService : Service() {
}
fun log(string: String) {
Log.d("WebSocket_Discord", 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")
}
//Logger.log(string)
}
fun resume() {

View file

@ -27,7 +27,7 @@ import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.download.video.ExoplayerDownloadService
import ani.dantotsu.download.video.Helper
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.media.Media
import ani.dantotsu.media.SubtitleDownloader
import ani.dantotsu.media.anime.AnimeWatchFragment
@ -249,7 +249,7 @@ class AnimeDownloaderService : Service() {
hasDownloadStarted(downloadManager, task, 30000) // 30 seconds timeout
if (!downloadStarted) {
logger("Download failed to start")
Logger.log("Download failed to start")
builder.setContentText("${task.title} - ${task.episode} Download failed to start")
notificationManager.notify(NOTIFICATION_ID, builder.build())
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)
if (download != null) {
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")
notificationManager.notify(NOTIFICATION_ID, builder.build())
snackString("${task.title} - ${task.episode} Download failed")
logger("Download failed: ${download.failureReason}")
Logger.log("Download failed: ${download.failureReason}")
downloadsManager.removeDownload(
DownloadedType(
task.title,
@ -289,7 +289,7 @@ class AnimeDownloaderService : Service() {
break
}
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")
notificationManager.notify(NOTIFICATION_ID, builder.build())
snackString("${task.title} - ${task.episode} Download completed")
@ -309,7 +309,7 @@ class AnimeDownloaderService : Service() {
break
}
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")
notificationManager.notify(NOTIFICATION_ID, builder.build())
snackString("${task.title} - ${task.episode} Download stopped")
@ -328,7 +328,7 @@ class AnimeDownloaderService : Service() {
}
} catch (e: Exception) {
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}")
e.printStackTrace()
Injekt.get<CrashlyticsInterface>().logException(e)

View file

@ -33,7 +33,7 @@ import ani.dantotsu.currContext
import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.initActivity
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsActivity
import ani.dantotsu.navBarHeight
@ -318,8 +318,8 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
val mediaJson = media.readText()
gson.fromJson(mediaJson, Media::class.java)
} catch (e: Exception) {
logger("Error loading media.json: ${e.message}")
logger(e.printStackTrace())
Logger.log("Error loading media.json: ${e.message}")
Logger.log(e)
Injekt.get<CrashlyticsInterface>().logException(e)
null
}
@ -374,8 +374,8 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
bannerUri
)
} catch (e: Exception) {
logger("Error loading media.json: ${e.message}")
logger(e.printStackTrace())
Logger.log("Error loading media.json: ${e.message}")
Logger.log(e)
Injekt.get<CrashlyticsInterface>().logException(e)
return OfflineAnimeModel(
"unknown",

View file

@ -21,7 +21,7 @@ import ani.dantotsu.R
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.media.Media
import ani.dantotsu.media.manga.ImageData
import ani.dantotsu.media.manga.MangaReadFragment.Companion.ACTION_DOWNLOAD_FAILED
@ -251,7 +251,7 @@ class MangaDownloaderService : Service() {
snackString("${task.title} - ${task.chapter} Download finished")
}
} 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}")
Injekt.get<CrashlyticsInterface>().logException(e)
broadcastDownloadFailed(task.chapter)

View file

@ -30,7 +30,7 @@ import ani.dantotsu.currContext
import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.initActivity
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsActivity
import ani.dantotsu.navBarHeight
@ -308,8 +308,8 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
val mediaJson = media.readText()
gson.fromJson(mediaJson, Media::class.java)
} catch (e: Exception) {
logger("Error loading media.json: ${e.message}")
logger(e.printStackTrace())
Logger.log("Error loading media.json: ${e.message}")
Logger.log(e)
Injekt.get<CrashlyticsInterface>().logException(e)
null
}
@ -358,8 +358,8 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
bannerUri
)
} catch (e: Exception) {
logger("Error loading media.json: ${e.message}")
logger(e.printStackTrace())
Logger.log("Error loading media.json: ${e.message}")
Logger.log(e)
Injekt.get<CrashlyticsInterface>().logException(e)
return OfflineMangaModel(
"unknown",

View file

@ -20,7 +20,7 @@ import ani.dantotsu.R
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.media.Media
import ani.dantotsu.media.novel.NovelReadFragment
import ani.dantotsu.snackString
@ -186,15 +186,15 @@ class NovelDownloaderService : Service() {
val contentType = response.header("Content-Type")
val contentDisposition = response.header("Content-Disposition")
logger("Content-Type: $contentType")
logger("Content-Disposition: $contentDisposition")
Logger.log("Content-Type: $contentType")
Logger.log("Content-Disposition: $contentDisposition")
// Return true if the Content-Type or Content-Disposition indicates an EPUB file
contentType == "application/epub+zip" ||
(contentDisposition?.contains(".epub") == true)
}
} catch (e: Exception) {
logger("Error checking file type: ${e.message}")
Logger.log("Error checking file type: ${e.message}")
false
}
}
@ -225,12 +225,12 @@ class NovelDownloaderService : Service() {
if (!isEpubFile(task.downloadLink)) {
if (isAlreadyDownloaded(task.originalLink)) {
logger("Already downloaded")
Logger.log("Already downloaded")
broadcastDownloadFinished(task.originalLink)
snackString("Already downloaded")
return@withContext
}
logger("Download link is not an .epub file")
Logger.log("Download link is not an .epub file")
broadcastDownloadFailed(task.originalLink)
snackString("Download link is not an .epub file")
return@withContext
@ -301,7 +301,7 @@ class NovelDownloaderService : Service() {
withContext(Dispatchers.Main) {
val progress =
(downloadedBytes * 100 / totalBytes).toInt()
logger("Download progress: $progress")
Logger.log("Download progress: $progress")
broadcastDownloadProgress(task.originalLink, progress)
}
lastBroadcastUpdate = downloadedBytes
@ -316,7 +316,7 @@ class NovelDownloaderService : Service() {
}
}
} catch (e: Exception) {
logger("Exception while downloading .epub inside request: ${e.message}")
Logger.log("Exception while downloading .epub inside request: ${e.message}")
throw e
}
}
@ -340,7 +340,7 @@ class NovelDownloaderService : Service() {
snackString("${task.title} - ${task.chapter} Download finished")
}
} 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}")
Injekt.get<CrashlyticsInterface>().logException(e)
broadcastDownloadFailed(task.originalLink)

View file

@ -43,6 +43,7 @@ import ani.dantotsu.parsers.SubtitleType
import ani.dantotsu.parsers.Video
import ani.dantotsu.parsers.VideoType
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.util.Logger
import eu.kanade.tachiyomi.network.NetworkHelper
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -157,15 +158,15 @@ object Helper {
finalException: Exception?
) {
if (download.state == Download.STATE_COMPLETED) {
Log.e("Downloader", "Download Completed")
Logger.log("Download Completed")
} else if (download.state == Download.STATE_FAILED) {
Log.e("Downloader", "Download Failed")
Logger.log("Download Failed")
} else if (download.state == Download.STATE_STOPPED) {
Log.e("Downloader", "Download Stopped")
Logger.log("Download Stopped")
} else if (download.state == Download.STATE_QUEUED) {
Log.e("Downloader", "Download Queued")
Logger.log("Download Queued")
} else if (download.state == Download.STATE_DOWNLOADING) {
Log.e("Downloader", "Download Downloading")
Logger.log("Download Downloading")
}
}
}

View file

@ -9,7 +9,7 @@ import androidx.lifecycle.ViewModel
import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.currContext
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.media.anime.Episode
import ani.dantotsu.media.anime.SelectorDialogFragment
import ani.dantotsu.media.manga.MangaChapter
@ -223,7 +223,7 @@ class MediaDetailsViewModel : ViewModel() {
}
fun setEpisode(ep: Episode?, who: String) {
logger("set episode ${ep?.number} - $who", false)
Logger.log("set episode ${ep?.number} - $who")
episode.postValue(ep)
MainScope().launch(Dispatchers.Main) {
episode.value = null
@ -270,7 +270,7 @@ class MediaDetailsViewModel : ViewModel() {
mangaChapters
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 {
mangaLoaded[i] =
mangaReadSources?.loadChaptersFromMedia(i, media) ?: return@tryWithSuspend

View file

@ -86,6 +86,7 @@ import ani.dantotsu.settings.PlayerSettingsActivity
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.util.Logger
import com.bumptech.glide.Glide
import com.google.android.gms.cast.framework.CastButtonFactory
import com.google.android.gms.cast.framework.CastContext
@ -1372,8 +1373,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
mediaItem = if (downloadedMediaItem == null) {
val builder = MediaItem.Builder().setUri(video!!.file.url).setMimeType(mimeType)
logger("url: ${video!!.file.url}")
logger("mimeType: $mimeType")
Logger.log("url: ${video!!.file.url}")
Logger.log("mimeType: $mimeType")
if (sub != null) {
val listofnotnullsubs = listOfNotNull(sub)

View file

@ -10,7 +10,7 @@ import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.util.LruCache
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.snackString
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.online.HttpSource
@ -32,8 +32,8 @@ data class ImageData(
try {
// Fetch the image
val response = httpSource.getImage(page)
logger("Response: ${response.code}")
logger("Response: ${response.message}")
Logger.log("Response: ${response.code}")
Logger.log("Response: ${response.message}")
// Convert the Response to an InputStream
val inputStream = response.body.byteStream()
@ -47,7 +47,7 @@ data class ImageData(
return@withContext bitmap
} catch (e: Exception) {
// Handle any exceptions
logger("An error occurred: ${e.message}")
Logger.log("An error occurred: ${e.message}")
snackString("An error occurred: ${e.message}")
return@withContext null
}

View file

@ -31,6 +31,7 @@ import ani.dantotsu.media.MediaDetailsViewModel
import ani.dantotsu.media.novel.novelreader.NovelReaderActivity
import ani.dantotsu.navBarHeight
import ani.dantotsu.parsers.ShowResponse
import ani.dantotsu.util.Logger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -59,7 +60,7 @@ class NovelReadFragment : Fragment(),
var loaded = false
override fun downloadTrigger(novelDownloadPackage: NovelDownloadPackage) {
Log.e("downloadTrigger", novelDownloadPackage.link)
Logger.log("novel link: ${novelDownloadPackage.link}")
val downloadTask = NovelDownloaderService.DownloadTask(
title = media.mainName(),
chapter = novelDownloadPackage.novelName,

View file

@ -11,6 +11,7 @@ import ani.dantotsu.databinding.ItemNovelResponseBinding
import ani.dantotsu.parsers.ShowResponse
import ani.dantotsu.setAnimation
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import com.bumptech.glide.Glide
import com.bumptech.glide.load.model.GlideUrl
@ -181,7 +182,7 @@ class NovelResponseAdapter(
if (position != -1) {
list[position].extra?.remove("0")
list[position].extra?.set("0", "Downloading: $progress%")
Log.d("NovelResponseAdapter", "updateDownloadProgress: $progress, position: $position")
Logger.log( "updateDownloadProgress: $progress, position: $position")
notifyItemChanged(position)
}
}

View file

@ -1,6 +1,6 @@
package ani.dantotsu.others
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import java.util.regex.Pattern
import kotlin.math.pow
@ -64,7 +64,7 @@ class JsUnpacker(packedJS: String?) {
return decoded.toString()
}
} catch (e: Exception) {
logger(e)
Logger.log(e)
}
return null
}

View file

@ -2,7 +2,7 @@ package ani.dantotsu.others
import ani.dantotsu.FileUrl
import ani.dantotsu.client
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.media.Media
import ani.dantotsu.media.anime.Episode
import ani.dantotsu.tryWithSuspend
@ -41,8 +41,7 @@ object Kitsu {
}
suspend fun getKitsuEpisodesDetails(media: Media): Map<String, Episode>? {
val print = false
logger("Kitsu : title=${media.mainName()}", print)
Logger.log("Kitsu : title=${media.mainName()}")
val query =
"""
query {
@ -70,7 +69,7 @@ query {
val result = getKitsuData(query) ?: return null
logger("Kitsu : result=$result", print)
//Logger.log("Kitsu : result=$result")
media.idKitsu = result.data?.lookupMapping?.id
val a = (result.data?.lookupMapping?.episodes?.nodes ?: return null).mapNotNull { ep ->
val num = ep?.number?.toString() ?: return@mapNotNull null
@ -81,7 +80,7 @@ query {
thumb = FileUrl[ep.thumbnail?.original?.url],
)
}.toMap()
logger("Kitsu : a=$a", print)
//Logger.log("Kitsu : a=$a")
return a
}

View file

@ -11,7 +11,7 @@ import android.os.Environment
import android.provider.MediaStore
import ani.dantotsu.FileUrl
import ani.dantotsu.currContext
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.media.anime.AnimeNameAdapter
import ani.dantotsu.media.manga.ImageData
import ani.dantotsu.media.manga.MangaCache
@ -129,7 +129,7 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
val configurableSource = extension.sources[sourceLanguage] as? ConfigurableAnimeSource
?: return false
currContext()?.let { context ->
logger("isDubAvailableSeparately: ${configurableSource.getPreferenceKey()}")
Logger.log("isDubAvailableSeparately: ${configurableSource.getPreferenceKey()}")
val sharedPreferences =
context.getSharedPreferences(
configurableSource.getPreferenceKey(),
@ -205,7 +205,7 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
}
return sortedEpisodes.map { SEpisodeToEpisode(it) }
} catch (e: Exception) {
logger("Exception: $e")
Logger.log("Exception: $e")
}
return emptyList()
}
@ -240,7 +240,7 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
val videos = source.getVideoList(sEpisode)
videos.map { VideoToVideoServer(it) }
} catch (e: Exception) {
logger("Exception occurred: ${e.message}")
Logger.log("Exception occurred: ${e.message}")
emptyList()
}
}
@ -260,16 +260,16 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
?: return emptyList())
return try {
val res = source.fetchSearchAnime(1, query, source.getFilterList()).awaitSingle()
logger("query: $query")
Logger.log("query: $query")
convertAnimesPageToShowResponse(res)
} catch (e: CloudflareBypassException) {
logger("Exception in search: $e")
Logger.log("Exception in search: $e")
withContext(Dispatchers.Main) {
snackString("Failed to bypass Cloudflare")
}
emptyList()
} catch (e: Exception) {
logger("General exception in search: $e")
Logger.log("General exception in search: $e")
emptyList()
}
}
@ -358,12 +358,12 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
val res = source.getChapterList(sManga)
val reversedRes = res.reversed()
val chapterList = reversedRes.map { SChapterToMangaChapter(it) }
logger("chapterList size: ${chapterList.size}")
logger("chapterList: ${chapterList[1].title}")
logger("chapterList: ${chapterList[1].description}")
Logger.log("chapterList size: ${chapterList.size}")
Logger.log("chapterList: ${chapterList[1].title}")
Logger.log("chapterList: ${chapterList[1].description}")
chapterList
} catch (e: Exception) {
logger("loadChapters Exception: $e")
Logger.log("loadChapters Exception: $e")
emptyList()
}
}
@ -379,7 +379,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
var imageDataList: List<ImageData> = listOf()
val ret = coroutineScope {
try {
logger("source.name " + source.name)
Logger.log("source.name " + source.name)
val res = source.getPageList(sChapter)
val reIndexedPages =
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) {
mangaCache.put(page.imageUrl ?: "", ImageData(page, source))
imageDataList += ImageData(page, source)
logger("put page: ${page.imageUrl}")
Logger.log("put page: ${page.imageUrl}")
pageToMangaImage(page)
}
}
@ -396,7 +396,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
deferreds.awaitAll()
} catch (e: Exception) {
logger("loadImages Exception: $e")
Logger.log("loadImages Exception: $e")
snackString("Failed to load images: $e")
emptyList()
}
@ -414,7 +414,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
return coroutineScope {
try {
logger("source.name " + source.name)
Logger.log("source.name " + source.name)
val res = source.getPageList(sChapter)
val reIndexedPages =
res.mapIndexed { index, page -> Page(index, page.url, page.imageUrl, page.uri) }
@ -430,7 +430,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
deferreds.awaitAll()
} catch (e: Exception) {
logger("loadImages Exception: $e")
Logger.log("loadImages Exception: $e")
snackString("Failed to load images: $e")
emptyList()
}
@ -446,8 +446,8 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
try {
// Fetch the image
val response = httpSource.getImage(page)
logger("Response: ${response.code}")
logger("Response: ${response.message}")
Logger.log("Response: ${response.code}")
Logger.log("Response: ${response.message}")
// Convert the Response to an InputStream
val inputStream = response.body.byteStream()
@ -467,7 +467,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
return@withContext bitmap
} catch (e: Exception) {
// Handle any exceptions
logger("An error occurred: ${e.message}")
Logger.log("An error occurred: ${e.message}")
return@withContext null
}
}
@ -500,7 +500,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
inputStream.close()
} catch (e: Exception) {
// 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) {
// 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 {
val res = source.fetchSearchManga(1, query, source.getFilterList()).awaitSingle()
logger("res observable: $res")
Logger.log("res observable: $res")
convertMangasPageToShowResponse(res)
} catch (e: CloudflareBypassException) {
logger("Exception in search: $e")
Logger.log("Exception in search: $e")
withContext(Dispatchers.Main) {
snackString("Failed to bypass Cloudflare")
}
emptyList()
} catch (e: Exception) {
logger("General exception in search: $e")
Logger.log("General exception in search: $e")
emptyList()
}
}
@ -714,7 +714,7 @@ class VideoServerPassthrough(val videoServer: VideoServer) : VideoExtractor() {
// If the format is still undetermined, log an error
if (format == null) {
logger("Unknown video format: $videoUrl")
Logger.log("Unknown video format: $videoUrl")
format = VideoType.CONTAINER
}
val headersMap: Map<String, String> =
@ -746,7 +746,7 @@ class VideoServerPassthrough(val videoServer: VideoServer) : VideoExtractor() {
private fun headRequest(fileName: String, networkHelper: NetworkHelper): VideoType? {
return try {
logger("attempting head request for $fileName")
Logger.log("attempting head request for $fileName")
val request = Request.Builder()
.url(fileName)
.head()
@ -771,13 +771,13 @@ class VideoServerPassthrough(val videoServer: VideoServer) : VideoExtractor() {
else -> null
}
} else {
logger("failed head request for $fileName")
Logger.log("failed head request for $fileName")
null
}
}
} catch (e: Exception) {
logger("Exception in headRequest: $e")
Logger.log("Exception in headRequest: $e")
null
}

View file

@ -3,7 +3,7 @@ package ani.dantotsu.parsers
import ani.dantotsu.FileUrl
import ani.dantotsu.R
import ani.dantotsu.currContext
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.media.Media
import ani.dantotsu.settings.saving.PrefManager
import eu.kanade.tachiyomi.animesource.model.SAnime
@ -59,11 +59,11 @@ abstract class BaseParser {
saveShowResponse(mediaObj.id, response, true)
} else {
setUserText("Searching : ${mediaObj.mainName()}")
logger("Searching : ${mediaObj.mainName()}")
Logger.log("Searching : ${mediaObj.mainName()}")
val results = search(mediaObj.mainName())
//log all results
results.forEach {
logger("Result: ${it.name}")
Logger.log("Result: ${it.name}")
}
val sortedResults = if (results.isNotEmpty()) {
results.sortedByDescending {
@ -83,7 +83,7 @@ abstract class BaseParser {
) < 100
) {
setUserText("Searching : ${mediaObj.nameRomaji}")
logger("Searching : ${mediaObj.nameRomaji}")
Logger.log("Searching : ${mediaObj.nameRomaji}")
val romajiResults = search(mediaObj.nameRomaji)
val sortedRomajiResults = if (romajiResults.isNotEmpty()) {
romajiResults.sortedByDescending {
@ -96,10 +96,10 @@ abstract class BaseParser {
emptyList()
}
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) {
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
} else {
val romajiRatio = FuzzySearch.ratio(
@ -110,14 +110,14 @@ abstract class BaseParser {
response.name.lowercase(),
mediaObj.mainName().lowercase()
)
logger("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 results: $mainNameRatio for ${response.name.lowercase()}")
Logger.log("Fuzzy ratio for closest match in RomajiResults: $romajiRatio for ${closestRomaji?.name?.lowercase() ?: "None"}")
if (romajiRatio > mainNameRatio) {
logger("RomajiResults has a closer match. Replacing response.")
Logger.log("RomajiResults has a closer match. Replacing response.")
closestRomaji
} 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
}
}

View file

@ -1,7 +1,7 @@
package ani.dantotsu.parsers
import ani.dantotsu.Lazier
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.media.Media
import ani.dantotsu.media.anime.Episode
import ani.dantotsu.media.manga.MangaChapter
@ -96,7 +96,7 @@ abstract class MangaReadSources : BaseSources() {
}
//must be downloaded
if (show.sManga == null) {
logger("sManga is null")
Logger.log("sManga is null")
}
if (parser is OfflineMangaParser && show.sManga == null) {
tryWithSuspend(true) {
@ -106,11 +106,11 @@ abstract class MangaReadSources : BaseSources() {
}
}
} 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
}
}

View file

@ -6,6 +6,7 @@ import ani.dantotsu.parsers.novel.DynamicNovelParser
import ani.dantotsu.parsers.novel.NovelExtension
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.util.Logger
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first
@ -47,8 +48,8 @@ object NovelSources : NovelReadSources() {
}
private fun createParsersFromExtensions(extensions: List<NovelExtension.Installed>): List<Lazier<BaseParser>> {
Log.d("NovelSources", "createParsersFromExtensions")
Log.d("NovelSources", extensions.toString())
Logger.log("createParsersFromExtensions")
Logger.log(extensions.toString())
return extensions.map { extension ->
val name = extension.name
Lazier({ DynamicNovelParser(extension) }, name)

View file

@ -3,7 +3,7 @@ package ani.dantotsu.parsers
import android.os.Environment
import ani.dantotsu.currContext
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.media.manga.MangaNameAdapter
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
@ -68,7 +68,7 @@ class OfflineMangaParser : MangaParser() {
matchResult?.groups?.get(1)?.value?.toIntOrNull() ?: Int.MAX_VALUE
}
for (image in images) {
logger("imageNumber: ${image.url.url}")
Logger.log("imageNumber: ${image.url.url}")
}
return images
}

View file

@ -1,6 +1,6 @@
package ani.dantotsu.parsers
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
class StringMatcher {
companion object {
@ -54,10 +54,10 @@ class StringMatcher {
val closestShowAndIndex = closestShow(target, shows)
val closestIndex = closestShowAndIndex.second
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
}
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(
closestIndex + 1,
shows.size

View file

@ -2,7 +2,7 @@ package ani.dantotsu.parsers.novel
import android.content.Context
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import eu.kanade.tachiyomi.extension.ExtensionUpdateNotifier
@ -14,9 +14,7 @@ import eu.kanade.tachiyomi.network.awaitSuccess
import eu.kanade.tachiyomi.network.parseAs
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import logcat.LogPriority
import tachiyomi.core.util.lang.withIOContext
import tachiyomi.core.util.system.logcat
import uy.kohesive.injekt.injectLazy
import java.util.Date
import kotlin.time.Duration.Companion.days
@ -41,20 +39,20 @@ class NovelExtensionGithubApi {
.newCall(GET("${REPO_URL_PREFIX}index.min.json"))
.awaitSuccess()
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e) { "Failed to get extensions from GitHub" }
Logger.log("Failed to get extensions from GitHub")
requiresFallbackSource = true
null
}
}
val response = githubResponse ?: run {
logger("using fallback source")
Logger.log("using fallback source")
networkService.client
.newCall(GET("${FALLBACK_REPO_URL_PREFIX}index.min.json"))
.awaitSuccess()
}
logger("response: $response")
Logger.log("response: $response")
val extensions = with(json) {
response
@ -67,7 +65,7 @@ class NovelExtensionGithubApi {
/*if (extensions.size < 10) { //TODO: uncomment when more extensions are added
throw Exception()
}*/
logger("extensions: $extensions")
Logger.log("extensions: $extensions")
extensions
}
}

View file

@ -3,6 +3,7 @@ package ani.dantotsu.parsers.novel
import android.os.FileObserver
import android.util.Log
import ani.dantotsu.parsers.novel.FileObserver.fileObserver
import ani.dantotsu.util.Logger
import java.io.File
@ -22,24 +23,24 @@ class NovelExtensionFileObserver(private val listener: Listener, private val pat
override fun onEvent(event: Int, file: String?) {
Log.e("NovelExtensionFileObserver", "Event: $event")
Logger.log("Event: $event")
if (file == null) return
val fullPath = File(path, file)
when (event) {
CREATE -> {
Log.e("NovelExtensionFileObserver", "File created: $fullPath")
Logger.log("File created: $fullPath")
listener.onExtensionFileCreated(fullPath)
}
DELETE -> {
Log.e("NovelExtensionFileObserver", "File deleted: $fullPath")
Logger.log("File deleted: $fullPath")
listener.onExtensionFileDeleted(fullPath)
}
MODIFY -> {
Log.e("NovelExtensionFileObserver", "File modified: $fullPath")
Logger.log("File modified: $fullPath")
listener.onExtensionFileModified(fullPath)
}
}

View file

@ -15,13 +15,12 @@ import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.net.toUri
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import com.jakewharton.rxrelay.PublishRelay
import eu.kanade.tachiyomi.extension.InstallStep
import eu.kanade.tachiyomi.util.storage.getUriCompat
import logcat.LogPriority
import rx.Observable
import rx.android.schedulers.AndroidSchedulers
import tachiyomi.core.util.system.logcat
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
@ -77,12 +76,12 @@ internal class NovelExtensionInstaller(private val context: Context) {
val fileToDelete = File("$sourcePath/${url.toUri().lastPathSegment}")
if (fileToDelete.exists()) {
if (fileToDelete.delete()) {
Log.i("Install APK", "APK file deleted successfully.")
Logger.log("APK file deleted successfully.")
} else {
Log.e("Install APK", "Failed to delete APK file.")
Logger.log("Failed to delete APK file.")
}
} 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
@ -161,7 +160,7 @@ internal class NovelExtensionInstaller(private val context: Context) {
// Check if source path is obtained correctly
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)
return InstallStep.Error
}
@ -172,14 +171,14 @@ internal class NovelExtensionInstaller(private val context: Context) {
destinationDir.mkdirs()
}
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)
return InstallStep.Error
}
// Copy the file to the new location
copyFileToInternalStorage(sourcePath, destinationPath)
Log.i("Install APK", "APK moved to $destinationPath")
Logger.log("APK moved to $destinationPath")
downloadsRelay.call(downloadId to InstallStep.Installed)
return InstallStep.Installed
}
@ -198,9 +197,9 @@ internal class NovelExtensionInstaller(private val context: Context) {
val fileToDelete = File(apkPath)
//give write permission to the file
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)
Log.i("Uninstall APK", "Success: $a")
Logger.log("Success: $a")
}
//set the directory to writable
val destinationDir = File(apkPath).parentFile
@ -208,27 +207,27 @@ internal class NovelExtensionInstaller(private val context: Context) {
destinationDir.mkdirs()
}
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) {
try {
Files.delete(fileToDelete.toPath())
} catch (e: Exception) {
Log.e("Uninstall APK", "Failed to delete APK file.")
Log.e("Uninstall APK", e.toString())
Logger.log("Failed to delete APK file.")
Logger.log(e)
snackString("Failed to delete APK file.")
}
} else {
if (fileToDelete.exists()) {
if (fileToDelete.delete()) {
Log.i("Uninstall APK", "APK file deleted successfully.")
Logger.log("APK file deleted successfully.")
snackString("APK file deleted successfully.")
} else {
Log.e("Uninstall APK", "Failed to delete APK file.")
Logger.log("Failed to delete APK file.")
snackString("Failed to delete APK file.")
}
} else {
Log.e("Uninstall APK", "APK file not found.")
Logger.log("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
if (destination.exists()) {
if (destination.delete()) {
Log.i("File Copy", "File deleted successfully.")
Logger.log("File deleted successfully.")
} 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()
}
Log.i("File Copy", "File copied to internal storage.")
Logger.log("File copied to internal storage.")
}
private fun getRealPathFromURI(context: Context, contentUri: Uri): String? {
@ -350,7 +349,7 @@ internal class NovelExtensionInstaller(private val context: Context) {
// Set next installation step
if (uri == null) {
logcat(LogPriority.ERROR) { "Couldn't locate downloaded APK" }
Logger.log("Couldn't locate downloaded APK")
downloadsRelay.call(id to InstallStep.Error)
return
}
@ -371,7 +370,7 @@ internal class NovelExtensionInstaller(private val context: Context) {
val uri = Uri.parse(localUri)
val path = uri.path
val pkgName = path?.substring(path.lastIndexOf('/') + 1)?.removeSuffix(".apk")
Log.i("Install APK", "Package name: $pkgName")
Logger.log("Package name: $pkgName")
return pkgName ?: ""
}
}

View file

@ -7,7 +7,7 @@ import android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES
import android.os.Build
import android.util.Log
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.parsers.NovelInterface
import ani.dantotsu.snackString
import dalvik.system.PathClassLoader
@ -26,21 +26,20 @@ internal object NovelExtensionLoader {
val installDir = context.getExternalFilesDir(null)?.absolutePath + "/extensions/novel/"
val results = mutableListOf<NovelLoadResult>()
//the number of files
Log.e("NovelExtensionLoader", "Loading extensions from $installDir")
Log.e(
"NovelExtensionLoader",
Logger.log("Loading extensions from $installDir")
Logger.log(
"Loading extensions from ${File(installDir).listFiles()?.size}"
)
File(installDir).setWritable(false)
File(installDir).listFiles()?.forEach {
//set the file to read only
it.setWritable(false)
Log.e("NovelExtensionLoader", "Loading extension ${it.name}")
Logger.log("Loading extension ${it.name}")
val extension = loadExtension(context, it)
if (extension is NovelLoadResult.Success) {
results.add(extension)
} else {
logger("Failed to load extension ${it.name}")
Logger.log("Failed to load extension ${it.name}")
}
}
return results
@ -62,7 +61,7 @@ internal object NovelExtensionLoader {
context.packageManager.getPackageArchiveInfo(path, 0)
} catch (error: Exception) {
// 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 loadExtension(context, File(path))
@ -88,8 +87,8 @@ internal object NovelExtensionLoader {
val signatureHash = getSignatureHash(packageInfo)
if ((signatureHash == null) || !signatureHash.contains(officialSignature)) {
logger("Package ${packageInfo.packageName} isn't signed")
logger("signatureHash: $signatureHash")
Logger.log("Package ${packageInfo.packageName} isn't signed")
Logger.log("signatureHash: $signatureHash")
snackString("Package ${packageInfo.packageName} isn't 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> {
return try {
Log.e("NovelExtensionLoader", "isFileWritable: ${file.canWrite()}")
Logger.log("isFileWritable: ${file.canWrite()}")
if (file.canWrite()) {
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 className =
"some.random.novelextensions.${className.lowercase(Locale.getDefault())}.$className"

View file

@ -2,7 +2,7 @@ package ani.dantotsu.parsers.novel
import android.content.Context
import android.graphics.drawable.Drawable
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.snackString
import eu.kanade.tachiyomi.extension.InstallStep
import kotlinx.coroutines.flow.MutableStateFlow
@ -70,7 +70,7 @@ class NovelExtensionManager(private val context: Context) {
val extensions: List<NovelExtension.Available> = try {
api.findExtensions()
} catch (e: Exception) {
logger("Error finding extensions: ${e.message}")
Logger.log("Error finding extensions: ${e.message}")
withUIContext { snackString("Failed to get Novel extensions list") }
emptyList()
}

View file

@ -14,7 +14,7 @@ import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.AnilistQueries
import ani.dantotsu.connections.anilist.api.Activity
import ani.dantotsu.databinding.FragmentFeedBinding
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.profile.ProfileActivity
import ani.dantotsu.snackString
import com.xwray.groupie.GroupieAdapter

View file

@ -25,7 +25,7 @@ import androidx.viewpager2.widget.ViewPager2
import ani.dantotsu.R
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.databinding.FragmentAnimeExtensionsBinding
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.others.LanguageMapper
import ani.dantotsu.parsers.AnimeSources
import ani.dantotsu.settings.extensionprefs.AnimeSourcePreferencesFragment
@ -146,7 +146,7 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
},
{ error ->
Injekt.get<CrashlyticsInterface>().logException(error)
Log.e("AnimeExtensionsAdapter", "Error: ", error) // Log the error
Logger.log(error) // Log the error
val builder = NotificationCompat.Builder(
context,
Notifications.CHANNEL_DOWNLOADER_ERROR

View file

@ -32,6 +32,7 @@ import ani.dantotsu.settings.extensionprefs.MangaSourcePreferencesFragment
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import com.google.android.material.tabs.TabLayout
import com.google.android.material.textfield.TextInputLayout
import eu.kanade.tachiyomi.data.notification.Notifications
@ -143,7 +144,7 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
},
{ error ->
Injekt.get<CrashlyticsInterface>().logException(error)
Log.e("MangaExtensionsAdapter", "Error: ", error) // Log the error
Logger.log(error) // Log the error
val builder = NotificationCompat.Builder(
context,
Notifications.CHANNEL_DOWNLOADER_ERROR

View file

@ -30,6 +30,7 @@ import ani.dantotsu.parsers.novel.NovelExtensionManager
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import eu.kanade.tachiyomi.data.notification.Notifications
import kotlinx.coroutines.launch
import rx.android.schedulers.AndroidSchedulers
@ -72,7 +73,7 @@ class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler {
},
{ error ->
Injekt.get<CrashlyticsInterface>().logException(error)
Log.e("NovelExtensionsAdapter", "Error: ", error) // Log the error
Logger.log(error) // Log the error
val builder = NotificationCompat.Builder(
context,
Notifications.CHANNEL_DOWNLOADER_ERROR
@ -216,7 +217,7 @@ class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_extension, parent, false)
Log.d("NovelExtensionsAdapter", "onCreateViewHolder: $view")
Logger.log("onCreateViewHolder: $view")
return ViewHolder(view)
}

View file

@ -59,7 +59,6 @@ class NovelExtensionsFragment : Fragment(),
lifecycleScope.launch {
viewModel.pagerFlow.collectLatest { pagingData ->
Log.d("NovelExtensionsFragment", "collectLatest")
adapter.submitData(pagingData)
}
}

View file

@ -45,7 +45,7 @@ import ani.dantotsu.download.video.ExoplayerDownloadService
import ani.dantotsu.downloadsPermission
import ani.dantotsu.initActivity
import ani.dantotsu.loadImage
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.navBarHeight
import ani.dantotsu.openLinkInBrowser
import ani.dantotsu.others.AppUpdater
@ -730,6 +730,16 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
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 {
val title = getString(R.string.account_help)
val full = getString(R.string.full_account_help)
@ -884,7 +894,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
if (dialogTag == "colorPicker") {
val color = extras.getInt(SimpleColorDialog.COLOR)
PrefManager.setVal(PrefName.CustomThemeInt, color)
logger("Custom Theme: $color")
Logger.log("Custom Theme: $color")
}
}
return true

View file

@ -61,11 +61,7 @@ class AnimeSourcePreferencesFragment : PreferenceFragmentCompat() {
pref.isIconSpaceReserved = false
if (pref is DialogPreference) {
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
if (pref is EditTextPreference) {

View file

@ -159,6 +159,7 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
FirstComment(Pref(Location.Irrelevant, Boolean::class, true)),
CommentAuthResponse(Pref(Location.Irrelevant, AuthResponse::class, "")),
CommentTokenExpiry(Pref(Location.Irrelevant, Long::class, 0L)),
LogToFile(Pref(Location.Irrelevant, Boolean::class, false)),
//Protected
DiscordToken(Pref(Location.Protected, String::class, "")),

View file

@ -7,7 +7,7 @@ import android.content.Context
import android.content.Intent
import ani.dantotsu.currContext
import ani.dantotsu.isOnline
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.subcriptions.Subscription.Companion.defaultTime
@ -22,7 +22,7 @@ class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
when (intent?.action) {
Intent.ACTION_BOOT_COMPLETED -> tryWith(true) {
logger("Starting Dantotsu Subscription Service on Boot")
Logger.log("Starting Dantotsu Subscription Service on Boot")
context?.startSubscription()
}
}

View file

@ -10,6 +10,7 @@ import ani.dantotsu.parsers.Episode
import ani.dantotsu.parsers.MangaChapter
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.util.Logger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
@ -27,7 +28,7 @@ class Subscription {
alreadyStarted = true
SubscriptionWorker.enqueue(this)
AlarmReceiver.alarm(this)
} else logger("Already Subscribed")
} else Logger.log("Already Subscribed")
}
private var currentlyPerforming = false

View file

@ -0,0 +1,146 @@
package ani.dantotsu.util
import android.content.Context
import android.content.Intent
import androidx.core.content.FileProvider
import ani.dantotsu.BuildConfig
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.File
import java.util.Date
import java.util.concurrent.Executors
object Logger {
var file: File? = null
private val loggerExecutor = Executors.newSingleThreadExecutor()
fun init(context: Context) {
try {
if (!PrefManager.getVal<Boolean>(PrefName.LogToFile) || file != null) return
file = File(context.getExternalFilesDir(null), "log.txt")
if (file?.exists() == true) {
val oldFile = File(context.getExternalFilesDir(null), "old_log.txt")
file?.copyTo(oldFile, true)
} else {
file?.createNewFile()
}
file?.writeText("log started\n")
file?.appendText("date/time: ${Date()}\n")
file?.appendText("device: ${android.os.Build.MODEL}\n")
file?.appendText("os version: ${android.os.Build.VERSION.RELEASE}\n")
file?.appendText(
"app version: ${
context.packageManager.getPackageInfo(
context.packageName,
0
).versionName
}\n"
)
file?.appendText(
"app version code: ${
context.packageManager.getPackageInfo(
context.packageName,
0
).versionCode
}\n"
)
file?.appendText("sdk version: ${android.os.Build.VERSION.SDK_INT}\n")
file?.appendText("manufacturer: ${android.os.Build.MANUFACTURER}\n")
file?.appendText("brand: ${android.os.Build.BRAND}\n")
file?.appendText("product: ${android.os.Build.PRODUCT}\n")
file?.appendText("device: ${android.os.Build.DEVICE}\n")
file?.appendText("hardware: ${android.os.Build.HARDWARE}\n")
file?.appendText("host: ${android.os.Build.HOST}\n")
file?.appendText("id: ${android.os.Build.ID}\n")
file?.appendText("type: ${android.os.Build.TYPE}\n")
file?.appendText("user: ${android.os.Build.USER}\n")
file?.appendText("tags: ${android.os.Build.TAGS}\n")
file?.appendText("time: ${android.os.Build.TIME}\n")
file?.appendText("radio: ${android.os.Build.RADIO}\n")
file?.appendText("bootloader: ${android.os.Build.BOOTLOADER}\n")
file?.appendText("board: ${android.os.Build.BOARD}\n")
file?.appendText("fingerprint: ${android.os.Build.FINGERPRINT}\n")
file?.appendText("supported_abis: ${android.os.Build.SUPPORTED_ABIS.joinToString()}\n")
file?.appendText("supported_32_bit_abis: ${android.os.Build.SUPPORTED_32_BIT_ABIS.joinToString()}\n")
file?.appendText("supported_64_bit_abis: ${android.os.Build.SUPPORTED_64_BIT_ABIS.joinToString()}\n")
file?.appendText("is emulator: ${android.os.Build.FINGERPRINT.contains("generic")}\n")
file?.appendText("--------------------------------\n")
} catch (e: Exception) {
Injekt.get<CrashlyticsInterface>().logException(e)
file = null
}
}
fun log(message: String) {
val trace = Thread.currentThread().stackTrace[3]
loggerExecutor.execute {
if (file == null) println(message)
else {
val className = trace.className
val methodName = trace.methodName
val lineNumber = trace.lineNumber
file?.appendText("date/time: ${Date()} | $className.$methodName($lineNumber)\n")
file?.appendText("message: $message\n-\n")
}
}
}
fun log(e: Exception) {
loggerExecutor.execute {
if (file == null) e.printStackTrace() else {
file?.appendText("---------------------------Exception---------------------------\n")
file?.appendText("date/time: ${Date()} | ${e.message}\n")
file?.appendText("trace: ${e.stackTrace}\n")
}
}
}
fun log(e: Throwable) {
loggerExecutor.execute {
if (file == null) e.printStackTrace() else {
file?.appendText("---------------------------Exception---------------------------\n")
file?.appendText("date/time: ${Date()} | ${e.message}\n")
file?.appendText("trace: ${e.stackTrace}\n")
}
}
}
fun shareLog(context: Context) {
if (file == null) {
snackString("No log file found")
return
}
val oldFile = File(context.getExternalFilesDir(null), "old_log.txt")
val fileToUse = if (oldFile.exists()) {
file?.readText()?.let { oldFile.appendText(it) }
oldFile
} else {
file
}
val shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.type = "text/plain"
shareIntent.putExtra(
Intent.EXTRA_STREAM,
FileProvider.getUriForFile(context, "${BuildConfig.APPLICATION_ID}.provider", fileToUse!!)
)
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "Log file")
shareIntent.putExtra(Intent.EXTRA_TEXT, "Log file")
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
context.startActivity(Intent.createChooser(shareIntent, "Share log file"))
}
}
class FinalExceptionHandler : Thread.UncaughtExceptionHandler {
private val defaultUEH: Thread.UncaughtExceptionHandler? =
Thread.getDefaultUncaughtExceptionHandler()
override fun uncaughtException(t: Thread, e: Throwable) {
Logger.log(e)
Injekt.get<CrashlyticsInterface>().logException(e)
defaultUEH?.uncaughtException(t, e)
}
}

View file

@ -7,7 +7,7 @@ import android.graphics.BitmapFactory
import android.widget.RemoteViews
import android.widget.RemoteViewsService
import ani.dantotsu.R
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
import java.io.InputStream
import java.net.HttpURLConnection
import java.net.URL
@ -19,7 +19,7 @@ class CurrentlyAiringRemoteViewsFactory(private val context: Context, intent: In
override fun onCreate() {
// 4 items for testing
widgetItems.clear()
logger("CurrentlyAiringRemoteViewsFactory onCreate")
Logger.log("CurrentlyAiringRemoteViewsFactory onCreate")
widgetItems = List(4) {
WidgetItem(
"Show $it",
@ -31,7 +31,7 @@ class CurrentlyAiringRemoteViewsFactory(private val context: Context, intent: In
override fun onDataSetChanged() {
// 4 items for testing
logger("CurrentlyAiringRemoteViewsFactory onDataSetChanged")
Logger.log("CurrentlyAiringRemoteViewsFactory onDataSetChanged")
widgetItems.clear()
widgetItems.add(
WidgetItem(
@ -79,7 +79,7 @@ class CurrentlyAiringRemoteViewsFactory(private val context: Context, intent: In
}
override fun getViewAt(position: Int): RemoteViews {
logger("CurrentlyAiringRemoteViewsFactory getViewAt")
Logger.log("CurrentlyAiringRemoteViewsFactory getViewAt")
val item = widgetItems[position]
val rv = RemoteViews(context.packageName, R.layout.item_currently_airing_widget).apply {
setTextViewText(R.id.text_show_title, item.title)

View file

@ -2,11 +2,11 @@ package ani.dantotsu.widgets
import android.content.Intent
import android.widget.RemoteViewsService
import ani.dantotsu.logger
import ani.dantotsu.util.Logger
class CurrentlyAiringRemoteViewsService : RemoteViewsService() {
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
logger("CurrentlyAiringRemoteViewsFactory onGetViewFactory")
Logger.log("CurrentlyAiringRemoteViewsFactory onGetViewFactory")
return CurrentlyAiringRemoteViewsFactory(applicationContext, intent)
}
}

View file

@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.extension.anime
import android.content.Context
import android.graphics.drawable.Drawable
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.tachiyomi.extension.InstallStep
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.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import logcat.LogPriority
import rx.Observable
import tachiyomi.core.util.lang.launchNow
import tachiyomi.core.util.lang.withUIContext
import tachiyomi.core.util.system.logcat
import tachiyomi.domain.source.anime.model.AnimeSourceData
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -120,7 +119,7 @@ class AnimeExtensionManager(
val extensions: List<AnimeExtension.Available> = try {
api.findExtensions()
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
Logger.log(e)
withUIContext { snackString("Failed to get extensions list") }
emptyList()
}

View file

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.extension.anime.api
import android.content.Context
import ani.dantotsu.util.Logger
import eu.kanade.tachiyomi.extension.ExtensionUpdateNotifier
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
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 kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import logcat.LogPriority
import tachiyomi.core.preference.Preference
import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.util.lang.withIOContext
import tachiyomi.core.util.system.logcat
import uy.kohesive.injekt.injectLazy
import java.util.Date
import kotlin.time.Duration.Companion.days
@ -45,7 +44,7 @@ internal class AnimeExtensionGithubApi {
.newCall(GET("${REPO_URL_PREFIX}index.min.json"))
.awaitSuccess()
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e) { "Failed to get extensions from GitHub" }
Logger.log("Failed to get extensions from GitHub")
requiresFallbackSource = true
null
}

View file

@ -10,12 +10,11 @@ import android.content.pm.PackageInstaller
import android.os.Build
import androidx.core.content.ContextCompat
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import eu.kanade.tachiyomi.extension.InstallStep
import eu.kanade.tachiyomi.util.lang.use
import eu.kanade.tachiyomi.util.system.getParcelableExtraCompat
import eu.kanade.tachiyomi.util.system.getUriSize
import logcat.LogPriority
import tachiyomi.core.util.system.logcat
class PackageInstallerInstallerAnime(private val service: Service) : InstallerAnime(service) {
@ -30,7 +29,7 @@ class PackageInstallerInstallerAnime(private val service: Service) : InstallerAn
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
val userAction = intent.getParcelableExtraCompat<Intent>(Intent.EXTRA_INTENT)
if (userAction == null) {
logcat(LogPriority.ERROR) { "Fatal error for $intent" }
Logger.log("Fatal error for $intent")
continueQueue(InstallStep.Error)
return
}
@ -89,11 +88,8 @@ class PackageInstallerInstallerAnime(private val service: Service) : InstallerAn
session.commit(intentSender)
}
} catch (e: Exception) {
logcat(
LogPriority.ERROR,
e
) { "Failed to install extension ${entry.downloadId} ${entry.uri}" }
logcat(LogPriority.ERROR) { "Exception: $e" }
Logger.log(e)
Logger.log("Failed to install extension ${entry.downloadId} ${entry.uri}")
snackString("Failed to install extension ${entry.downloadId} ${entry.uri}")
activeSession?.let { (_, sessionId) ->
packageInstaller.abandonSession(sessionId)

View file

@ -5,15 +5,14 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
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.AnimeLoadResult
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import logcat.LogPriority
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
@ -103,7 +102,7 @@ internal class AnimeExtensionInstallReceiver(private val listener: Listener) :
private suspend fun getExtensionFromIntent(context: Context, intent: Intent?): AnimeLoadResult {
val pkgName = getPackageNameFromIntent(intent)
if (pkgName == null) {
logcat(LogPriority.WARN) { "Package name not found" }
Logger.log("Package name not found")
return AnimeLoadResult.Error
}
return GlobalScope.async(Dispatchers.Default, CoroutineStart.DEFAULT) {

View file

@ -8,6 +8,7 @@ import android.net.Uri
import android.os.Build
import android.os.IBinder
import ani.dantotsu.R
import ani.dantotsu.util.Logger
import eu.kanade.domain.base.BasePreferences
import eu.kanade.tachiyomi.data.notification.Notifications
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.util.system.getSerializableExtraCompat
import eu.kanade.tachiyomi.util.system.notificationBuilder
import logcat.LogPriority
import tachiyomi.core.util.system.logcat
class AnimeExtensionInstallService : Service() {
@ -60,7 +59,7 @@ class AnimeExtensionInstallService : Service() {
)
else -> {
logcat(LogPriority.ERROR) { "Not implemented for installer $installerUsed" }
Logger.log("Not implemented for installer $installerUsed")
stopSelf()
return START_NOT_STICKY
}

View file

@ -10,16 +10,15 @@ import android.os.Environment
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.net.toUri
import ani.dantotsu.util.Logger
import com.jakewharton.rxrelay.PublishRelay
import eu.kanade.domain.base.BasePreferences
import eu.kanade.tachiyomi.extension.InstallStep
import eu.kanade.tachiyomi.extension.anime.installer.InstallerAnime
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
import eu.kanade.tachiyomi.util.storage.getUriCompat
import logcat.LogPriority
import rx.Observable
import rx.android.schedulers.AndroidSchedulers
import tachiyomi.core.util.system.logcat
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.File
@ -248,7 +247,7 @@ internal class AnimeExtensionInstaller(private val context: Context) {
// Set next installation step
if (uri == null) {
logcat(LogPriority.ERROR) { "Couldn't locate downloaded APK" }
Logger.log("Couldn't locate downloaded APK")
downloadsRelay.call(id to InstallStep.Error)
return
}

View file

@ -6,6 +6,7 @@ import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.content.pm.PackageInfoCompat
import ani.dantotsu.util.Logger
import dalvik.system.PathClassLoader
import eu.kanade.domain.source.service.SourcePreferences
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 kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import logcat.LogPriority
import tachiyomi.core.util.system.logcat
import uy.kohesive.injekt.injectLazy
/**
@ -91,11 +90,11 @@ internal object AnimeExtensionLoader {
context.packageManager.getPackageInfo(pkgName, PACKAGE_FLAGS)
} catch (error: PackageManager.NameNotFoundException) {
// Unlikely, but the package may have been uninstalled at this point
logcat(LogPriority.ERROR, error)
Logger.log(error)
return AnimeLoadResult.Error
}
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 loadExtension(context, pkgName, pkgInfo)
@ -119,7 +118,7 @@ internal object AnimeExtensionLoader {
pkgManager.getApplicationInfo(pkgName, PackageManager.GET_META_DATA)
} catch (error: PackageManager.NameNotFoundException) {
// Unlikely, but the package may have been uninstalled at this point
logcat(LogPriority.ERROR, error)
Logger.log(error)
return AnimeLoadResult.Error
}
@ -128,24 +127,23 @@ internal object AnimeExtensionLoader {
val versionCode = PackageInfoCompat.getLongVersionCode(pkgInfo)
if (versionName.isNullOrEmpty()) {
logcat(LogPriority.WARN) { "Missing versionName for extension $extName" }
Logger.log("Missing versionName for extension $extName")
return AnimeLoadResult.Error
}
// Validate lib version
val libVersion = versionName.substringBeforeLast('.').toDoubleOrNull()
if (libVersion == null || libVersion < LIB_VERSION_MIN || libVersion > LIB_VERSION_MAX) {
logcat(LogPriority.WARN) {
"Lib version is $libVersion, while only versions " +
Logger.log("Lib version is $libVersion, while only versions " +
"$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed"
}
)
return AnimeLoadResult.Error
}
val signatureHash = getSignatureHash(pkgInfo)
if (signatureHash == null) {
logcat(LogPriority.WARN) { "Package $pkgName isn't signed" }
Logger.log("Package $pkgName isn't signed")
return AnimeLoadResult.Error
} else if (signatureHash !in trustedSignatures) {
val extension = AnimeExtension.Untrusted(
@ -156,13 +154,13 @@ internal object AnimeExtensionLoader {
libVersion,
signatureHash
)
logcat(LogPriority.WARN, message = { "Extension $pkgName isn't trusted" })
Logger.log("Extension $pkgName isn't trusted")
return AnimeLoadResult.Untrusted(extension)
}
val isNsfw = appInfo.metaData.getInt(METADATA_NSFW) == 1
if (!loadNsfwSource && isNsfw) {
logcat(LogPriority.WARN) { "NSFW extension $pkgName not allowed" }
Logger.log("NSFW extension $pkgName not allowed")
return AnimeLoadResult.Error
}
@ -189,7 +187,7 @@ internal object AnimeExtensionLoader {
else -> throw Exception("Unknown source class type! ${obj.javaClass}")
}
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e) { "Extension load error: $extName ($it)" }
Logger.log("Extension load error: $extName ($it)")
return AnimeLoadResult.Error
}
}

View file

@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.extension.manga
import android.content.Context
import android.graphics.drawable.Drawable
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.tachiyomi.extension.InstallStep
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.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import logcat.LogPriority
import rx.Observable
import tachiyomi.core.util.lang.launchNow
import tachiyomi.core.util.lang.withUIContext
import tachiyomi.core.util.system.logcat
import tachiyomi.domain.source.manga.model.MangaSourceData
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -117,7 +116,7 @@ class MangaExtensionManager(
val extensions: List<MangaExtension.Available> = try {
api.findExtensions()
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
Logger.log(e)
withUIContext { snackString("Failed to get manga extensions") }
emptyList()
}

View file

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.extension.manga.api
import android.content.Context
import ani.dantotsu.util.Logger
import eu.kanade.tachiyomi.extension.ExtensionUpdateNotifier
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
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 kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import logcat.LogPriority
import tachiyomi.core.preference.Preference
import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.util.lang.withIOContext
import tachiyomi.core.util.system.logcat
import uy.kohesive.injekt.injectLazy
import java.util.Date
import kotlin.time.Duration.Companion.days
@ -45,7 +44,7 @@ internal class MangaExtensionGithubApi {
.newCall(GET("${REPO_URL_PREFIX}index.min.json"))
.awaitSuccess()
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e) { "Failed to get extensions from GitHub" }
Logger.log("Failed to get extensions from GitHub")
requiresFallbackSource = true
null
}

View file

@ -10,12 +10,11 @@ import android.content.pm.PackageInstaller
import android.os.Build
import androidx.core.content.ContextCompat
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import eu.kanade.tachiyomi.extension.InstallStep
import eu.kanade.tachiyomi.util.lang.use
import eu.kanade.tachiyomi.util.system.getParcelableExtraCompat
import eu.kanade.tachiyomi.util.system.getUriSize
import logcat.LogPriority
import tachiyomi.core.util.system.logcat
class PackageInstallerInstallerManga(private val service: Service) : InstallerManga(service) {
@ -30,7 +29,7 @@ class PackageInstallerInstallerManga(private val service: Service) : InstallerMa
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
val userAction = intent.getParcelableExtraCompat<Intent>(Intent.EXTRA_INTENT)
if (userAction == null) {
logcat(LogPriority.ERROR) { "Fatal error for $intent" }
Logger.log("Fatal error for $intent")
continueQueue(InstallStep.Error)
return
}
@ -89,8 +88,8 @@ class PackageInstallerInstallerManga(private val service: Service) : InstallerMa
session.commit(intentSender)
}
} catch (e: Exception) {
logcat(LogPriority.ERROR) { "Failed to install extension ${entry.downloadId} ${entry.uri}" }
logcat(LogPriority.ERROR) { "Exception: $e" }
Logger.log("Failed to install extension ${entry.downloadId} ${entry.uri}")
Logger.log(e)
snackString("Failed to install extension ${entry.downloadId} ${entry.uri}")
activeSession?.let { (_, sessionId) ->
packageInstaller.abandonSession(sessionId)

View file

@ -5,15 +5,14 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
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.MangaLoadResult
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import logcat.LogPriority
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
@ -103,7 +102,7 @@ internal class MangaExtensionInstallReceiver(private val listener: Listener) :
private suspend fun getExtensionFromIntent(context: Context, intent: Intent?): MangaLoadResult {
val pkgName = getPackageNameFromIntent(intent)
if (pkgName == null) {
logcat(LogPriority.WARN) { "Package name not found" }
Logger.log("Package name not found")
return MangaLoadResult.Error
}
return GlobalScope.async(Dispatchers.Default, CoroutineStart.DEFAULT) {

View file

@ -8,6 +8,7 @@ import android.net.Uri
import android.os.Build
import android.os.IBinder
import ani.dantotsu.R
import ani.dantotsu.util.Logger
import eu.kanade.domain.base.BasePreferences
import eu.kanade.tachiyomi.data.notification.Notifications
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.util.system.getSerializableExtraCompat
import eu.kanade.tachiyomi.util.system.notificationBuilder
import logcat.LogPriority
import tachiyomi.core.util.system.logcat
class MangaExtensionInstallService : Service() {
@ -60,7 +59,7 @@ class MangaExtensionInstallService : Service() {
)
else -> {
logcat(LogPriority.ERROR) { "Not implemented for installer $installerUsed" }
Logger.log("Not implemented for installer $installerUsed")
stopSelf()
return START_NOT_STICKY
}

View file

@ -10,16 +10,15 @@ import android.os.Environment
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.net.toUri
import ani.dantotsu.util.Logger
import com.jakewharton.rxrelay.PublishRelay
import eu.kanade.domain.base.BasePreferences
import eu.kanade.tachiyomi.extension.InstallStep
import eu.kanade.tachiyomi.extension.manga.installer.InstallerManga
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
import eu.kanade.tachiyomi.util.storage.getUriCompat
import logcat.LogPriority
import rx.Observable
import rx.android.schedulers.AndroidSchedulers
import tachiyomi.core.util.system.logcat
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.File
@ -245,7 +244,7 @@ internal class MangaExtensionInstaller(private val context: Context) {
// Set next installation step
if (uri == null) {
logcat(LogPriority.ERROR) { "Couldn't locate downloaded APK" }
Logger.log("Couldn't locate downloaded APK")
downloadsRelay.call(id to InstallStep.Error)
return
}

View file

@ -6,6 +6,7 @@ import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.content.pm.PackageInfoCompat
import ani.dantotsu.util.Logger
import dalvik.system.PathClassLoader
import eu.kanade.domain.source.service.SourcePreferences
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 kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import logcat.LogPriority
import tachiyomi.core.util.system.logcat
import uy.kohesive.injekt.injectLazy
/**
@ -91,11 +90,11 @@ internal object MangaExtensionLoader {
context.packageManager.getPackageInfo(pkgName, PACKAGE_FLAGS)
} catch (error: PackageManager.NameNotFoundException) {
// Unlikely, but the package may have been uninstalled at this point
logcat(LogPriority.ERROR, error)
Logger.log(error)
return MangaLoadResult.Error
}
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 loadMangaExtension(context, pkgName, pkgInfo)
@ -119,7 +118,7 @@ internal object MangaExtensionLoader {
pkgManager.getApplicationInfo(pkgName, PackageManager.GET_META_DATA)
} catch (error: PackageManager.NameNotFoundException) {
// Unlikely, but the package may have been uninstalled at this point
logcat(LogPriority.ERROR, error)
Logger.log(error)
return MangaLoadResult.Error
}
@ -129,17 +128,16 @@ internal object MangaExtensionLoader {
val versionCode = PackageInfoCompat.getLongVersionCode(pkgInfo)
if (versionName.isNullOrEmpty()) {
logcat(LogPriority.WARN) { "Missing versionName for extension $extName" }
Logger.log("Missing versionName for extension $extName")
return MangaLoadResult.Error
}
// Validate lib version
val libVersion = versionName.substringBeforeLast('.').toDoubleOrNull()
if (libVersion == null || libVersion < LIB_VERSION_MIN || libVersion > LIB_VERSION_MAX) {
logcat(LogPriority.WARN) {
"Lib version is $libVersion, while only versions " +
Logger.log("Lib version is $libVersion, while only versions " +
"$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed"
}
)
return MangaLoadResult.Error
}
@ -147,18 +145,18 @@ internal object MangaExtensionLoader {
/* temporarily disabling signature check TODO: remove?
if (signatureHash == null) {
logcat(LogPriority.WARN) { "Package $pkgName isn't signed" }
Logger.log("Package $pkgName isn't signed")
return MangaLoadResult.Error
} else if (signatureHash !in trustedSignatures) {
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)
}
*/
val isNsfw = appInfo.metaData.getInt(METADATA_NSFW) == 1
if (!loadNsfwSource && isNsfw) {
logcat(LogPriority.WARN) { "NSFW extension $pkgName not allowed" }
Logger.log("NSFW extension $pkgName not allowed")
return MangaLoadResult.Error
}
@ -185,7 +183,7 @@ internal object MangaExtensionLoader {
else -> throw Exception("Unknown source class type! ${obj.javaClass}")
}
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e) { "Extension load error: $extName ($it)" }
Logger.log("Extension load error: $extName ($it)")
return MangaLoadResult.Error
}
}

View file

@ -21,10 +21,9 @@ import androidx.core.graphics.blue
import androidx.core.graphics.green
import androidx.core.graphics.red
import androidx.core.net.toUri
import ani.dantotsu.util.Logger
import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.util.lang.truncateCenter
import logcat.LogPriority
import tachiyomi.core.util.system.logcat
import java.io.File
import kotlin.math.roundToInt
@ -47,7 +46,7 @@ fun Context.copyToClipboard(label: String, content: String) {
toast("Copied to clipboard: " + content.truncateCenter(50))
}
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e)
Logger.log(e)
toast("Failed to copy to clipboard")
}
}

View file

@ -2,8 +2,7 @@ package eu.kanade.tachiyomi.util.system
import android.annotation.SuppressLint
import android.os.Build
import logcat.LogPriority
import tachiyomi.core.util.system.logcat
import ani.dantotsu.util.Logger
object DeviceUtil {
@ -72,7 +71,7 @@ object DeviceUtil {
.getDeclaredMethod("get", String::class.java)
.invoke(null, key) as String
} catch (e: Exception) {
logcat(LogPriority.WARN, e) { "Unable to use SystemProperties.get()" }
Logger.log("Unable to use SystemProperties.get()")
null
}
}

View file

@ -6,8 +6,7 @@ import android.content.pm.PackageManager
import android.webkit.CookieManager
import android.webkit.WebSettings
import android.webkit.WebView
import logcat.LogPriority
import tachiyomi.core.util.system.logcat
import ani.dantotsu.util.Logger
object WebViewUtil {
const val SPOOF_PACKAGE_NAME = "org.chromium.chrome"
@ -20,7 +19,7 @@ object WebViewUtil {
// is not installed
CookieManager.getInstance()
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e)
Logger.log(e)
return false
}