-- {"id":31,"ver":"1.0.1","libVer":"1.0.0","author":"Gta-Cool"} local json = Require("dkjson") --- Identification number of the extension. --- Should be unique. Should be consistent in all references. --- --- Required. --- --- @type int local id = 31 --- Name of extension to display to the user. --- Should match index. --- --- Required. --- --- @type string local name = "Light Novel Pub" --- Base URL of the extension. Used to open web view in Shosetsu. --- --- Required. --- --- @type string local baseURL = "https://www.lightnovelpub.com/" --- URL of the logo. --- --- Optional, Default is empty. --- --- @type string local imageURL = "https://gitlab.com/shosetsuorg/extensions/-/raw/dev/icons/LightNovelPub.png" --- Shosetsu tries to handle cloudflare protection if this is set to true. --- --- Optional, Default is false. --- --- @type boolean local hasCloudFlare = true --- If the website has search. --- --- Optional, Default is true. --- --- @type boolean local hasSearch = true --- If the websites search increments or not. --- --- Optional, Default is true. --- --- @type boolean local isSearchIncrementing = true local GENRE_VALUES = { [0] = "genre-all-04061342", [1] = "genre-action-04061342", [2] = "genre-adventure-04061342", [3] = "genre-drama-04061342", [4] = "genre-fantasy-04061342", [5] = "genre-harem-04061342", [6] = "genre-martial-arts-10032131", [7] = "genre-mature-04061342", [8] = "genre-romance-04061342", [9] = "genre-tragedy-10032131", [10] = "genre-xuanhuan-10032131", [11] = "genre-ecchi-04061342", [12] = "genre-comedy-10032131", [13] = "genre-slice-of-life-04061342", [14] = "genre-mystery-10032131", [15] = "genre-supernatural-10032131", [16] = "genre-psychological-10032131", [17] = "genre-sci-fi-04061342", [18] = "genre-xianxia-04061342", [19] = "genre-school-life-10032131", [20] = "genre-josei-04061342", [21] = "genre-wuxia-04061342", [22] = "genre-shounen-10032131", [23] = "genre-horror-04061342", [24] = "genre-mecha-10032131", [25] = "genre-historical-04061342", [26] = "genre-shoujo-10032131", [27] = "genre-adult-04061342", [28] = "genre-seinen-04061342", [29] = "genre-sports-10032131", [30] = "genre-lolicon-10032131", [31] = "genre-gender-bender-04061342", [32] = "genre-shounen-ai-10032131", [33] = "genre-yaoi-04061342", [34] = "genre-video-games-04061342", [35] = "genre-smut-04061342", [36] = "genre-magical-realism-10032131", [37] = "genre-eastern-fantasy-04061342", [38] = "genre-contemporary-romance-10032131", [39] = "genre-fantasy-romance-10032131", [40] = "genre-shoujo-ai-10032131", [41] = "genre-yuri-10032131" } local GENRE_KEY = 11 local ORDER_VALUES = { [0] = "order-new", [1] = "order-popular", [2] = "order-updated" } local ORDER_KEY = 12 local STATUS_VALUES = { [0] = "status-all", [1] = "status-completed", [2] = "status-ongoing" } local STATUS_KEY = 13 --- Filters to display via the filter fab in Shosetsu. --- --- Optional, Default is none. --- --- @type Filter[] | Array local searchFilters = { DropdownFilter(GENRE_KEY, "Genre / Category", { "All", "Action", "Adventure", "Drama", "Fantasy", "Harem", "Martial Arts", "Mature", "Romance", "Tragedy", "Xuanhuan", "Ecchi", "Comedy", "Slice of Life", "Mystery", "Supernatural", "Psychological", "Sci-fi", "Xianxia", "School Life", "Josei", "Wuxia", "Shounen", "Horror", "Mecha", "Historical", "Shoujo", "Adult", "Seinen", "Sports", "Lolicon", "Gender Bender", "Shounen Ai", "Yaoi", "Video Games", "Smut", "Magical Realism", "Eastern Fantasy", "Contemporary Romance", "Fantasy Romance", "Shoujo Ai", "Yuri" }), DropdownFilter(ORDER_KEY, "Order By", { "New", "Popular", "Updates" }), DropdownFilter(STATUS_KEY, "Status", { "All", "Completed", "Ongoing" }) } --- Internal settings store. --- --- Completely optional. --- But required if you want to save results from [updateSetting]. --- --- Notice, each key is surrounded by "[]" and the value is on the right side. --- @type table local settings = { [1] = 0 } --- Settings model for Shosetsu to render. --- --- Optional, Default is empty. --- --- @type Filter[] | Array local settingsModel = {} --- ChapterType provided by the extension. --- --- Optional, Default is STRING. But please do HTML. --- --- @type ChapterType local chapterType = ChapterType.HTML --- Index that pages start with. For example, the first page of search is index 1. --- --- Optional, Default is 1. --- --- @type number local startIndex = 1 --- Shrink the website url down. This is for space saving purposes. --- --- Required. --- --- @param url string Full URL to shrink. --- @param type int Either KEY_CHAPTER_URL or KEY_NOVEL_URL. --- @return string Shrunk URL. local function shrinkURL(url, type) return url:gsub(".-lightnovelpub%.com/novel/", "") end --- Expand a given URL. --- --- Required. --- --- @param url string Shrunk URL to expand. --- @param type int Either KEY_CHAPTER_URL or KEY_NOVEL_URL. --- @return string Full URL. local function expandURL(url, type) return baseURL .. "novel/" .. url end local function getRankingNovels(url) local document = GETDocument(url):selectFirst("#ranking .container") return map(document:select(".rank-novels .novel-item"), function(ni) local n = Novel() local te = ni:selectFirst(".item-body .title a"); n:setTitle(te:attr("title")) n:setLink(shrinkURL(baseURL .. te:attr("href"):sub(2), KEY_NOVEL_URL)) n:setImageURL(ni:selectFirst(".cover img"):attr("data-src")) return n end) end --- Listings that users can navigate in Shosetsu. --- --- Required, 1 value at minimum. --- --- @type Listing[] | Array local listings = { Listing("Browse List", true, function(data) local document = GETDocument(baseURL .. "browse/" .. GENRE_VALUES[data[GENRE_KEY]] .. "/" .. ORDER_VALUES[data[ORDER_KEY]] .. "/" .. STATUS_VALUES[data[STATUS_KEY]] .. "/" .. "?page=" .. data[PAGE] ):selectFirst("#explore .container") local activePage = document:selectFirst(".pagination .active"):text() if activePage == ("" .. data[PAGE]) then return map(document:select(".novel-list .novel-item"), function(ni) local n = Novel() local te = ni:selectFirst(".item-body .novel-title a"); n:setTitle(te:attr("title")) n:setLink(shrinkURL(baseURL .. te:attr("href"):sub(2), KEY_NOVEL_URL)) n:setImageURL(ni:selectFirst(".novel-cover img"):attr("data-src")) return n end) end return {} end), Listing("Novel Ranking", false, function(data) return getRankingNovels(baseURL .. "ranking-04061612") end), Listing("Top Rated Novels", false, function(data) return getRankingNovels(baseURL .. "ranking-04061612/ratings") end), Listing("Most Read Novels", false, function(data) return getRankingNovels(baseURL .. "ranking-04061612/mostread") end), Listing("The novels with the most reviews", false, function(data) return getRankingNovels(baseURL .. "ranking-04061612/mostreview") end), Listing("The novels with the most commentary activity", false, function(data) return getRankingNovels(baseURL .. "ranking-04061612/mostcomment") end), Listing("The novels most added to the library", false, function(data) return getRankingNovels(baseURL .. "ranking-04061612/mostlib") end) } --- Get a chapter passage based on its chapterURL. --- --- Required. --- --- @param chapterURL string The chapters shrunken URL. --- @return string Strings in lua are byte arrays. If you are not outputting strings/html you can return a binary stream. local function getPassage(chapterURL) local url = expandURL(chapterURL, KEY_CHAPTER_URL) --- Chapter page, extract info from it. local document = GETDocument(url):selectFirst("#chapter-article") local title = document:selectFirst("section .titles .chapter-title"):text() local chapter = document:selectFirst("#chapter-container") -- Remove unwanted HTML elements (ads) chapter:select(".adsbygoogle"):parents():remove() -- Chapter title inserted before chapter text chapter:child(0):before("