Open MrBoomDeveloper opened 7 months ago
do you think this will work? this is mangaplus API actual code of abandonedcart has used mangaupdates API
package ani.dantotsu.connections.mangaplus
import android.content.Context
import ani.dantotsu.R
import ani.dantotsu.client
import ani.dantotsu.media.Media
import ani.dantotsu.tryWithSuspend
import ani.dantotsu.util.Logger
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import org.json.JSONException
import org.json.JSONObject
import org.jsoup.Jsoup
import java.io.IOException
import java.net.URLEncoder
import java.nio.charset.Charset
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import java.util.TimeZone
import java.util.concurrent.TimeUnit
class MangaPlusAPI {
val String.utf8: String get() = URLEncoder.encode(this, Charset.forName("UTF-8").name())
private val Int?.dateFormat get() = String.format("%02d", this)
suspend fun findLatestRelease(media: Media): ReleaseResponse.Results? {
return tryWithSuspend {
val query = JSONObject().apply {
try {
put("title", media.mangaName().utf8)
media.startDate?.let {
put(
"start_date",
"${it.year}-${it.month.dateFormat}-${it.day.dateFormat}"
)
}
} catch (e: JSONException) {
e.printStackTrace()
}
}
val res = client.post(
"https://mangaplus.shueisha.co.jp/api/series/${media.mangaName().utf8}",
json = query
).parsed<ReleaseResponse>()
coroutineScope {
res.data?.map {
async(Dispatchers.IO) {
Logger.log(it.toString())
}
}
}?.awaitAll()
res.data?.firstOrNull()
}
}
suspend fun getSeries(results: ReleaseResponse.Results): SeriesResponse? {
return tryWithSuspend {
val res = client.get(
"https://mangaplus.shueisha.co.jp/api/manga/${results.titleId}"
).parsed<SeriesResponse>()
Logger.log(res.toString())
res.latestChapter?.let { res }
}
}
fun getLatestChapter(context: Context, results: ReleaseResponse.Results): String {
return context.getString(R.string.chapter_number, results.titleLastChapter)
}
private suspend fun findReleaseDates(media: Media): List<String> {
val releaseList = hashMapOf<String, String>()
return tryWithSuspend {
val query = JSONObject().apply {
try {
put("title", media.mangaName().utf8)
media.startDate?.let {
put(
"start_date",
"${it.year}-${it.month.dateFormat}-${it.day.dateFormat}"
)
}
} catch (e: JSONException) {
e.printStackTrace()
}
}
val res = client.post(
"https://mangaplus.shueisha.co.jp/api/series/${media.mangaName().utf8}",
json = query
).parsed<ReleaseResponse>()
res.data?.filter {
it.releaseDate != null
}?.sortedByDescending { it.releaseDate }?.forEach {
releaseList[it.titleLastChapter] = it.releaseDate!!
Logger.log(it.toString())
}
releaseList.values.toList().sortedDescending()
} ?: releaseList.values.toList()
}
private fun getCalendarInstance(releaseDate: String): Calendar {
val calendar: Calendar = Calendar.getInstance()
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.ROOT)
calendar.timeZone = TimeZone.getDefault()
dateFormat.parse(releaseDate)?.let { calendar.time = it }
return calendar
}
suspend fun predictRelease(media: Media, latest: Long): Long? {
val releaseDates = findReleaseDates(media)
if (releaseDates.size < 5) return null
releaseDates.forEach {
Logger.log(it)
}
val date01 = getCalendarInstance(releaseDates[0])
val date02 = getCalendarInstance(releaseDates[1])
val date03 = getCalendarInstance(releaseDates[2])
val date04 = getCalendarInstance(releaseDates[3])
val date05 = getCalendarInstance(releaseDates[4])
val days0102: Long = TimeUnit.MILLISECONDS.toDays(date01.timeInMillis - date02.timeInMillis)
val days0203: Long = TimeUnit.MILLISECONDS.toDays(date02.timeInMillis - date03.timeInMillis)
val days0304: Long = TimeUnit.MILLISECONDS.toDays(date03.timeInMillis - date04.timeInMillis)
val days0405: Long = TimeUnit.MILLISECONDS.toDays(date04.timeInMillis - date05.timeInMillis)
val average = (days0102 + days0203 + days0304 + days0405) / 4
val date: Calendar = Calendar.getInstance()
date.timeInMillis = latest
return when {
average in 5..14 -> {
latest + 604800000 // 7 days
}
average in 28..36 -> {
date.add(Calendar.MONTH, 1)
date.timeInMillis
}
average in 84..98 -> {
date.add(Calendar.MONTH, 3)
date.timeInMillis
}
average >= 358 -> {
date.add(Calendar.YEAR, 1)
date.timeInMillis
}
else -> {
null
}
}
}
@Serializable
data class ReleaseResponse(
val data: List<Data>?
) {
@Serializable
data class Data(
val titleId: String,
val title: String,
val titleLastChapter: String,
val releaseDate: String?
)
}
@Serializable
data class SeriesResponse(
val titleId: String,
val title: String,
val titleEn: String?,
val titleUrl: String?,
val summary: String?,
val thumbnailUrl: String?,
val author: String?,
val updateDay: String?,
val isSerializing: Boolean,
val firstChapterAt: String?,
val lastChapterAt: String?,
val viewCount: Int?,
val favoriteCount: Int?,
val pageViewCount: Int?,
val shareCount: Int?,
val episodeCount: Int?,
val latestChapter: String?,
val isLatestChapter: Boolean
)
suspend fun scrapeMangaInfo(mangaUrl: String): MangaInfo? {
return try {
val doc = Jsoup.connect(mangaUrl).get()
val title = doc.select("h1.title").text()
val latestChapter = doc.select("div.chapter-btn").first()?.text()
val summary = doc.select("div#introduction-detail").text()
val thumbnailUrl = doc.select("img.lazyload").attr("data-src")
MangaInfo(title, latestChapter, summary, thumbnailUrl)
} catch (e: IOException) {
Logger.logError("Error scraping manga information: ${e.message}")
null
}
}
data class MangaInfo(
val title: String,
val latestChapter: String?,
val summary: String?,
val thumbnailUrl: String?
)
}
@minsoramune We can first ask the user to get a list of chapters from some source, and then, based on the release dates of the chapters, display the approximate date of the next one using the average duration between their release dates.
@minsoramune We can first ask the user to get a list of chapters from some source, and then, based on the release dates of the chapters, display the approximate date of the next one using the average duration between their release dates.
Yh main code gets info from the scanlators if I'm not wrong