Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.work.WorkManager
import androidx.work.WorkerParameters
import com.lagradost.quicknovel.BookDownloader2Helper.IMPORT_SOURCE
import com.lagradost.quicknovel.BookDownloader2Helper.IMPORT_SOURCE_PDF
import com.lagradost.quicknovel.mvvm.logError
import com.lagradost.quicknovel.ui.download.DownloadFragment
import com.lagradost.quicknovel.ui.download.DownloadViewModel
import com.lagradost.quicknovel.util.Apis
Expand Down Expand Up @@ -76,7 +77,17 @@ class DownloadFileWorkManager(val context: Context, private val workerParams: Wo
fun refreshAllReadingProgress(from: DownloadViewModel, context: Context, currentTab: Int) {
viewModel = from
val uniqueWorkName = "${ID_REFRESH_READINGPROGRESS}_$currentTab"
(WorkManager.getInstance(context)).enqueueUniqueWork(

val workManager = try {
WorkManager.getInstance(context.applicationContext)
} catch (t: Throwable) {
logError(t)
val config = androidx.work.Configuration.Builder().build()
WorkManager.initialize(context.applicationContext, config)
WorkManager.getInstance(context.applicationContext)
}

workManager.enqueueUniqueWork(
uniqueWorkName,
ExistingWorkPolicy.KEEP,
OneTimeWorkRequest.Builder(DownloadFileWorkManager::class.java)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ import java.util.Locale
import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import kotlin.math.pow
import kotlin.reflect.KClass
import kotlin.reflect.KProperty

Expand Down Expand Up @@ -372,9 +371,16 @@ class RegularBook(val data: EpubBook) : AbstractBook() {

doc.select("img, image").forEach { img ->
val attrName = if (img.tagName() == "image") "xlink:href" else "src"
val src = img.attr(attrName)
var src = img.attr(attrName)
if (src.isNotEmpty() && !src.startsWith("http") && !src.startsWith("data:")) {
img.attr(attrName, resolveRelativePath(basePath, src))
src = resolveRelativePath(basePath, src)
}
if (img.tagName() == "image") {
val newImg = doc.createElement("img")
newImg.attr("src", src)
img.replaceWith(newImg)
} else {
img.attr("src", src)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class AnnasArchive : MainAPI() {
override val hasReviews = false
override val lang = "en"
override val name = "Annas Archive"
override val mainUrl = "https://annas-archive.li"
override val mainUrl = "https://annas-archive.pk"

//open val searchTags = "lang=en&content=book_fiction&ext=epub&sort=&"

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package com.lagradost.quicknovel.providers

import android.net.Uri
import com.lagradost.quicknovel.ChapterData
import com.lagradost.quicknovel.HeadMainPageResponse
import com.lagradost.quicknovel.LoadResponse
import com.lagradost.quicknovel.MainAPI
import com.lagradost.quicknovel.MainActivity.Companion.app
import com.lagradost.quicknovel.R
import com.lagradost.quicknovel.SearchResponse
import com.lagradost.quicknovel.newChapterData
import com.lagradost.quicknovel.newSearchResponse
import com.lagradost.quicknovel.newStreamResponse
import org.jsoup.nodes.Document

class DevilNovelsProvider : MainAPI() {

override val name = "DevilNovels"
override val mainUrl = "https://devilnovels.com"
override val iconId = R.drawable.icon_devilnovels
override val lang = "es"
override val hasMainPage = true

override suspend fun loadMainPage(
page: Int,
mainCategory: String?,
orderBy: String?,
tag: String?
): HeadMainPageResponse {

val url = "$mainUrl/listado-de-novelas/"
val document = app.get(url).document

val items = document.select("div.pvc-featured-pages-grid > div.pvc-featured-page-item").mapNotNull { card ->
val href = card.selectFirst("a")?.attr("href") ?: return@mapNotNull null
val title = card.selectFirst("p")?.text() ?: return@mapNotNull null

newSearchResponse(title, href) {
posterUrl = card.selectFirst("img")?.attr("src")
}
}

return HeadMainPageResponse(url, items)
}

private suspend fun getChapters(document: Document, url: String): List<ChapterData> {
val pagination = document.select("nav.elementor-pagination a.page-numbers")
if (pagination.size > 1) {
val lastPageElement = pagination[pagination.size - 1]
val lastPageNumber = lastPageElement.ownText().toIntOrNull() ?: 1

val lastPageUrl = "$url/?e-page-bc939d8=$lastPageNumber"
val lastPageDoc = app.get(lastPageUrl).document
val lastTotalChapters = lastPageDoc.select("div.elementor-posts-container > article").size
val totalChapters = ((lastPageNumber - 1) * 100) + lastTotalChapters

return (0..< totalChapters).map { chapterNumber ->
newChapterData("Chapter ${chapterNumber + 1}", "$url--------$chapterNumber")
}
}

return document.select("div.elementor-posts-container > article").mapNotNull { li ->
val name = li.selectFirst("a")?.text() ?: return@mapNotNull null
val url = li.selectFirst("a")?.attr("href") ?: return@mapNotNull null
newChapterData(name, url)
}
}


override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
val chapters = getChapters(document, url)

return newStreamResponse(document.selectFirst("div.elementor-widget-container p")?.text() ?: "", url, chapters) {
this.posterUrl = document.selectFirst("div.elementor-widget-container > p > img")?.attr("src")
this.synopsis = document.select("div.elementor-widget-container > p")?.drop(1)?.joinToString("\n"){it.text()}
this.author = author
this.tags = tags
}
}

private suspend fun getSpecificChapter(url:String, number:Int):String{
val page = (number + 100 - 1)/100
val document = app.get("$url/?e-page-bc939d8=$page").document
val realNumber = number % 100
val chapter = document.select("div.elementor-posts-container > article")[realNumber]
return chapter.selectFirst("a")?.attr("href") ?: ""
}

override suspend fun loadHtml(url: String): String? {
var newUrl = url
val chapterNumber = url.split("--------")
if(chapterNumber.size > 1) {
newUrl = getSpecificChapter(chapterNumber[0],chapterNumber[1].toInt())
}

val document = app.get(newUrl).document
val content = document.select("div.ast-post-format- > div.entry-content > p")
?.joinToString("</br>") { it.html() }
return content
}

override suspend fun search(query: String): List<SearchResponse> {
val url = "$mainUrl/?post_type=page&s=${Uri.encode(query)}"
val document = app.get(url).document

return document.select("main#main > div > article").mapNotNull { card ->
val href = card.selectFirst("a")?.attr("href") ?: return@mapNotNull null
val title = card.selectFirst("h2")?.text() ?: return@mapNotNull null

newSearchResponse(title, href) {
posterUrl = card.selectFirst("img")?.attr("src")
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
package com.lagradost.quicknovel.providers

import com.lagradost.quicknovel.HeadMainPageResponse
import com.lagradost.quicknovel.LoadResponse
import com.lagradost.quicknovel.MainAPI
import com.lagradost.quicknovel.MainActivity.Companion.app
import com.lagradost.quicknovel.R
import com.lagradost.quicknovel.SearchResponse
import com.lagradost.quicknovel.fixUrlNull
import com.lagradost.quicknovel.newSearchResponse
import com.lagradost.quicknovel.newStreamResponse
import com.lagradost.quicknovel.setStatus
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.quicknovel.newChapterData
import kotlin.collections.map

class FenrirRealProvider: MainAPI() {
override val name = "FenrirRealm"
override val mainUrl = "https://fenrirealm.com"
override val iconId = R.drawable.icon_fenrirealm
override val hasMainPage = true
override val rateLimitTime = 500L

override val mainCategories = listOf(
"All" to "any",
"Completed" to "completed",
"Ongoing" to "on-going"
)
override val orderBys =
listOf(
"Popular" to "popular",
"Latest" to "latest",
"Updated" to "updated"
)
override val tags = listOf(
"All" to "0",
"Action" to "1",
"Adult" to "2",
"Adventure" to "3",
"Comedy" to "4",
"Drama" to "5",
"Ecchi" to "6",
"Fantasy" to "7",
"Gender Bender" to "8",
"Harem" to "9",
"Historical" to "10",
"Horror" to "11",
"Josei" to "12",
"Martial Arts" to "13",
"Mature" to "14",
"Mecha" to "15",
"Mystery" to "16",
"Psychological" to "17",
"Romance" to "18",
"School Life" to "19",
"Sci-fi" to "20",
"Seinen" to "21",
"Shoujo" to "22",
"Shoujo Ai" to "23",
"Shounen" to "24",
"Shounen Ai" to "25",
"Slice of Life" to "26",
"Smut" to "27",
"Sports" to "28",
"Supernatural" to "29",
"Tragedy" to "30",
"Wuxia" to "31",
"Xianxia" to "32",
"Xuanhuan" to "33",
"Yaoi" to "34",
"Yuri" to "35",
)

fun String.getSlugFromUrl() = this.replace("$mainUrl/series/", "")

override suspend fun loadMainPage(
page: Int,
mainCategory: String?,
orderBy: String?,
tag: String?
): HeadMainPageResponse
{
val url = if(tag != "0") "$mainUrl/api/new/v2/series?page=$page&per_page=12&status=$mainCategory&sort=$orderBy&tags%5B%5D=$tag"
else "$mainUrl/api/new/v2/series?page=$page&per_page=24&status=$mainCategory&sort=$orderBy"
val document = app.get(url).parsed<FenrirMainPageResponse>()
val returnValue = document.data.map { novel ->
newSearchResponse(
name = novel.title,
url = mainUrl + "/series/" + novel.slug
) {
posterUrl = fixUrlNull(novel.cover)
}

}
return HeadMainPageResponse(url, returnValue)
}



override suspend fun load(url: String): LoadResponse
{
val document = app.get(url).document
val infoDiv = document.select("div.flex.flex-col.items-center.gap-5 div.flex-1")
val chapters = app
.get("$mainUrl/api/new/v2/series/${url.getSlugFromUrl()}/chapters")
.parsed<Array<ChapterInf>>()
.mapNotNull { ch ->
if(ch.locked.price > 0) null
else newChapterData("${ch.name} ${if(ch.title.isNullOrEmpty()) "" else "- ${ch.title}"}", "$url/${ch.slug}"){
dateOfRelease = ch.updatedAt.split("T")[0]
}
}

val title = infoDiv.selectFirst("h1")?.text() ?: throw Exception("Title not found")
return newStreamResponse(title,url, chapters) {
infoDiv.select(" > div").forEachIndexed { index, inf ->
when (index) {
1 -> {
setStatus(inf.selectFirst("span")?.text())
}
2 -> {
this.author = inf.selectFirst("a")?.text()
}
3 -> {
this.tags = infoDiv.select("a").mapNotNull {
it.text().trim().takeIf { text -> text.isNotEmpty()}
}
}
}
}
this.synopsis = document.selectFirst("div.synopsis")?.text()
this.posterUrl = document.selectFirst("meta[property=og:image]")?.attr("content")
}
}



override suspend fun loadHtml(url: String): String? {
val document = app.get(url).document
val contentElement = document.selectFirst("div.reader-area[role=region]")
?: document.selectFirst("div.main-area div.chapter-view div.content-area")
?: return null
return contentElement.html()
}




override suspend fun search(query: String): List<SearchResponse> {
val url = "$mainUrl/api/new/v2/series?page=1&per_page=5&search=$query"
val document = app.get(url).parsed<FenrirMainPageResponse>()

return document.data.map{ novel ->
val title = novel.title
val novelUrl = mainUrl + "/series/" + novel.slug
newSearchResponse(title, novelUrl){
posterUrl = fixUrlNull(novel.cover)
}
}
}



data class FenrirMainPageResponse(
@JsonProperty("data")
val data: List<Daum>,
)

data class Daum( // Novel inf
@JsonProperty("title")
val title: String,
@JsonProperty("slug")
val slug: String,
@JsonProperty("cover")
val cover: String,
)

data class ChapterInf(
@JsonProperty("slug")
val slug: String,
@JsonProperty("name")
val name: String,
@JsonProperty("title")
val title: String?,
@JsonProperty("updated_at")
val updatedAt: String,
@JsonProperty("locked")
val locked: Locked,
)

data class Locked(
@JsonProperty("price")
val price: Int,
)

}

Loading