Skip to content

Commit

Permalink
[New Provider] libread.com (#209)
Browse files Browse the repository at this point in the history
* Add new source: `https://libread.com`

* Updated links

* Reverted `rating` change since we still can't see it
  • Loading branch information
USLTD authored Dec 6, 2023
1 parent 914da8c commit 47ea891
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
package com.lagradost.quicknovel.providers

import com.lagradost.quicknovel.*
import com.lagradost.quicknovel.MainActivity.Companion.app
import org.jsoup.Jsoup


class LibReadProvider : MainAPI() {

override val name = "LibRead"
override val mainUrl = "https://libread.com"
override val hasMainPage = true

override val iconId = R.drawable.icon_libread

override val iconBackgroundId = R.color.libread_header_color

override val tags = listOf(
Pair("All", ""),
Pair("Action", "Action"),
Pair("Adult", "Adult"),
Pair("Adventure", "Adventure"),
Pair("Comedy", "Comedy"),
Pair("Drama", "Drama"),
Pair("Eastern", "Eastern"),
Pair("Ecchi", "Ecchi"),
Pair("Fantasy", "Fantasy"),
Pair("Game", "Game"),
Pair("Gender Bender", "Gender Bender"),
Pair("Harem", "Harem"),
Pair("Historical", "Historical"),
Pair("Horror", "Horror"),
Pair("Josei", "Josei"),
Pair("Martial Arts", "Martial Arts"),
Pair("Mature", "Mature"),
Pair("Mecha", "Mecha"),
Pair("Mystery", "Mystery"),
Pair("Psychological", "Psychological"),
Pair("Reincarnation", "Reincarnation"),
Pair("Romance", "Romance"),
Pair("School Life", "School Life"),
Pair("Sci-fi", "Sci-fi"),
Pair("Seinen", "Seinen"),
Pair("Shoujo", "Shoujo"),
Pair("Shounen Ai", "Shounen Ai"),
Pair("Shounen", "Shounen"),
Pair("Slice of Life", "Slice of Life"),
Pair("Smut", "Smut"),
Pair("Sports", "Sports"),
Pair("Supernatural", "Supernatural"),
Pair("Tragedy", "Tragedy"),
Pair("Wuxia", "Wuxia"),
Pair("Xianxia", "Xianxia"),
Pair("Xuanhuan", "Xuanhuan"),
Pair("Yaoi", "Yaoi")
)

override suspend fun loadMainPage(
page: Int,
mainCategory: String?,
orderBy: String?,
tag: String?
): HeadMainPageResponse {
val url = if (tag.isNullOrBlank()) "$mainUrl/sort/latest-release/$page" else "$mainUrl/genre/$tag/$page"
val response = app.get(url)

val document = Jsoup.parse(response.text)

val headers = document.select("div.ul-list1.ul-list1-2.ss-custom > div.li-row")
if (headers.size <= 0) return HeadMainPageResponse(url, ArrayList())
val returnValue: ArrayList<SearchResponse> = ArrayList()
for (h in headers) {
val h3 = h?.selectFirst("h3.tit > a")
val cUrl = fixUrl(h3?.attr("href") ?: continue)

val name = h3.attr("title")
val posterUrl = h.selectFirst("div.pic > a > img")?.attr("src")

val latestChap = h.select("div.item")[2].selectFirst("> div > a")?.text()
returnValue.add(
SearchResponse(
name,
cUrl,
fixUrlNull(posterUrl),
null,
latestChap,
this.name
)
)
}
return HeadMainPageResponse(url, returnValue)
}

override suspend fun loadHtml(url: String): String? {
val response = app.get(url)
val document = Jsoup.parse(
response.text
.replace("\uD835\uDCF5\uD835\uDC8A\uD835\uDC83\uD835\uDE67\uD835\uDE5A\uD835\uDC82\uD835\uDCED.\uD835\uDCEC\uD835\uDE64\uD835\uDE62", "", true)
.replace("libread.com", "", true)
)
return document.selectFirst("div.txt")?.html()
}


override suspend fun search(query: String): List<SearchResponse> {
val response = app.post(
"$mainUrl/search/",
headers = mapOf(
"referer" to mainUrl,
"x-requested-with" to "XMLHttpRequest",
"content-type" to "application/x-www-form-urlencoded",
"accept" to "*/*",
"user-agent" to USER_AGENT
),
data = mapOf("searchkey" to query)
)
val document = Jsoup.parse(response.text)


val headers = document.select("div.li-row")
if (headers.size <= 0) return ArrayList()
val returnValue: ArrayList<SearchResponse> = ArrayList()
for (h in headers) {
val h3 = h?.selectFirst("h3.tit > a")
val cUrl = fixUrl(h3?.attr("href") ?: continue)

val name = h3.attr("title") ?: continue
val posterUrl = h.selectFirst("div.pic > a > img")?.attr("src")

val latestChap = h.select("div.item")[2].selectFirst("> div > a")?.text()
returnValue.add(
SearchResponse(
name,
cUrl,
fixUrlNull(posterUrl),
null,
latestChap,
this.name
)
)
}
return returnValue
}

override suspend fun load(url: String): LoadResponse? {
val response = app.get(url)

val document = Jsoup.parse(response.text)
val name = document.selectFirst("h1.tit")?.text() ?: return null

val author =
document.selectFirst("span.glyphicon.glyphicon-user")?.nextElementSibling()?.text()
val tags =
document.selectFirst("span.glyphicon.glyphicon-th-list")?.nextElementSiblings()?.get(0)
?.text()
?.splitToSequence(", ")?.toList()

val posterUrl = document.select(" div.pic > img").attr("src")
val synopsis = document.selectFirst("div.inner")?.text()

val data: ArrayList<ChapterData> = ArrayList()
val aid = "[0-9]+s.jpg".toRegex().find(response.text)?.value?.substringBefore("s")
val chaptersDataphp = app.post(
"$mainUrl/api/chapterlist.php",
data = mapOf(
"aid" to aid!!
)
)
val parsed = Jsoup.parse(chaptersDataphp.text.replace("""\""", "")).select("option")

for (c in parsed) {

val cUrl = url + '/' + c.attr("value").split('/').last()
val cName = c.text().ifEmpty {
"chapter $c"
}
data.add(ChapterData(cName, cUrl, null, null))
}


val statusHeader0 = document.selectFirst("span.s1.s2")
val statusHeader = document.selectFirst("span.s1.s3")

val status = if (statusHeader != null) {
when (statusHeader.selectFirst("a")?.text()) {
"OnGoing" -> STATUS_ONGOING
"Completed" -> STATUS_COMPLETE
else -> STATUS_NULL
}

} else {
when (statusHeader0?.selectFirst("> a")?.text()) {
"OnGoing" -> STATUS_ONGOING
"Completed" -> STATUS_COMPLETE
else -> STATUS_NULL
}
}

var rating = 0
var peopleVoted = 0

val votes = document.selectFirst("div.m-desc > div.score > p:nth-child(2)")
if (votes != null) {
rating = votes.text().substringBefore('/').toFloat().times(200).toInt()
peopleVoted = votes.text().substringAfter('(').filter { it.isDigit() }.toInt()
}

return StreamResponse(
url,
name,
data,
author,
fixUrlNull(posterUrl),
rating,
peopleVoted,
null,
synopsis,
tags,
status
)
}
}
1 change: 1 addition & 0 deletions app/src/main/java/com/lagradost/quicknovel/util/Apis.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class Apis {
BestLightNovelProvider(),
// WuxiaWorldOnlineProvider(), // Site does not work
RoyalRoadProvider(),
LibReadProvider(),
FreewebnovelProvider(),
//AzynovelProvider(), // dont exist anymore
ReadfromnetProvider(),
Expand Down
Binary file added app/src/main/res/drawable/icon_libread.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,5 @@

<color name="colorTestPass">#48E484</color>
<color name="colorTestFail">#ea596e</color>
<color name="libread_header_color">#009688</color>
</resources>

0 comments on commit 47ea891

Please sign in to comment.