())
47 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_sp7_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/reader/src/main/java/cc/aoeiuv020/reader/AnimationMode.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.reader
2 |
3 | import cc.aoeiuv020.pager.AnimMode
4 |
5 | /**
6 | * 所有翻页动画,
7 | * SIMPLE对应旧阅读器,
8 | * 剩下的对应新阅读器的所有动画,AnimMode,
9 | * Created by AoEiuV020 on 2017.12.09-01:01:49.
10 | */
11 | enum class AnimationMode {
12 | SIMPLE,
13 | SIMULATION,
14 | COVER,
15 | SLIDE,
16 | NONE,
17 | SCROLL;
18 |
19 | fun toAnimMode(): AnimMode = when (this) {
20 | SIMPLE -> {
21 | throw IllegalStateException("简单翻页动画不可用在这里,")
22 | }
23 | SIMULATION -> AnimMode.SIMULATION
24 | COVER -> AnimMode.COVER
25 | SLIDE -> AnimMode.SLIDE
26 | NONE -> AnimMode.NONE
27 | SCROLL -> AnimMode.SCROLL
28 | }
29 |
30 | companion object {
31 | @Suppress("unused")
32 | fun fromAnimMode(animMode: AnimMode): AnimationMode = when (animMode) {
33 | AnimMode.SIMULATION -> SIMULATION
34 | AnimMode.COVER -> COVER
35 | AnimMode.SLIDE -> SLIDE
36 | AnimMode.NONE -> NONE
37 | AnimMode.SCROLL -> SCROLL
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/filepicker/src/main/java/cc/aoeiuv020/filepicker/controller/NotifyItemChecked.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Angad Singh
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package cc.aoeiuv020.filepicker.controller;
18 |
19 | /*
20 | *
21 | * Created by Angad Singh on 11-07-2016.
22 | *
23 | */
24 |
25 | /**
26 | * Interface definition for a callback to be invoked
27 | * when a checkbox is checked.
28 | */
29 | public interface NotifyItemChecked {
30 |
31 | /**
32 | * Called when a checkbox is checked.
33 | */
34 | void notifyCheckBoxIsClicked();
35 | }
36 |
--------------------------------------------------------------------------------
/IronDB/src/main/java/cc/aoeiuv020/irondb/impl/KeysContainer.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.irondb.impl
2 |
3 | import cc.aoeiuv020.irondb.KeySerializer
4 | import java.io.File
5 |
6 | /**
7 | * 只用于判断元素是否存在集合中,
8 | * 不可用于读出元素,
9 | *
10 | * Created by AoEiuV020 on 2018.05.27-15:14:05.
11 | */
12 | class KeysContainer(
13 | base: File,
14 | private val keySerializer: KeySerializer
15 | ) : Collection {
16 | // 文件名列表,包括目录,也就是Database.sub方法产生的,
17 | private val nameSet = base.list()?.toSet() ?: emptySet()
18 |
19 | override val size: Int = nameSet.size
20 |
21 | override fun contains(element: String): Boolean =
22 | nameSet.contains(keySerializer.serialize(element))
23 |
24 | override fun containsAll(elements: Collection): Boolean {
25 | for (element in elements) {
26 | if (!contains(element)) {
27 | return false
28 | }
29 | }
30 | return true
31 | }
32 |
33 | override fun isEmpty(): Boolean = nameSet.isEmpty()
34 |
35 | // 不打算支持,
36 | override fun iterator(): Iterator = throw UnsupportedOperationException()
37 | }
38 |
--------------------------------------------------------------------------------
/api/src/main/java/cc/aoeiuv020/panovel/api/base/JsNovelContext.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.base
2 |
3 | import cc.aoeiuv020.js.JsContext
4 | import cc.aoeiuv020.js.JsUtil
5 | import org.jsoup.nodes.Element
6 | import java.util.concurrent.ExecutorService
7 | import java.util.concurrent.Executors
8 | import java.util.concurrent.Future
9 |
10 | /**
11 | * Created by AoEiuV020 on 2019.02.11-18:27:45.
12 | */
13 | abstract class JsNovelContext : DslJsoupNovelContext() {
14 | // js线程,一个js上下文只能一个线程使用,其他线程需要时都等待这个线程执行,
15 | private val jsExecutor: ExecutorService = Executors.newSingleThreadExecutor()
16 | private val jsContext: JsContext = get { JsUtil.create() }
17 |
18 | @Suppress("UNCHECKED_CAST")
19 | private fun submit(block: () -> T): Future {
20 | return jsExecutor.submit(block) as Future
21 | }
22 |
23 | private fun get(block: () -> T): T {
24 | return submit(block).get()
25 | }
26 |
27 | protected fun js(string: String): String = get {
28 | jsContext.run(string)
29 | }
30 |
31 | protected fun Element.script(query: String) = requireElement(query, TAG_SCRIPT).data()
32 | }
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/QingkanTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by AoEiuV020 on 2018.06.03-14:55:54.
7 | */
8 | class QingkanTest : BaseNovelContextText(Qingkan::class) {
9 | @Test
10 | fun search() {
11 | search("都市")
12 | search("争虚", "何途", "zhengxu")
13 | search("盗天仙途", "荆柯守", "daotianxiantu")
14 | }
15 |
16 | @Test
17 | fun detail() {
18 | detail("daotianxiantu", "daotianxiantu", "盗天仙途", "荆柯守",
19 | null,
20 | "福地产生地仙,洞天来往天仙,我有梅花一株,盗取天机!",
21 | null)
22 | }
23 |
24 | @Test
25 | fun chapters() {
26 | chapters("daotianxiantu", "序", "daotianxiantu/29249297", null,
27 | "第三百五十四章 检测", "daotianxiantu/54903911", null,
28 | 308)
29 | }
30 |
31 | @Test
32 | fun content() {
33 | content("daotianxiantu/54903911",
34 | "古镜六寸高,形制古雅,镜面却有一个虚影,现出极淡的金光,正照着下去,一批拔干净,就换下一批,只是这时发生了变故。",
35 | "看着骑兵冲了上来,押粮将军冷笑:“你区区两三百轻甲就敢冲击押粮队?也罢,杀光你们,就是一功!”",
36 | 48)
37 | }
38 |
39 | }
--------------------------------------------------------------------------------
/server/src/main/java/cc/aoeiuv020/panovel/server/dal/model/MobResponse.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.server.dal.model
2 |
3 | import cc.aoeiuv020.panovel.server.common.ErrorCode
4 | import cc.aoeiuv020.panovel.server.common.toBean
5 | import cc.aoeiuv020.panovel.server.common.toJson
6 | import java.lang.reflect.Type
7 |
8 | /**
9 | *
10 | * Created by AoEiuV020 on 2018.04.02-11:21:33.
11 | */
12 | class MobResponse(
13 | var code: Int = ErrorCode.UNKNOWN_ERROR.code,
14 | val data: String = "{}"
15 | ) {
16 | companion object {
17 | fun success(data: Any = Any()): MobResponse {
18 | return MobResponse(ErrorCode.SUCCESS.code, data.toJson())
19 | }
20 |
21 | fun error(error: ErrorCode = ErrorCode.UNKNOWN_ERROR): MobResponse {
22 | return MobResponse(error.code)
23 | }
24 | }
25 |
26 | inline fun getRealData(): T {
27 | return data.toBean()
28 | }
29 |
30 | fun getRealData(type: Type): T {
31 | return data.toBean(type)
32 | }
33 |
34 | fun isSuccess(): Boolean {
35 | return code == ErrorCode.SUCCESS.code
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/MianhuatangTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by AoEiuV020 on 2018.06.03-11:13:24.
7 | */
8 | class MianhuatangTest : BaseNovelContextText(Mianhuatang::class) {
9 | @Test
10 | fun search() {
11 | search("元尊", "天蚕土豆", "8328778")
12 | }
13 |
14 | @Test
15 | fun detail() {
16 | detail("8326615", "8326615", "漫威世界的术士", "火之高兴",
17 | null,
18 | "恶魔是我的奴仆,邪能是我的力量,暗影与烈焰伴我左右,我是一名术士。" +
19 | "一名术士行走在漫威的世界里。(没系统,靠自己吧少年。)" +
20 | "欢迎加入漫威世界的术士书友群,群号码:177873494",
21 | null)
22 | }
23 |
24 | @Test
25 | fun chapters() {
26 | chapters("8326615", "第一章,周围没术士吧?我穿个越", "8326615/81992180", null,
27 | "第1029章", "8326615/84174452", null,
28 | 1057)
29 | }
30 |
31 | @Test
32 | fun content() {
33 | content("8329585/82278161",
34 | "在这样的情况下,如果能够让林霄有机会休息几秒,哪怕是几秒也好,估计也会恢复的比较快,但是奥布勒加却没有给林霄喘息的机会。",
35 | "只是这需要机会!",
36 | 69)
37 | }
38 | }
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/SiFangTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by AoEiuV020 on 2019.10.13-13:50:00.
7 | */
8 | class SiFangTest : BaseNovelContextText(SiFang::class) {
9 | @Test
10 | fun search() {
11 | search("逆风岁月", "君尽欢", "20")
12 | }
13 |
14 | @Test
15 | fun detail() {
16 | detail("20", "20", "逆风岁月", "君尽欢",
17 | "http://www.sifangbook.com/uploads/20180724/4cf6966367c66aef17091409b493c895.jpg",
18 | "当曾经的谎言破碎在手中,原本一心想逃离家族的俞南思不得不停下脚步。为夺回母亲该有的一切,她甚至不惜踏上违背初心的路。而赫北书,无论曾经现在,虚无的皮囊,内心下依然隐藏着恶魔,肆无忌惮。\n" +
19 | "开始的二人,命途相似,做的却都不是真实的自...",
20 | "2018-12-24 23:49:32")
21 | }
22 |
23 | @Test
24 | fun chapters() {
25 | chapters("20", "001:关于俞家", "712", null,
26 | "140:圆满结局", "5543", "2018-12-24 23:49:32",
27 | 140)
28 | }
29 |
30 | @Test
31 | fun content() {
32 | content("712",
33 | "三月,是雨最肆意的时节。",
34 | "想到这儿,俞南思不屑地笑了笑,这种鬼话父亲也信,真是傻透了。",
35 | 56)
36 | }
37 |
38 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_qidianshuju_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_qidianshuju_post.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/cc/aoeiuv020/panovel/migration/impl/DownloadMigration.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.migration.impl
2 |
3 | import android.content.Context
4 | import cc.aoeiuv020.panovel.migration.Migration
5 | import cc.aoeiuv020.panovel.settings.DownloadSettings
6 | import cc.aoeiuv020.panovel.settings.GeneralSettings
7 | import cc.aoeiuv020.panovel.util.VersionName
8 |
9 | /**
10 | * 3.2.4开始添加下载相关专用的设置页,
11 | * 原先在在GeneralSettings里的下载相关设置迁移到DownloadSettings里,
12 | *
13 | * Created by AoEiuV020 on 2018.11.11-12:27:38.
14 | */
15 | class DownloadMigration : Migration() {
16 | override val to: VersionName = VersionName("3.2.4")
17 | override val message: String = "下载设置"
18 |
19 | override fun migrate(ctx: Context, from: VersionName) {
20 | GeneralSettings.sharedPreferences.all.forEach { (key, value) ->
21 | when (key) {
22 | "downloadThreadsLimit" -> DownloadSettings.downloadThreadsLimit = value as Int
23 | "downloadCount" -> DownloadSettings.downloadCount = value as Int
24 | "autoDownloadCount" -> DownloadSettings.autoDownloadCount = value as Int
25 | }
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/GgdownTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by AoEiuV020 on 2018.06.03-15:47:22.
7 | */
8 | class GgdownTest : BaseNovelContextText(Ggdown::class) {
9 | @Test
10 | fun search() {
11 | search("都市")
12 | search("与天同兽", "雾矢翊", "46272")
13 | search("黑风城战记", "耳雅", "19447")
14 | }
15 |
16 | @Test
17 | fun detail() {
18 | detail("19447", "19447", "黑风城战记", "耳雅",
19 | "https://www.ggdownxs.com/image/19/19447/19447s.jpg",
20 | "恶帝城的建立打破了西北的平静,正邪之战一触即发~~\n" +
21 | "案件结合战役,龙图原班人马继续他们的传奇经历~~\n",
22 | "2019-05-15 00:00:00")
23 | }
24 |
25 | @Test
26 | fun chapters() {
27 | chapters("19447", "第1章 【黑风城】", "19/19447/5585742", null,
28 | "第254章 【番外火凤篇】01 红叶红蝶", "19/19447/33518674", null,
29 | 191)
30 | }
31 |
32 | @Test
33 | fun content() {
34 | content("19/19447/5585742",
35 | "黑风山位于黑风城以南,山顶常年积雪、山腰植被茂密、山脚溪流交错,一山四季。",
36 | "go~",
37 | 100)
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_settings.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_site_choose.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/cc/aoeiuv020/panovel/settings/location.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.settings
2 |
3 | import cc.aoeiuv020.panovel.backup.BackupPresenter
4 | import cc.aoeiuv020.panovel.data.CacheManager
5 | import cc.aoeiuv020.panovel.local.NovelExporter
6 | import cc.aoeiuv020.panovel.util.Delegates
7 | import cc.aoeiuv020.panovel.util.Pref
8 |
9 | /**
10 | * Created by AoEiuV020 on 2018.12.31-20:41:11.
11 | */
12 | @Suppress("unused")
13 | object LocationSettings : Pref {
14 | override val name: String
15 | get() = "Location"
16 | var cacheLocation: String by Delegates.string(ctx.cacheDir.resolve(CacheManager.NAME_FOLDER).absolutePath)
17 | var backupLocation: String by Delegates.string(sdcardResolve(BackupPresenter.NAME_FOLDER))
18 | var exportLocation: String by Delegates.string(sdcardResolve(NovelExporter.NAME_FOLDER))
19 |
20 | // 优先SD卡,不可用就私有目录,
21 | private fun sdcardResolve(name: String): String = (
22 | ctx.getExternalFilesDir(null)
23 | ?.resolve(name)
24 | ?.apply { exists() || mkdirs() }
25 | ?.takeIf { it.canWrite() }
26 | ?: ctx.filesDir.resolve(name)
27 | ).absolutePath
28 |
29 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_read.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/refresher/src/main/java/cc/aoeiuv020/panovel/refresher/Application.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.refresher
2 |
3 | import cc.aoeiuv020.jsonpath.JsonPathUtils
4 | import cc.aoeiuv020.panovel.server.ServerAddress
5 | import cc.aoeiuv020.panovel.server.common.toBean
6 | import java.io.File
7 |
8 | /**
9 | * Created by AoEiuV020 on 2018.04.21-16:05:40.
10 | */
11 | fun main(args: Array) {
12 | JsonPathUtils.initGson()
13 | val ite = args.iterator()
14 | var address: ServerAddress = ServerAddress.getDefault()
15 | var config = Config()
16 | val bookshelfList = mutableSetOf()
17 |
18 | while (ite.hasNext()) {
19 | when (ite.next()) {
20 | "-a" -> {
21 | address = File(ite.next()).readText().toBean()
22 | }
23 | "-h" -> {
24 | address = ServerAddress.new(ite.next())
25 | }
26 | "-b" -> {
27 | bookshelfList.add(ite.next())
28 | }
29 | "-c" -> {
30 | config = File(ite.next()).readText().toBean()
31 | }
32 | }
33 | }
34 | Refresher(config = config).start(address = address, bookshelfList = bookshelfList)
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/ShoudashuTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by AoEiuV020 on 2021.05.15-22:58:40.
7 | */
8 | class ShoudashuTest : BaseNovelContextText(Shoudashu::class) {
9 | @Test
10 | fun search() {
11 | search("都市")
12 | search("都市最强狂神萧羽秦媛媛", "半只凉鞋", "277/277083")
13 | }
14 |
15 | @Test
16 | fun detail() {
17 | detail(
18 | "277/277083", "277/277083", "都市最强狂神萧羽秦媛媛", "半只凉鞋",
19 | "https://www.shoudashu.com/files/article/image//277/277083/277083s.jpg",
20 | "萧羽活了五千年,死不了,也老不成,这搞得他心情有点差,所以还请没事别招惹。要是惹怒了被暴打一顿,他还会狠狠地告诉你:“我的世界,没有能与不能,只有想与不想。”",
21 | null
22 | )
23 | }
24 |
25 | @Test
26 | fun chapters() {
27 | chapters(
28 | "277/277083", "第一章 大亨之殇", "277/277083/66921365", null,
29 | "第四百二十六章 你怎么敢", "277/277083/70018272", null,
30 | 425
31 | )
32 | }
33 |
34 | @Test
35 | fun content() {
36 | content(
37 | "277/277083/66921365",
38 | "炎夏,魔都。",
39 | "萧羽感受到的怨气,就是由她的身上散发出来的。",
40 | 91
41 | )
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/WenxuemiTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by AoEiuV020 on 2018.06.03-19:57:36.
7 | */
8 | class WenxuemiTest : BaseNovelContextText(Wenxuemi::class) {
9 | @Test
10 | fun search() {
11 | search("都市")
12 | search("大道朝天", "猫腻", "24/24163")
13 | }
14 |
15 | @Test
16 | fun detail() {
17 | detail(
18 | "30/30818", "30/30818", "长生种", "月中阴",
19 | "https://www.wenxuemi.cc/files/article/image/30/30818/30818s.jpg",
20 | "这是一个疯狂氪金(挂逼),在异界为所欲为的故事。生死看淡,不服就干!……ps:老月已经完本《法师奥义》《永恒武道》皆是精品,大家有兴趣的可以去看一看。老月出品,必属精品!书友企鹅群:189099589",
21 | "2020-03-22 23:11:15"
22 | )
23 | }
24 |
25 | @Test
26 | fun chapters() {
27 | chapters("30/30818", "第一章 你可还有童子身?", "30/30818/15644464", null,
28 | "新书《以力服人》已经发布", "30/30818/20073343", "2020-03-22 23:11:15",
29 | 1126)
30 | }
31 |
32 | @Test
33 | fun content() {
34 | content("30/30818/15644464",
35 | "姓名:雷道(十八岁)",
36 | "张青龙也没有看那些银子,而是沉声道:“道哥儿真要练武也行,但这童子功却有些特殊。嗯,我得先问道哥儿一句,道哥儿,你可还有童子身?”",
37 | 73)
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/X23usTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by AoEiuV020 on 2018.06.08-18:03:24.
7 | */
8 | class X23usTest : BaseNovelContextText(X23us::class) {
9 | @Test
10 | fun search() {
11 | search("都市")
12 | search("帝霸", "厌笔萧生", "64889")
13 | }
14 |
15 | @Test
16 | fun detail() {
17 | detail("64889", "64889", "帝霸", "厌笔萧生",
18 | "https://www.x23us.com/files/article/image/64/64889/64889s.jpg",
19 | "天若逆我,我必封之,神若挡我,我必屠之——站在万族之巅的李七夜立下豪言!\n" +
20 | "这是属于一个平凡小子崛起的故事,一个牧童走向万族之巅的征程。\n" +
21 | "在这里充满神话与奇迹,天魔建起古国,石人筑就天城,鬼族铺成仙路,魅灵修补神府……",
22 | "2018-06-08 00:00:00")
23 | }
24 |
25 | @Test
26 | fun chapters() {
27 | chapters("64889", "契子(读者必看 非常重要)", "64/64889/26487455", null,
28 | "第3800章三才剑法", "64/64889/33839747", "2019-10-11 00:00:00",
29 | 3842)
30 | }
31 |
32 | @Test
33 | fun content() {
34 | content("64/64889/26487455",
35 | "契子",
36 | "一只不甘命运被左右的乌鸦,对抗着天地最可怕的存在,左右着千万年中的一个又一个大时代的变迁!",
37 | 24)
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/app/src/main/res/xml/pref_location.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
10 |
11 |
17 |
18 |
24 |
25 |
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/KsswTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | class KsswTest : BaseNovelContextText(Kssw::class) {
6 | @Test
7 | fun search() {
8 | search("都市")
9 | search("我真不是邪神走狗", "万劫火", "2588")
10 | }
11 |
12 | @Test
13 | fun detail() {
14 | detail(
15 | "2588", "2588", "我真不是邪神走狗", "万劫火",
16 | "https://pc.kssw.net/files/article/image/2/2588/2588s.jpg",
17 | "",
18 | "2020-10-07 01:19:00"
19 | )
20 | }
21 |
22 | @Test
23 | fun chapters() {
24 | chapters(
25 | "2588", "001-欢迎光临", "2588/21098411", null,
26 | "255-“季”与A16庄园(第三更)", "2588/24265713", "2020-10-07 01:19:00",
27 | 257
28 | )
29 | }
30 |
31 | @Test
32 | fun content() {
33 | content(
34 | "2588/24265713",
35 | "就在胡德与安德曾两人在哲罗姆办么室当中,商量着怎么把自家基地连锅端的时候。另一边,同在中央区的a16号住宅之中,此刻却发生了一件或许将要改变-些什么的事情。a16号住宅,姓季",
36 | "费很够,但是你再不去书店拜访,别人就都把羹分完了。季博农把那份文件拿过来翻了翻,心里-惊,眉头皱“这次真理会?”wuhl他的目光不由得移到了桌子的右上角,那里同样也有一模一样类型的纸质文件记录了每一次不同组织、个人和书店的接触,以及各自的结果。最近的一份情报,还是关于太阳神教的建立。在那之前,季博农依靠的还是自己的情报网,但是现在,女儿情报却比自己还要先了",
37 | 10
38 | )
39 | }
40 | }
--------------------------------------------------------------------------------
/server/src/main/java/cc/aoeiuv020/panovel/server/ServerAddress.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.server
2 |
3 | /**
4 | *
5 | * Created by AoEiuV020 on 2018.04.06-13:03:41.
6 | */
7 | class ServerAddress(
8 | val baseUrl: String
9 | ) {
10 | companion object {
11 | const val MESSAGE_HOST = "msg.panovel.aoeiuv020.com"
12 | const val CONFIG_HOST = "panovel.aoeiuv020.com"
13 | private const val PANOVEL_API_HOST = "http://panovel.aoeiuv020.com"
14 |
15 | fun getDefault(): ServerAddress = new(PANOVEL_API_HOST)
16 |
17 | fun new(host: String): ServerAddress {
18 | return ServerAddress(host)
19 | }
20 | }
21 |
22 | val updateUploadUrl: String
23 | get() = "$baseUrl/novel/update"
24 |
25 | val needRefreshNovelListUrl: String
26 | get() = "$baseUrl/novel/needRefreshNovelList"
27 |
28 | val queryListUrl: String
29 | get() = "$baseUrl/novel/queryList"
30 |
31 | val touchUrl: String
32 | get() = "$baseUrl/novel/touch"
33 |
34 | val minVersionUrl: String
35 | get() = "$baseUrl/novel/minVersion"
36 |
37 | val config: String
38 | get() = "$baseUrl/novel/config"
39 |
40 | val message: String
41 | get() = "$baseUrl/novel/message"
42 | }
43 |
--------------------------------------------------------------------------------
/filepicker/src/main/java/cc/aoeiuv020/filepicker/controller/DialogSelectionListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Angad Singh
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package cc.aoeiuv020.filepicker.controller;
18 |
19 | /*
20 | * Created by Angad Singh on 10-07-2016.
21 | *
22 | */
23 |
24 | /**
25 | * Interface definition for a callback to be invoked
26 | * when dialog selects files.
27 | */
28 | public interface DialogSelectionListener {
29 |
30 | /**
31 | * The method is called when files or directories are selected.
32 | *
33 | * @param files The array of String containing selected file paths.
34 | */
35 | void onSelectedFilePaths(String files[]);
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/cc/aoeiuv020/panovel/text/DispatchTouchFrameLayout.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.text
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.MotionEvent
6 | import android.widget.FrameLayout
7 | import org.jetbrains.anko.AnkoLogger
8 | import org.jetbrains.anko.verbose
9 |
10 | /**
11 | *
12 | * Created by AoEiuV020 on 2017.11.24-19:54:53.
13 | */
14 | class DispatchTouchFrameLayout : FrameLayout, AnkoLogger {
15 | constructor(context: Context)
16 | : super(context)
17 |
18 | constructor(context: Context, attrs: AttributeSet)
19 | : super(context, attrs)
20 |
21 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int)
22 | : super(context, attrs, defStyleAttr)
23 |
24 | var activity: NovelTextActivity? = null
25 |
26 | private var previousAction: Int = MotionEvent.ACTION_UP
27 | override fun dispatchTouchEvent(event: MotionEvent): Boolean {
28 | verbose { event }
29 | if (previousAction == MotionEvent.ACTION_DOWN
30 | && event.action == MotionEvent.ACTION_UP) {
31 | activity?.toggle()
32 | }
33 | previousAction = event.action
34 | return super.dispatchTouchEvent(event)
35 | }
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/cc/aoeiuv020/panovel/data/ServerManager.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.data
2 |
3 | import android.content.Context
4 | import cc.aoeiuv020.panovel.data.entity.Novel
5 | import cc.aoeiuv020.panovel.server.ServerManager
6 | import cc.aoeiuv020.panovel.server.dal.model.Message
7 | import cc.aoeiuv020.panovel.server.dal.model.QueryResponse
8 | import cc.aoeiuv020.panovel.server.toServer
9 |
10 | /**
11 | *
12 | * Created by AoEiuV020 on 2018.05.31-18:22:55.
13 | */
14 | class ServerManager(@Suppress("UNUSED_PARAMETER") ctx: Context) {
15 |
16 | /**
17 | * 订阅书架列表,覆盖所有tag,
18 | */
19 | fun setTags(list: List) {
20 | }
21 |
22 | /**
23 | * 添加这些小说的订阅,
24 | */
25 | fun addTags(
26 | list: List, callback: (List) -> Unit = { novelList ->
27 | }
28 | ) {
29 | }
30 |
31 | fun removeTags(
32 | list: List, callback: (List) -> Unit = { novelList ->
33 | }
34 | ) {
35 | }
36 |
37 | fun touchUpdate(novel: Novel) = ServerManager.touch(novel.toServer())
38 | fun askUpdate(list: List): Map =
39 | ServerManager.queryList(list.map { it.nId to it.toServer() }.toMap())
40 |
41 | fun getMessage(): Message? = ServerManager.message()
42 | }
--------------------------------------------------------------------------------
/app/schemas/cc.aoeiuv020.panovel.data.db.AppDatabase/1.json:
--------------------------------------------------------------------------------
1 | {
2 | "formatVersion": 1,
3 | "database": {
4 | "version": 1,
5 | "identityHash": "21396976adb39f249c4500e23b2b5d90",
6 | "entities": [
7 | {
8 | "tableName": "SiteEnabled",
9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `enabled` INTEGER NOT NULL, PRIMARY KEY(`name`))",
10 | "fields": [
11 | {
12 | "fieldPath": "name",
13 | "columnName": "name",
14 | "affinity": "TEXT",
15 | "notNull": true
16 | },
17 | {
18 | "fieldPath": "enabled",
19 | "columnName": "enabled",
20 | "affinity": "INTEGER",
21 | "notNull": true
22 | }
23 | ],
24 | "primaryKey": {
25 | "columnNames": [
26 | "name"
27 | ],
28 | "autoGenerate": false
29 | },
30 | "indices": [],
31 | "foreignKeys": []
32 | }
33 | ],
34 | "setupQueries": [
35 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
36 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"21396976adb39f249c4500e23b2b5d90\")"
37 | ]
38 | }
39 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/novel_item_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_single_search.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/reader/src/main/java/cc/aoeiuv020/reader/simple/ResizableImageView.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.reader.simple
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.View
6 | import com.github.chrisbanes.photoview.PhotoView
7 |
8 | /**
9 | * https://stackoverflow.com/a/12283909/5615186
10 | * Created by AoEiuV020 on 2018.06.11-10:56:37.
11 | */
12 | class ResizableImageView : PhotoView {
13 | constructor(context: Context)
14 | : super(context)
15 |
16 | constructor(context: Context, attrs: AttributeSet)
17 | : super(context, attrs)
18 |
19 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int)
20 | : super(context, attrs, defStyleAttr)
21 |
22 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
23 | val d = drawable
24 |
25 | if (d != null) {
26 | // ceil not round - avoid thin vertical gaps along the left/right edges
27 | val width = View.MeasureSpec.getSize(widthMeasureSpec)
28 | val height = Math.ceil((width.toFloat() * d.intrinsicHeight.toFloat() / d.intrinsicWidth.toFloat()).toDouble()).toInt()
29 | setMeasuredDimension(width, height)
30 | } else {
31 | super.onMeasure(widthMeasureSpec, heightMeasureSpec)
32 | }
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 爬小说
2 | 我们不生产小说,我们只做网站的搬运工,
3 | [](https://github.com/AoEiuV020/PaNovel/releases)
4 | [](https://github.com/AoEiuV020/PaNovel/actions)
5 | [](https://t.me/PaNovelGroup)
6 |
7 | ## 应用简介
8 | 这是有理想的小说神器,目前支持<35>个网站,
9 | 支持阅读本地.txt以及.epub小说,
10 |
11 | 【库】
12 | kotlin + mvp + room
13 | [jsoup](https://github.com/jhy/jsoup)
14 | [glide](https://github.com/bumptech/glide)
15 | [anko](https://github.com/Kotlin/anko)
16 | [MaterialSearchView](https://github.com/MiguelCatalan/MaterialSearchView)
17 | [slf4j](https://github.com/qos-ch/slf4j)
18 | [gson](https://github.com/google/gson)
19 | [ColorPicker](https://github.com/QuadFlask/colorpicker)
20 | [MagicIndicator](https://github.com/hackware1993/MagicIndicator)
21 | [NovelReader](https://github.com/newbiechen1024/NovelReader)
22 | [Bugly](https://github.com/BuglyDevTeam/Bugly-Android)
23 | [Zip4j](https://mvnrepository.com/artifact/net.lingala.zip4j/zip4j)
24 | [AspectRatioImageView](https://github.com/santalu/aspect-ratio-imageview)
25 | [jchardet](http://jchardet.sourceforge.net/index.html)
26 |
27 | 
28 | 
29 | 
30 |
--------------------------------------------------------------------------------
/app/src/test/java/cc/aoeiuv020/panovel/share/PasteUbuntuTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.share
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Assert.assertTrue
5 | import org.junit.Before
6 | import org.junit.Test
7 |
8 | /**
9 | *
10 | * Created by AoEiuV020 on 2018.03.07-19:31:38.
11 | */
12 | class PasteUbuntuTest {
13 | private lateinit var paste: PasteUbuntu
14 | private val text = "PasteUbuntuTest"
15 | @Before
16 | fun setUp() {
17 | paste = PasteUbuntu()
18 | }
19 |
20 | @Test
21 | fun upload() {
22 | val link = paste.upload(PasteUbuntu.PasteUbuntuData(text, expiration = Expiration.DAY))
23 | println(link)
24 | assertTrue(link.matches(Regex("https://paste.ubuntu.com/p/\\w*/")))
25 | val receive = paste.download(link)
26 | assertEquals(text, receive)
27 | }
28 |
29 | @Test
30 | fun download() {
31 | val receive = paste.download("https://paste.ubuntu.com/p/CH3g747q9S/")
32 | assertEquals("""{
33 | "list": [
34 | {
35 | "author": "二目",
36 | "name": "放开那个女巫",
37 | "requester": {
38 | "type": "cc.aoeiuv020.panovel.api.DetailRequester",
39 | "extra": "https://book.qidian.com/info/1003306811"
40 | },
41 | "site": "起点中文"
42 | }
43 | ],
44 | "name": "bs"
45 | }""", receive)
46 | }
47 |
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/cc/aoeiuv020/panovel/data/entity/NovelWithProgress.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.data.entity
2 |
3 | /**
4 | * Created by AoEiuV020 on 2018.05.31-12:48:03.
5 | */
6 | data class NovelWithProgress(
7 | /**
8 | * 网站名,
9 | * 必须存在,不可空,一本小说至少要有["site", "author“, ”name", "detail"],
10 | * 不外键到网站表,那张表不稳定,
11 | */
12 | var site: String,
13 | /**
14 | * 作者名,
15 | * 必须存在,不可空,一本小说至少要有["site", "author“, ”name", "detail"],
16 | */
17 | var author: String,
18 | /**
19 | * 小说名,
20 | * 必须存在,不可空,一本小说至少要有["site", "author“, ”name", "detail"],
21 | */
22 | var name: String,
23 | /**
24 | * 用于请求小说详情页的额外信息,
25 | * 必须存在,不可空,一本小说至少要有["site", "author“, ”name", "detail"],
26 | * [cc.aoeiuv020.panovel.api.NovelItem.extra]
27 | */
28 | var detail: String,
29 |
30 | // 阅读进度,
31 |
32 | /**
33 | * 阅读进度,
34 | * 阅读至的章节索引,
35 | */
36 | var readAtChapterIndex: Int = 0,
37 | /**
38 | * 章节内的阅读进度,
39 | * 看到第几页或者第几个字,具体没决定,
40 | */
41 | var readAtTextIndex: Int = 0
42 | ) {
43 | constructor(novel: Novel)
44 | : this(novel.site, novel.author, novel.name, novel.detail, novel.readAtChapterIndex, novel.readAtTextIndex)
45 | }
--------------------------------------------------------------------------------
/reader/src/main/java/cc/aoeiuv020/reader/INovelReader.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.reader
2 |
3 | import android.content.Context
4 | import java.util.concurrent.ExecutorService
5 | import java.util.concurrent.Executors
6 |
7 | /**
8 | *
9 | * Created by AoEiuV020 on 2017.12.01-02:13:39.
10 | */
11 | interface INovelReader {
12 | val ctx: Context
13 |
14 | var novel: String
15 |
16 | var readingListener: ReadingListener?
17 | var menuListener: MenuListener?
18 |
19 | var requester: TextRequester
20 | var chapterList: List
21 |
22 | var currentChapter: Int
23 | var textProgress: Int
24 | val maxTextProgress: Int
25 |
26 | val config: ReaderConfig
27 |
28 | fun refreshCurrentChapter()
29 |
30 | fun scrollNext(): Boolean
31 | fun scrollPrev(): Boolean
32 |
33 | fun destroy()
34 | }
35 |
36 | abstract class BaseNovelReader(override var novel: String, override var requester: TextRequester) : INovelReader {
37 | override var readingListener: ReadingListener? = null
38 | override var menuListener: MenuListener? = null
39 | override var chapterList: List = emptyList()
40 | // 独立的线程池用于请求小说章节,不要用anko-common自带的以免导致阻塞,
41 | val ioExecutorService: ExecutorService = Executors.newCachedThreadPool()
42 |
43 | override fun scrollNext(): Boolean = false
44 | override fun scrollPrev(): Boolean = false
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/GulizwTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by AoEiuV020 on 2018.06.03-22:26:59.
7 | */
8 | class GulizwTest : BaseNovelContextText(Gulizw::class) {
9 | @Test
10 | fun search() {
11 | // ProtocolException: Unexpected status line: ?�????????????��??????????HTTP/1.1 302 Moved Temporarily
12 | search("都市")
13 | search("一念永恒", "耳根", "94719")
14 | search("我是至尊", "风凌天下", "5141")
15 | }
16 |
17 | @Test
18 | fun detail() {
19 | detail("94719", "94719", "一念永恒", "耳根",
20 | "http://www.gulizw.com/files/article/image/94/94719/94719s.jpg",
21 | "一念成沧海,一念化桑田。一念斩千魔,一念诛万仙。唯我念……永恒",
22 | "2018-02-09 00:00:00")
23 | }
24 |
25 | @Test
26 | fun chapters() {
27 | chapters("52771", "第1章 黄山真君和九洲一号群", "52771/20455308", null,
28 | "第1743章 你就不能给我正常的晋升一回吗?", "52771/37939770", null,
29 | 1824)
30 | chapters("94719", "外传1 柯父。", "94719/28723558", null,
31 | "第1314章 你的选择(终)3", "94719/37928328", null,
32 | 1529)
33 | }
34 |
35 | @Test
36 | fun content() {
37 | content("94719/37928328",
38 | "画面在这一刻,成为了永恒,渐渐模糊,直至消散。",
39 | "六月一号,不见不散!",
40 | 21)
41 | }
42 |
43 | }
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/YmoxuanTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by AoEiuV020 on 2018.06.03-13:57:34.
7 | */
8 | class YmoxuanTest : BaseNovelContextText(Ymoxuan::class) {
9 | @Test
10 | fun search() {
11 | search("都市")
12 | search("斗战狂潮", "骷髅精灵", "31577")
13 | search("大主宰", "天蚕土豆", "21825")
14 | }
15 |
16 | @Test
17 | fun detail() {
18 | detail("31577", "31577", "斗战狂潮", "骷髅精灵",
19 | "http://r.m.ymxxs.com/jieqi/cover/31/31577/31577s.jpg",
20 | "双月当空,无限可能的英魂世界\n" +
21 | "孤寂黑暗,神秘古怪的嬉命小丑\n" +
22 | "百城联邦,三大帝国,异族横行,魂兽霸幽\n" +
23 | "这是一个英雄辈出的年代,人类卧薪尝胆重掌地球主权,孕育着进军高纬度的野望!\n" +
24 | "重点是……二年级的废柴学长王同学,如何使用嬉命轮盘,撬动整个世界,伙伴们,请注意,学长来了!!!",
25 | "2018-06-03 00:04:00")
26 | }
27 |
28 | @Test
29 | fun chapters() {
30 | chapters("31577", "第一章 嬉命小丑", "31/31577/29700048", null,
31 | "12月1日,英雄联盟:我的时代!", "31/31577/172511130", null,
32 | 1245)
33 | }
34 |
35 | @Test
36 | fun content() {
37 | content("31/31577/29700048",
38 | "欲望是进步的动力,也孕育了毁灭。",
39 | "小丑的脸一下子跨了下来,“什么小狗,我是嬉命小丑辛巴,戏弄命运,无所不能,小孩,你摊上大事儿了!”",
40 | 28)
41 | }
42 |
43 | }
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/Jdxs520Test.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by AoEiuV020 on 2018.06.03-18:50:03.
7 | */
8 | class Jdxs520Test : BaseNovelContextText(Jdxs520::class) {
9 | @Test
10 | fun search() {
11 | // 这网站可能搜索结果可能随机出现乱码开头,刷新又好,
12 | search("都市")
13 | search("念念不忘,总裁乘胜追妻", "七爷", "77903")
14 | search("圣墟", "辰东", "45887")
15 | }
16 |
17 | @Test
18 | fun detail() {
19 | detail("77903", "77903", "念念不忘,总裁乘胜追妻", "七爷",
20 | "https://www.jdxs5200.net/files/article/image/77/77903/77903s.jpg",
21 | "初见,她在下,他在上,他的口中叫着别人的名字。\n" +
22 | "再见,她衣裳凌乱,披头散发,被人屈辱按在地上,狼狈不堪……\n" +
23 | "他是人人敬畏的传奇人物,霍家太子爷。\n" +
24 | "顺手救下她,冷漠送她四个字“咎由自取!”\n" +
25 | "狼狈的她,却露出一抹明媚的笑,声音清脆“姐夫……谢谢啊!”",
26 | "2018-06-02 21:52:00")
27 | }
28 |
29 | @Test
30 | fun chapters() {
31 | chapters("77903", "第1章 错位替身", "77903/45183134", null,
32 | "第148章 重新开始", "77903/46358897", "2018-06-02 21:52:00",
33 | 148)
34 | }
35 |
36 | @Test
37 | fun content() {
38 | content("77903/45183134",
39 | "十二月的南城很冷很冷。",
40 | "从此,她们之间就没有了交集。",
41 | 45)
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/LreadTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by AoEiuV020 on 2018.06.03-19:36:18.
7 | */
8 | class LreadTest : BaseNovelContextText(Lread::class) {
9 | @Test
10 | fun search() {
11 | search("都市")
12 | search("飞剑问道", "我吃西红柿", "88917")
13 | }
14 |
15 | @Test
16 | fun detail() {
17 | detail("88917", "88917", "飞剑问道", "我吃西红柿",
18 | "https://www.6ks.net/files/article/image/88/88917/88917s.jpg",
19 | "在这个世界,有狐仙、河神、水怪、大妖,也有求长生的修行者。\n" +
20 | "修行者们,\n" +
21 | "开法眼,可看妖魔鬼怪。\n" +
22 | "炼一口飞剑,可千里杀敌。\n" +
23 | "千里眼、顺风耳,更可探查四方。\n" +
24 | "……\n" +
25 | "秦府二公子‘秦云’,便是一位修行者……",
26 | "2018-06-03 00:15:00")
27 | }
28 |
29 | @Test
30 | fun chapters() {
31 | chapters("88917", "第一章 归来", "88917/32771268", null,
32 | "第十一篇 第八章 魔神世界的帝君", "88917/40963324", "2018-06-03 00:15:00",
33 | 679)
34 | }
35 |
36 | @Test
37 | fun content() {
38 | content("88917/40963324",
39 | "“死!”",
40 | "那模糊庞大身影沉默了片刻,才道:“在蛮祖教布置的一切,全部毁掉,不留任何痕迹。不能让神霄道人他们查出来!至于你们四个,放弃蛮祖教,想办法逃命吧。”",
41 | 64)
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/ByzwTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by AoEiuV020 on 2018.06.02-19:48:12.
7 | */
8 | class ByzwTest : BaseNovelContextText(Byzw::class) {
9 | @Test
10 | fun search() {
11 | search("都市")
12 | search("道君", "跃千愁", "28675")
13 | search("蛊真人", "蛊真人", "7900")
14 | }
15 |
16 | @Test
17 | fun detail() {
18 | detail("7900", "7900", "蛊真人", "蛊真人",
19 | "https://www.81book.com/files/article/image/7/7900/7900s.jpg",
20 | "人是万物之灵,蛊是天地真精。\n" +
21 | "三观不正,魔头重生。\n" +
22 | "昔日旧梦,同名新作。\n" +
23 | "一个穿越者不断重生的故事。\n" +
24 | "一个养蛊、炼蛊、用蛊的奇特世界。\n" +
25 | "春秋蝉、月光蛊、酒虫、一气金光虫、青丝蛊、希望蛊……\n" +
26 | "还有一个纵情纵横的绝世大魔头!",
27 | "2018-06-02 19:01:52")
28 | }
29 |
30 | @Test
31 | fun chapters() {
32 | chapters("7900", "序:不是走向成功,就是走向毁灭", "7900/234025", null,
33 | "今天无更", "7900/13073827", "2018-06-02 19:01:52",
34 | 2038)
35 | }
36 |
37 | @Test
38 | fun content() {
39 | content("7900/234025",
40 | "在过去的几个月内,我经历了生活赐予的痛苦,并且身心都在其中挣扎。",
41 | "看更新最快的武动乾坤最新章节Www.81zw.Com",
42 | 60)
43 | }
44 |
45 | }
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/PiaotianTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | *
7 | * Created by AoEiuV020 on 2017.10.02-16:07:05.
8 | */
9 | class PiaotianTest : BaseNovelContextText(Piaotian::class) {
10 | @Test
11 | fun search() {
12 | search("都市")
13 | search("都市之位面旅行家", "书仙鱼", "8/8017")
14 | search("斗破苍穹之无上之境", "夜雨闻铃0", "1/1767")
15 | search("从前有座灵剑山", "国王陛下", "4/4316")
16 | }
17 |
18 | @Test
19 | fun detail() {
20 | detail(
21 | "8/8605", "8/8605", "剑灵同居日记", "国王陛下",
22 | "https://www.ptwxz.com/files/article/image/8/8605/8605s.jpg",
23 | "“天外神剑剑灵,应呼唤而苏醒,我问你,你就是我的坐骑么?”\n一个无敌的随身剑灵与天才美少女(们)的同居故事。",
24 | "2018-05-21 17:30:00"
25 | )
26 | }
27 |
28 | @Test
29 | fun chapters() {
30 | chapters("4/4316", "序幕:天外飞仙+第一章:客栈柴房温暖如春", "4/4316/2216316", null,
31 | "第七十七章:再见", "4/4316/4260402", null,
32 | 852)
33 | chapters("8/8912",
34 | "第001章 狂暴系统", "8/8912/5786830", null,
35 | "第3568章 大道无门?(补一)", "8/8912/6442359", null,
36 | 3564)
37 | }
38 |
39 | @Test
40 | fun content() {
41 | content("8/8605/5582838",
42 | "6月1日凌晨0点,本书正式上架。",
43 | "请各位绅士们量力而行,不必强求逆天。",
44 | 21)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/YunduwuTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by AoEiuV020 on 2020.03.28-23:30:33.
7 | */
8 | class YunduwuTest : BaseNovelContextText(Yunduwu::class) {
9 | @Test
10 | fun search() {
11 | search("书")
12 | search("曾国藩家书", "曾国藩", "607")
13 | }
14 |
15 | @Test
16 | fun detail() {
17 | detail("607", "607", "曾国藩家书", "曾国藩",
18 | "https://www.yunduwu.com/upload/novel/20191116/157387546035259.jpg",
19 | "愚于近人,独服曾文正,观其收拾洪杨一役,完满无缺。使以今人易其位,其能如彼之完满乎?\n" +
20 | "——毛泽东1917年8月23日致黎锦熙\n" +
21 | "何兆武说:“中国历史上真正能够做到立德,立功,立言的只有二人:王阳明,曾国藩。”\n" +
22 | "曾国藩是中国近代史上权位显赫、作用极大、很有影响的人物,又是一个复杂的人物,近代中国人尤其湖南人,从权贵政要、志士仁人到青年学子,大多佩服曾国藩,佩服其治学为人和带兵做事。从李鸿章、张之洞到袁世凯、蒋介石,无不对他顶礼膜拜,尊为“圣哲”;从梁启超到杨昌济,从陈独秀到毛泽东,也无不表示过推崇其师法,受过其人的种种影响。",
23 | "2019-11-16 11:47:26")
24 | }
25 |
26 | @Test
27 | fun chapters() {
28 | chapters("607", "前言", "607/3576", null,
29 | "同治十年十月二十三日", "607/3631", null,
30 | 56)
31 | }
32 |
33 | @Test
34 | fun content() {
35 | content("607/3631",
36 | "澄、沅两弟左右:",
37 | "为兄在外两个多月,应酬太过繁忙,眩晕和疝气等毛病幸好没有复发,脚肿的毛病也好了。只是老眼昏花,一天比一天厉害;小便也太过频繁。衰弱和年老逼人,是当然之理,不值为怪。",
38 | 21)
39 | }
40 | }
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/GuanshuwangTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by AoEiuV020 on 2018.06.03-18:17:22.
7 | */
8 | class GuanshuwangTest : BaseNovelContextText(Guanshuwang::class) {
9 | @Test
10 | fun search() {
11 | search("都市")
12 | search("剑来", "烽火戏诸侯", "86/86047")
13 | search("天道图书馆", "横扫天涯", "86/86950")
14 | }
15 |
16 | @Test
17 | fun detail() {
18 | detail("86/86047", "86/86047", "剑来", "烽火戏诸侯",
19 | "https://www.guanshu.cc/coverimages/86/86047/86047s.jpg",
20 | "大千世界,无奇不有。" +
21 | "我陈平安,唯有一剑,可搬山,倒海,降妖,镇魔,敕神,摘星,断江,摧城,开天!",
22 | "2018-06-01 23:59:55")
23 | }
24 |
25 | @Test
26 | fun chapters() {
27 | chapters("86/86047", "新书感言", "86/86047/2336", null,
28 | "第三百一十一章 人外有人", "86/86047/1110517", "2018-06-01 23:59:55",
29 | 313)
30 | }
31 |
32 | @Test
33 | fun content() {
34 | content("86/86047/2336",
35 | "新书的重心在于“构建一个光怪陆离却合理有趣的仙侠世界”,对于一个崭新世界基础构建," +
36 | "即人与精怪鬼魅如何共处人间,会比较花力气和心思。当然,“传统”仙侠的套路,也会有,也是必然是不可或缺的。",
37 | "新书框架很大,写的时候会越来越大,但我有信心把那个世界写得有意思,也会很注重故事和人物之间的平衡," +
38 | "“珠子以线串成珠帘”,琳琅满目,毕竟是一件很美好的事物。世间好物不坚牢,彩云易散琉璃脆。那咱们就从小说里找补回来,多好。",
39 | 6)
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/LiudatxtTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | *
7 | * Created by AoEiuV020 on 2017.10.11-21:00:18.
8 | */
9 | class LiudatxtTest : BaseNovelContextText(Liudatxt::class) {
10 | @Test
11 | fun search() {
12 | search("都市")
13 | search("诸天万界反派聊天群", "不要尬舞", "22921")
14 | }
15 |
16 | @Test
17 | fun detail() {
18 | detail("22921", "22921", "诸天万界反派聊天群", "不要尬舞",
19 | "http://www.txtshuku.org/headimgs/22/22921/s22921.jpg",
20 | "这个穿越画风有些不对?开局就是地狱难度是个什么鬼?还好自带一个金手指。\n" +
21 | "从此以后踏上了诸天万界各大反派人生导师的不归路!露出一脸和善微笑的雄霸正指挥着风云怒肛帝释天、" +
22 | "海贼世界已经成为一个出色海军的路飞正带着自己的海军攻打四皇、" +
23 | "以及把令狐冲当做亲儿子一般的对待满脸正气的岳不群。\n" +
24 | "......刘锋叹了一...",
25 | "2018-04-26 21:42:32")
26 | }
27 |
28 | @Test
29 | fun chapters() {
30 | chapters("22921", "第1章 穿越到噩梦难度的世界该怎么办?", "22921/8412231", null,
31 | "第584章 自信的零充", "22921/11561166", "2018-05-21 20:15:40",
32 | 610)
33 | }
34 |
35 | @Test
36 | fun content() {
37 | content("22921/8710426",
38 | "“你是怪物吗?!”这会儿刘锋是真的被面前这个身上血迹斑斑的哥们给惊着了,卧槽,二十多刀刀刀避开要害,简直是人才!",
39 | "顺带一提,为了避免实力一样引起的怀疑,刘锋稍稍的将刘淼这个账号的实力水平降低了一点设定在二级。",
40 | 37)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/BiqugeTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | *
7 | * Created by AoEiuV020 on 2017.10.08-21:52:04.
8 | */
9 | class BiqugeTest : BaseNovelContextText(Biquge::class) {
10 | @Test
11 | fun search() {
12 | search("都市")
13 | search("最大权限", "肥鱼马甲", "18156")
14 | search("都市酒仙系统", "酒剑仙人", "19679")
15 | }
16 |
17 | @Test
18 | fun detail() {
19 | detail(
20 | "18156", "18156", "最大权限", "肥鱼马甲",
21 | "https://www.biqugee.com/cover/18/18156/18156s.jpg",
22 | "制作游戏成功的林陨意外猝死,穿越到自己制作的游戏世界,结果拥有了这个世界的最大权限!\n" +
23 | "最大权限书友群:305908807",
24 | "2018-04-26 21:42:32"
25 | )
26 | }
27 |
28 | @Test
29 | fun chapters() {
30 | chapters("18156", "序章", "18156/7491883", null,
31 | "第505章 格斗", "18156/9637191", "2018-04-25 21:42:32",
32 | 515)
33 | chapters("18156", "序章", "18156/7491883", null,
34 | "关于本书和新书的一些事情", "18156/10188197", "2018-04-26 21:42:32",
35 | 516)
36 | }
37 |
38 | @Test
39 | fun content() {
40 | content("18156/8791124",
41 | "中年男子下意识的接住魂晶,这东西能够让卡片使更好的修炼魂力,可以说是硬通货,属于最高等的金钱。",
42 | "“没什么,绿色级别吗,这不是问题。”林陨摇了摇头,接着拿出一张卡片,直接激发,同时林陨的气息也迅速增强,瞬间魂力翻倍,直接突破一千,迈过绿色级别的门槛。",
43 | 38)
44 | }
45 | }
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/DajiaduTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Created by AoEiuV020 on 2018.06.06-15:28:17.
7 | */
8 | class DajiaduTest : BaseNovelContextText(Dajiadu::class) {
9 | @Test
10 | fun search() {
11 | // 这网站搜索可能随机失败,刷新又好,
12 | search("都市")
13 | search("修真聊天群", "圣骑士的传说", "24/24478")
14 | }
15 |
16 | @Test
17 | fun detail() {
18 | detail(
19 | "24/24478", "24/24478", "修真聊天群", "圣骑士的传说",
20 | "https://www.dajiadu8.com/files/article/image/24/24478/24478s.jpg",
21 | "某天,宋书航意外加入了一个仙侠中二病资深患者的交流群,里面的群友们都以‘道友’相称,群名片都是各种府主、洞主、真人、天师。连群主走失的宠物犬都称为大妖犬离家出走。整天聊的是炼丹、闯秘境、炼功经验啥的。\n" +
22 | "突然有一天,潜水良久的他突然发现……群里每一个群员,竟然全部是修真者,能移山倒海、长生千年的那种!\n" +
23 | "啊啊啊啊,世界观在一夜间彻底崩碎啦!\n" +
24 | "(本站郑重提醒:本故事纯属虚构,如有雷同,纯属巧合,切勿模仿。)",
25 | null
26 | )
27 | }
28 |
29 | @Test
30 | fun chapters() {
31 | chapters(
32 | "24/24478", "书友群", "24/24478/7005434", null,
33 | "新书上传啦,《万界点名册》", "24/24478/14761299", null,
34 | 3229
35 | )
36 | }
37 |
38 | @Test
39 | fun content() {
40 | content("23/23752/11507981",
41 | "矫若惊龙,漂若浮云,宣纸上的“咏箸”宛若一条蛟龙破纸而出,搅动一室浩然正气和灵气,震惊了场中众人。",
42 | "bq",
43 | 62)
44 | }
45 |
46 | }
--------------------------------------------------------------------------------
/api/src/test/java/cc/aoeiuv020/panovel/api/site/BiqugeseTest.kt:
--------------------------------------------------------------------------------
1 | package cc.aoeiuv020.panovel.api.site
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | *
7 | * Created by AoEiuV020 on 2017.10.08-21:52:04.
8 | */
9 | class BiqugeseTest : BaseNovelContextText(Biqugese::class) {
10 | @Test
11 | fun search() {
12 | search("都市")
13 | search("系统和我不匹配", "此梦当醒", "67191")
14 | }
15 |
16 | @Test
17 | fun detail() {
18 | detail("67191", "67191", "系统和我不匹配", "此梦当醒",
19 | "http://www.bqxs520.com/cover/20200830/31c621903ffe48a3c8919934bb35ee83.jpg",
20 | "通俗版:穿越了,带着游戏《神尊》中的最强剑士账号,但想象中的平推异世界却没有发生,毕竟游戏角色【极恶·至善·漆黑之光】跟我吴羽又有什么关系呢!\n" +
21 | "“狗系统,你倒是把属性点加到我的本体上面啊!”此乃吴羽每晚都会发出的绝望咆哮。\n" +
22 | "正式版:每一个世界都是用来封印神明的囚笼,而凡人们更愿意称那位神明为魔王,只因祂突破封印的方法被我们称之为——灭世。\n" +
23 | "ps:其实这就是某条咸鱼费尽心思重塑自己左手的故事。",
24 | "2021-01-02 00:00:00")
25 | }
26 |
27 | @Test
28 | fun chapters() {
29 | chapters("67191", "第1章我和狗系统的初遇", "67191/75496627", null,
30 | "第20章不变的初衷", "67191/80104630", "2021-01-02 00:00:00",
31 | 164)
32 | }
33 |
34 | @Test
35 | fun content() {
36 | content("67191/78029901",
37 | "在光明教会的地下,存在着许多不为人知的密室,而其中有一处,则是只有历代教皇才能够出入的禁地。",
38 | "“还跟我装傻呢?”吴羽也懒得继续都圈子了,直接说道“那我问你,你把菲尔利斯卖给那群强盗,你到底收了他们多少好处费啊?”",
39 | 91)
40 | }
41 | }
--------------------------------------------------------------------------------