Merge branch 'gedoor:master' into master
@@ -95,7 +95,7 @@ https://gedoor.github.io/about.html
|
||||
* [书源规则](https://alanskycn.gitee.io/teachme)
|
||||
* [更新日志](/app/src/main/assets/updateLog.md)
|
||||
* [帮助文档](/app/src/main/assets/help/appHelp.md)
|
||||
* [web端](https://github.com/celetor/web-yuedu3)
|
||||
* [web端](https://github.com/gedoor/legado_web_bookshelf)
|
||||
|
||||
<a href="#readme">
|
||||
<img src="https://img.shields.io/badge/-返回顶部-orange.svg" alt="#" align="right">
|
||||
|
||||
@@ -11,6 +11,12 @@
|
||||
* 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。
|
||||
* 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
|
||||
|
||||
**2022/03/02**
|
||||
|
||||
* ~~js引擎rhino升级到1.7.4~~
|
||||
* 优化web端,修复一些封面无法访问bug,代理正文图片
|
||||
* 其它一些优化
|
||||
|
||||
**2022/02/28**
|
||||
|
||||
* APP内编写规则时,对由XPath|JSOUP|CSS组成的规则进行简单的默认补全。需手动开启,单次生效
|
||||
|
||||
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 799 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -1,149 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="16.000000pt" height="16.000000pt" viewBox="0 0 16.000000 16.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,16.000000) scale(0.000320,-0.000320)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M18 46618 c45 -75 122 -207 122 -211 0 -2 25 -45 55 -95 30 -50 55
|
||||
-96 55 -102 0 -5 5 -10 10 -10 6 0 10 -4 10 -9 0 -5 73 -135 161 -288 89 -153
|
||||
173 -298 187 -323 14 -25 32 -57 41 -72 88 -149 187 -324 189 -335 2 -7 8 -13
|
||||
13 -13 5 0 9 -4 9 -10 0 -5 46 -89 103 -187 175 -302 490 -846 507 -876 8 -16
|
||||
20 -36 25 -45 28 -46 290 -498 339 -585 13 -23 74 -129 136 -236 61 -107 123
|
||||
-215 137 -240 14 -25 29 -50 33 -56 5 -5 23 -37 40 -70 18 -33 38 -67 44 -75
|
||||
11 -16 21 -33 63 -109 14 -25 29 -50 33 -56 4 -5 21 -35 38 -65 55 -100 261
|
||||
-455 269 -465 4 -5 14 -21 20 -35 15 -29 41 -75 103 -180 24 -41 52 -88 60
|
||||
-105 9 -16 57 -100 107 -185 112 -193 362 -626 380 -660 8 -14 23 -38 33 -55
|
||||
11 -16 23 -37 27 -45 4 -8 26 -46 48 -85 23 -38 53 -90 67 -115 46 -81 64
|
||||
-113 178 -310 62 -107 121 -210 132 -227 37 -67 56 -99 85 -148 16 -27 32 -57
|
||||
36 -65 4 -8 15 -27 25 -42 9 -15 53 -89 96 -165 44 -76 177 -307 296 -513 120
|
||||
-206 268 -463 330 -570 131 -227 117 -203 200 -348 36 -62 73 -125 82 -140 10
|
||||
-15 21 -34 25 -42 4 -8 20 -37 36 -65 17 -27 38 -65 48 -82 49 -85 64 -111 87
|
||||
-153 13 -25 28 -49 32 -55 4 -5 78 -134 165 -285 87 -151 166 -288 176 -305
|
||||
10 -16 26 -43 35 -59 9 -17 125 -217 257 -445 132 -229 253 -441 270 -471 17
|
||||
-30 45 -79 64 -108 18 -29 33 -54 33 -57 0 -2 20 -37 44 -77 24 -40 123 -212
|
||||
221 -383 97 -170 190 -330 205 -355 16 -25 39 -65 53 -90 13 -25 81 -144 152
|
||||
-265 70 -121 137 -238 150 -260 12 -22 37 -65 55 -95 18 -30 43 -73 55 -95 12
|
||||
-22 48 -85 80 -140 77 -132 163 -280 190 -330 13 -22 71 -123 130 -225 59
|
||||
-102 116 -199 126 -217 10 -17 29 -50 43 -72 15 -22 26 -43 26 -45 0 -2 27
|
||||
-50 60 -106 33 -56 60 -103 60 -105 0 -2 55 -98 90 -155 8 -14 182 -316 239
|
||||
-414 13 -22 45 -79 72 -124 27 -46 49 -86 49 -89 0 -2 14 -24 30 -48 16 -24
|
||||
30 -46 30 -49 0 -5 74 -135 100 -176 5 -8 24 -42 43 -75 50 -88 58 -101 262
|
||||
-455 104 -179 199 -345 213 -370 14 -25 28 -49 32 -55 4 -5 17 -26 28 -45 10
|
||||
-19 62 -109 114 -200 114 -197 133 -230 170 -295 16 -27 33 -57 38 -65 17 -28
|
||||
96 -165 103 -180 4 -8 16 -28 26 -45 10 -16 77 -131 148 -255 72 -124 181
|
||||
-313 243 -420 62 -107 121 -209 131 -227 35 -62 323 -560 392 -678 38 -66 83
|
||||
-145 100 -175 16 -30 33 -59 37 -65 4 -5 17 -27 29 -47 34 -61 56 -100 90
|
||||
-156 17 -29 31 -55 31 -57 0 -2 17 -32 39 -67 21 -35 134 -229 251 -433 117
|
||||
-203 235 -407 261 -451 27 -45 49 -85 49 -88 0 -4 8 -19 19 -34 15 -21 200
|
||||
-341 309 -533 10 -19 33 -58 51 -87 17 -29 31 -54 31 -56 0 -2 25 -44 55 -94
|
||||
30 -50 55 -95 55 -98 0 -4 6 -15 14 -23 7 -9 27 -41 43 -71 17 -30 170 -297
|
||||
342 -594 171 -296 311 -542 311 -547 0 -5 5 -9 10 -9 6 0 10 -4 10 -10 0 -5
|
||||
22 -47 49 -92 27 -46 58 -99 68 -118 24 -43 81 -140 93 -160 5 -8 66 -114 135
|
||||
-235 69 -121 130 -227 135 -235 12 -21 259 -447 283 -490 10 -19 28 -47 38
|
||||
-62 11 -14 19 -29 19 -32 0 -3 37 -69 83 -148 99 -170 305 -526 337 -583 13
|
||||
-22 31 -53 41 -70 11 -16 22 -37 26 -45 7 -14 82 -146 103 -180 14 -24 181
|
||||
-311 205 -355 13 -22 46 -80 75 -130 29 -49 64 -110 78 -135 14 -25 51 -88 82
|
||||
-140 31 -52 59 -102 63 -110 4 -8 18 -33 31 -55 205 -353 284 -489 309 -535
|
||||
17 -30 45 -78 62 -106 18 -28 36 -60 39 -72 4 -12 12 -22 17 -22 5 0 9 -4 9
|
||||
-10 0 -5 109 -197 241 -427 133 -230 250 -431 259 -448 51 -90 222 -385 280
|
||||
-485 37 -63 78 -135 92 -160 14 -25 67 -117 118 -205 51 -88 101 -175 111
|
||||
-193 34 -58 55 -95 149 -257 51 -88 101 -173 110 -190 9 -16 76 -131 147 -255
|
||||
72 -124 140 -241 151 -260 61 -108 281 -489 355 -615 38 -66 77 -133 87 -150
|
||||
35 -63 91 -161 100 -175 14 -23 99 -169 128 -220 54 -97 135 -235 142 -245 4
|
||||
-5 20 -32 35 -60 26 -48 238 -416 276 -480 10 -16 26 -46 37 -65 30 -53 382
|
||||
-661 403 -695 10 -16 22 -37 26 -45 4 -8 26 -48 50 -88 24 -41 43 -75 43 -77
|
||||
0 -2 22 -40 50 -85 27 -45 50 -84 50 -86 0 -3 38 -69 83 -147 84 -142 302
|
||||
-520 340 -587 10 -19 34 -60 52 -90 18 -30 44 -75 57 -100 14 -25 45 -79 70
|
||||
-120 25 -41 56 -96 70 -121 14 -25 77 -133 138 -240 62 -107 122 -210 132
|
||||
-229 25 -43 310 -535 337 -581 11 -19 26 -45 34 -59 17 -32 238 -414 266 -460
|
||||
11 -19 24 -41 28 -49 3 -7 75 -133 160 -278 84 -146 153 -269 153 -274 0 -5 5
|
||||
-9 10 -9 6 0 10 -4 10 -10 0 -5 82 -150 181 -322 182 -314 201 -346 240 -415
|
||||
12 -21 80 -139 152 -263 71 -124 141 -245 155 -270 14 -25 28 -49 32 -55 6 -8
|
||||
145 -248 220 -380 37 -66 209 -362 229 -395 11 -19 24 -42 28 -49 4 -8 67
|
||||
-118 140 -243 73 -125 133 -230 133 -233 0 -2 15 -28 33 -57 19 -29 47 -78 64
|
||||
-108 17 -30 53 -93 79 -139 53 -90 82 -141 157 -272 82 -142 115 -199 381
|
||||
-659 142 -245 268 -463 281 -485 12 -22 71 -125 132 -230 60 -104 172 -298
|
||||
248 -430 76 -132 146 -253 156 -270 11 -16 22 -36 26 -44 3 -8 30 -54 60 -103
|
||||
29 -49 53 -91 53 -93 0 -3 18 -34 40 -70 22 -36 40 -67 40 -69 0 -2 37 -66 81
|
||||
-142 45 -77 98 -168 119 -204 20 -36 47 -81 58 -100 12 -19 27 -47 33 -62 6
|
||||
-16 15 -28 20 -28 5 0 9 -4 9 -9 0 -6 63 -118 140 -251 77 -133 140 -243 140
|
||||
-245 0 -2 18 -33 41 -70 22 -37 49 -83 60 -101 10 -19 29 -51 40 -71 25 -45
|
||||
109 -189 126 -218 7 -11 17 -29 22 -40 6 -11 22 -38 35 -60 14 -22 37 -62 52
|
||||
-90 14 -27 35 -62 45 -77 11 -14 19 -29 19 -32 0 -3 18 -35 40 -71 22 -36 40
|
||||
-67 40 -69 0 -2 19 -35 42 -72 23 -38 55 -94 72 -124 26 -47 139 -244 171
|
||||
-298 6 -9 21 -36 34 -60 28 -48 37 -51 51 -19 6 12 19 36 29 52 10 17 27 46
|
||||
38 65 11 19 104 181 208 360 103 179 199 345 213 370 14 25 42 74 64 109 21
|
||||
34 38 65 38 67 0 2 18 33 40 69 22 36 40 67 40 69 0 3 177 310 199 346 16 26
|
||||
136 234 140 244 2 5 25 44 52 88 27 44 49 81 49 84 0 2 18 34 40 70 22 36 40
|
||||
67 40 69 0 2 20 36 43 77 35 58 169 289 297 513 9 17 50 86 90 155 40 69 86
|
||||
150 103 180 16 30 35 62 41 70 6 8 16 24 22 35 35 64 72 129 167 293 59 100
|
||||
116 199 127 220 11 20 30 53 41 72 43 72 1070 1850 1121 1940 14 25 65 113
|
||||
113 195 48 83 96 166 107 185 10 19 28 50 38 68 11 18 73 124 137 235 64 111
|
||||
175 303 246 427 71 124 173 299 225 390 52 91 116 202 143 248 27 45 49 85 49
|
||||
89 0 4 6 14 14 22 7 9 28 43 46 76 26 47 251 436 378 655 11 19 29 51 40 70
|
||||
11 19 101 176 201 348 99 172 181 317 181 323 0 5 5 9 10 9 6 0 10 5 10 11 0
|
||||
6 8 23 18 37 11 15 32 52 49 82 16 30 130 228 253 440 122 212 234 405 248
|
||||
430 13 25 39 70 57 100 39 65 69 117 130 225 25 44 50 87 55 95 12 19 78 134
|
||||
220 380 61 107 129 224 150 260 161 277 222 382 246 425 15 28 47 83 71 123
|
||||
24 41 43 78 43 83 0 5 4 9 8 9 4 0 13 12 19 28 7 15 23 45 36 67 66 110 277
|
||||
478 277 483 0 3 6 13 14 21 7 9 27 41 43 71 17 30 45 80 63 110 34 57 375 649
|
||||
394 685 6 11 16 27 22 35 6 8 26 42 44 75 18 33 41 74 51 90 10 17 24 41 32
|
||||
55 54 97 72 128 88 152 11 14 19 28 19 30 0 3 79 141 175 308 96 167 175 305
|
||||
175 308 0 3 6 13 14 21 7 9 26 39 41 66 33 60 276 483 338 587 24 40 46 80 50
|
||||
88 4 8 13 24 20 35 14 23 95 163 125 215 11 19 52 91 92 160 40 69 80 139 90
|
||||
155 9 17 103 179 207 360 105 182 200 346 211 365 103 181 463 802 489 845 7
|
||||
11 15 27 19 35 4 8 29 51 55 95 64 110 828 1433 848 1470 9 17 24 41 33 55 9
|
||||
14 29 48 45 77 15 28 52 93 82 145 30 51 62 107 71 123 17 30 231 398 400 690
|
||||
51 88 103 179 115 202 12 23 26 48 32 55 6 7 24 38 40 68 17 30 61 107 98 170
|
||||
37 63 84 144 103 180 19 36 41 72 48 81 8 8 14 18 14 21 0 4 27 51 59 106 32
|
||||
55 72 124 89 154 16 29 71 125 122 213 51 88 104 180 118 205 13 25 28 50 32
|
||||
55 4 6 17 26 28 45 11 19 45 80 77 135 31 55 66 116 77 135 11 19 88 152 171
|
||||
295 401 694 620 1072 650 1125 11 19 87 152 170 295 83 143 158 273 166 288 9
|
||||
16 21 36 26 45 6 9 31 52 55 96 25 43 54 94 66 115 11 20 95 164 186 321 91
|
||||
157 173 299 182 315 9 17 26 46 37 65 12 19 66 114 121 210 56 96 108 186 117
|
||||
200 8 14 24 40 34 59 24 45 383 664 412 713 5 9 17 29 26 45 15 28 120 210
|
||||
241 419 36 61 68 117 72 125 4 8 12 23 19 34 35 57 245 420 262 453 11 20 35
|
||||
61 53 90 17 29 32 54 32 56 0 3 28 51 62 108 33 57 70 119 80 138 10 19 23 42
|
||||
28 50 5 8 32 53 59 100 27 47 149 258 271 470 122 212 234 405 248 430 30 53
|
||||
62 108 80 135 6 11 15 27 19 35 4 8 85 150 181 315 96 165 187 323 202 350 31
|
||||
56 116 202 130 225 5 8 25 42 43 75 19 33 92 159 162 280 149 257 157 271 202
|
||||
350 19 33 38 67 43 75 9 14 228 392 275 475 12 22 55 96 95 165 40 69 80 139
|
||||
90 155 24 42 202 350 221 383 9 15 27 47 41 72 14 25 75 131 136 236 61 106
|
||||
121 210 134 232 99 172 271 470 279 482 5 8 23 40 40 70 18 30 81 141 142 245
|
||||
60 105 121 210 135 235 14 25 71 124 127 220 56 96 143 247 194 335 51 88 96
|
||||
167 102 175 14 24 180 311 204 355 23 43 340 590 356 615 5 8 50 87 101 175
|
||||
171 301 517 898 582 1008 25 43 46 81 46 83 0 2 12 23 27 47 14 23 40 67 56
|
||||
97 16 30 35 62 42 70 7 8 15 22 18 30 4 8 20 38 37 65 16 28 33 57 37 65 6 12
|
||||
111 196 143 250 5 8 55 95 112 193 57 98 113 195 126 215 12 20 27 46 32 57 6
|
||||
11 14 27 20 35 5 8 76 130 156 270 80 140 165 287 187 325 23 39 52 90 66 115
|
||||
13 25 30 52 37 61 8 8 14 18 14 21 0 4 41 77 92 165 50 87 175 302 276 478
|
||||
101 176 208 360 236 408 28 49 67 117 86 152 19 35 41 70 48 77 6 6 12 15 12
|
||||
19 0 7 124 224 167 291 12 21 23 40 23 42 0 2 21 40 46 83 26 43 55 92 64 109
|
||||
54 95 327 568 354 614 19 30 45 75 59 100 71 128 82 145 89 148 4 2 8 8 8 13
|
||||
0 5 42 82 94 172 311 538 496 858 518 897 14 25 40 70 58 100 18 30 42 71 53
|
||||
90 10 19 79 139 152 265 73 127 142 246 153 265 10 19 43 76 72 125 29 50 63
|
||||
108 75 130 65 116 80 140 87 143 4 2 8 8 8 12 0 8 114 212 140 250 6 8 14 24
|
||||
20 35 5 11 54 97 108 190 l100 170 -9611 3 c-5286 1 -9614 -1 -9618 -5 -5 -6
|
||||
-419 -719 -619 -1068 -89 -155 -267 -463 -323 -560 -38 -66 -81 -140 -95 -165
|
||||
-31 -56 -263 -457 -526 -910 -110 -190 -224 -388 -254 -440 -29 -52 -61 -109
|
||||
-71 -125 -23 -39 -243 -420 -268 -465 -11 -19 -204 -352 -428 -740 -224 -388
|
||||
-477 -826 -563 -975 -85 -148 -185 -322 -222 -385 -37 -63 -120 -207 -185
|
||||
-320 -65 -113 -177 -306 -248 -430 -72 -124 -172 -297 -222 -385 -51 -88 -142
|
||||
-245 -202 -350 -131 -226 -247 -427 -408 -705 -65 -113 -249 -432 -410 -710
|
||||
-160 -278 -388 -673 -506 -877 -118 -205 -216 -373 -219 -373 -3 0 -52 82
|
||||
-109 183 -58 100 -144 250 -192 332 -95 164 -402 696 -647 1120 -85 149 -228
|
||||
396 -317 550 -212 365 -982 1700 -1008 1745 -10 19 -43 76 -72 125 -29 50 -64
|
||||
110 -77 135 -14 25 -63 110 -110 190 -47 80 -96 165 -110 190 -14 25 -99 171
|
||||
-188 325 -89 154 -174 300 -188 325 -13 25 -64 113 -112 195 -48 83 -140 242
|
||||
-205 355 -65 113 -183 317 -263 454 -79 137 -152 264 -163 282 -50 89 -335
|
||||
583 -354 614 -12 19 -34 58 -50 85 -15 28 -129 226 -253 440 -124 215 -235
|
||||
408 -247 430 -12 22 -69 121 -127 220 -58 99 -226 389 -373 645 -148 256 -324
|
||||
561 -392 678 -67 117 -134 232 -147 255 -13 23 -33 59 -46 80 l-22 37 -9615 0
|
||||
-9615 0 20 -32z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 10 KiB |
@@ -4,40 +4,30 @@
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<!--[if IE]>
|
||||
<link rel="icon" href="favicon.ico"/><![endif]--><title>Legado Bookshelf</title>
|
||||
<link href="css/about.b9bb4fe0.css" rel="prefetch">
|
||||
<link href="css/detail.e03dc50b.css" rel="prefetch">
|
||||
<link href="js/about.9f8f9ac0.js" rel="prefetch">
|
||||
<link href="js/about~detail.8270a871.js" rel="prefetch">
|
||||
<link href="js/detail.4e6a53a9.js" rel="prefetch">
|
||||
<link rel="icon" href="../favicon.ico" type="image/x-icon">
|
||||
<link rel="shortcut icon" href="../favicon.ico" type="image/x-icon">
|
||||
<title>Legado Bookshelf</title>
|
||||
<link href="css/about.71e409b6.css" rel="prefetch">
|
||||
<link href="css/detail.cfefeb27.css" rel="prefetch">
|
||||
<link href="js/about.29795c94.js" rel="prefetch">
|
||||
<link href="js/about~detail.67be2f55.js" rel="prefetch">
|
||||
<link href="js/detail.989b5dbd.js" rel="prefetch">
|
||||
<link href="css/app.e4c919b7.css" rel="preload" as="style">
|
||||
<link href="css/chunk-vendors.8a465a1d.css" rel="preload" as="style">
|
||||
<link href="js/app.e84ee963.js" rel="preload" as="script">
|
||||
<link href="js/chunk-vendors.3ef7796f.js" rel="preload" as="script">
|
||||
<link href="css/chunk-vendors.8a465a1d.css" rel="stylesheet">
|
||||
<link href="css/chunk-vendors.5f0f4fba.css" rel="preload" as="style">
|
||||
<link href="js/app.79f613ac.js" rel="preload" as="script">
|
||||
<link href="js/chunk-vendors.6d9073dd.js" rel="preload" as="script">
|
||||
<link href="css/chunk-vendors.5f0f4fba.css" rel="stylesheet">
|
||||
<link href="css/app.e4c919b7.css" rel="stylesheet">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="img/icons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="img/icons/favicon-16x16.png">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<meta name="theme-color" content="#4DBA87">
|
||||
<meta name="apple-mobile-web-app-capable" content="no">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
||||
<meta name="apple-mobile-web-app-title" content="yd-web-tool">
|
||||
<link rel="apple-touch-icon" href="img/icons/apple-touch-icon-152x152.png">
|
||||
<link rel="mask-icon" href="img/icons/safari-pinned-tab.svg" color="#4DBA87">
|
||||
<meta name="msapplication-TileImage" content="img/icons/msapplication-icon-144x144.png">
|
||||
<meta name="msapplication-TileColor" content="#000000">
|
||||
</head>
|
||||
<style>body::-webkit-scrollbar {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<body style="margin: 0;height:100%">
|
||||
<noscript><strong>We're sorry but yd-web-tool doesn't work properly without JavaScript enabled.
|
||||
Please enable it to continue.</strong></noscript>
|
||||
<div id="app"></div>
|
||||
<script src="js/chunk-vendors.3ef7796f.js"></script>
|
||||
<script src="js/app.e84ee963.js"></script>
|
||||
<script src="js/chunk-vendors.6d9073dd.js"></script>
|
||||
<script src="js/app.79f613ac.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
1
app/src/main/assets/web/bookshelf/js/about.29795c94.js
Normal file
1
app/src/main/assets/web/bookshelf/js/detail.989b5dbd.js
Normal file
@@ -1 +0,0 @@
|
||||
{"name":"yd-web-tool","short_name":"yd-web-tool","theme_color":"#4DBA87","icons":[{"src":"./img/icons/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"./img/icons/android-chrome-512x512.png","sizes":"512x512","type":"image/png"},{"src":"./img/icons/android-chrome-maskable-192x192.png","sizes":"192x192","type":"image/png","purpose":"maskable"},{"src":"./img/icons/android-chrome-maskable-512x512.png","sizes":"512x512","type":"image/png","purpose":"maskable"}],"start_url":".","display":"standalone","background_color":"#000000"}
|
||||
@@ -1,70 +0,0 @@
|
||||
self.__precacheManifest = (self.__precacheManifest || []).concat([
|
||||
{
|
||||
"revision": "c6913d775f2f965ac5f3",
|
||||
"url": "css/about.b9bb4fe0.css"
|
||||
},
|
||||
{
|
||||
"revision": "c7b3e35a4e0391b1ed37",
|
||||
"url": "css/app.e4c919b7.css"
|
||||
},
|
||||
{
|
||||
"revision": "9a65f05f9810a3ea7f46",
|
||||
"url": "css/chunk-vendors.8a465a1d.css"
|
||||
},
|
||||
{
|
||||
"revision": "5ab5c6be15b21e2d609b",
|
||||
"url": "css/detail.e03dc50b.css"
|
||||
},
|
||||
{
|
||||
"revision": "535877f50039c0cb49a6196a5b7517cd",
|
||||
"url": "fonts/element-icons.535877f5.woff"
|
||||
},
|
||||
{
|
||||
"revision": "732389ded34cb9c52dd88271f1345af9",
|
||||
"url": "fonts/element-icons.732389de.ttf"
|
||||
},
|
||||
{
|
||||
"revision": "f9a3fb0e145017e166dd4d91d9280cc4",
|
||||
"url": "fonts/iconfont.f9a3fb0e.woff"
|
||||
},
|
||||
{
|
||||
"revision": "f39ecc1a1d2a1eff3aca8aadd818bb61",
|
||||
"url": "fonts/popfont.f39ecc1a.ttf"
|
||||
},
|
||||
{
|
||||
"revision": "6c094b6d4ae9404dbed273c41b06fae8",
|
||||
"url": "fonts/shelffont.6c094b6d.ttf"
|
||||
},
|
||||
{
|
||||
"revision": "8a8424347500238b7b6c08a98d0f89af",
|
||||
"url": "index.html"
|
||||
},
|
||||
{
|
||||
"revision": "c6913d775f2f965ac5f3",
|
||||
"url": "js/about.9f8f9ac0.js"
|
||||
},
|
||||
{
|
||||
"revision": "5998ccb313ed338c15e1",
|
||||
"url": "js/about~detail.8270a871.js"
|
||||
},
|
||||
{
|
||||
"revision": "c7b3e35a4e0391b1ed37",
|
||||
"url": "js/app.e84ee963.js"
|
||||
},
|
||||
{
|
||||
"revision": "9a65f05f9810a3ea7f46",
|
||||
"url": "js/chunk-vendors.3ef7796f.js"
|
||||
},
|
||||
{
|
||||
"revision": "5ab5c6be15b21e2d609b",
|
||||
"url": "js/detail.4e6a53a9.js"
|
||||
},
|
||||
{
|
||||
"revision": "b46d04eb43bc31ca0f9f95121646440d",
|
||||
"url": "manifest.json"
|
||||
},
|
||||
{
|
||||
"revision": "b6216d61c03e6ce0c9aea6ca7808f7ca",
|
||||
"url": "robots.txt"
|
||||
}
|
||||
]);
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* Welcome to your Workbox-powered service worker!
|
||||
*
|
||||
* You'll need to register this file in your web app and you should
|
||||
* disable HTTP caching for this file too.
|
||||
* See https://goo.gl/nhQhGp
|
||||
*
|
||||
* The rest of the code is auto-generated. Please don't update this file
|
||||
* directly; instead, make changes to your Workbox build configuration
|
||||
* and re-run your build process.
|
||||
* See https://goo.gl/2aRDsh
|
||||
*/
|
||||
|
||||
importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
|
||||
|
||||
importScripts(
|
||||
"precache-manifest.5ae9ceec57e7f0f3cc808807b7fe5f32.js"
|
||||
);
|
||||
|
||||
workbox.core.setCacheNameDetails({prefix: "yd-web-tool"});
|
||||
|
||||
self.addEventListener('message', (event) => {
|
||||
if (event.data && event.data.type === 'SKIP_WAITING') {
|
||||
self.skipWaiting();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The workboxSW.precacheAndRoute() method efficiently caches and responds to
|
||||
* requests for URLs in the manifest.
|
||||
* See https://goo.gl/S9QRab
|
||||
*/
|
||||
self.__precacheManifest = [].concat(self.__precacheManifest || []);
|
||||
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
|
||||
@@ -21,6 +21,7 @@ import io.legado.app.model.localBook.LocalBook
|
||||
import io.legado.app.model.localBook.UmdFile
|
||||
import io.legado.app.model.webBook.WebBook
|
||||
import io.legado.app.utils.*
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import splitties.init.appCtx
|
||||
import java.io.File
|
||||
@@ -153,7 +154,16 @@ object BookController {
|
||||
return returnData.setErrorMsg("参数index不能为空, 请指定目录序号")
|
||||
}
|
||||
val book = appDb.bookDao.getBook(bookUrl)
|
||||
val chapter = appDb.bookChapterDao.getChapter(bookUrl, index)
|
||||
val chapter = runBlocking {
|
||||
var chapter = appDb.bookChapterDao.getChapter(bookUrl, index)
|
||||
var wait = 0
|
||||
while (chapter == null && wait < 30) {
|
||||
delay(1000)
|
||||
chapter = appDb.bookChapterDao.getChapter(bookUrl, index)
|
||||
wait++
|
||||
}
|
||||
chapter
|
||||
}
|
||||
if (book == null || chapter == null) {
|
||||
return returnData.setErrorMsg("未找到")
|
||||
}
|
||||
@@ -188,9 +198,8 @@ object BookController {
|
||||
* 保存书籍
|
||||
*/
|
||||
fun saveBook(postData: String?): ReturnData {
|
||||
val book = GSON.fromJsonObject<Book>(postData)
|
||||
val returnData = ReturnData()
|
||||
if (book != null) {
|
||||
GSON.fromJsonObject<Book>(postData).getOrNull()?.let { book ->
|
||||
book.save()
|
||||
AppWebDav.uploadBookProgress(book)
|
||||
if (ReadBook.book?.bookUrl == book.bookUrl) {
|
||||
@@ -279,6 +288,9 @@ object BookController {
|
||||
return returnData.setData(true)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
fun saveWebReadConfig(postData: String?): ReturnData {
|
||||
val returnData = ReturnData()
|
||||
postData?.let {
|
||||
@@ -287,6 +299,9 @@ object BookController {
|
||||
return returnData.setData("")
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
fun getWebReadConfig(): ReturnData {
|
||||
val returnData = ReturnData()
|
||||
val data = CacheManager.get("webReadConfig") ?: "{}"
|
||||
|
||||
@@ -73,11 +73,13 @@ object BookSourceController {
|
||||
|
||||
fun deleteSources(postData: String?): ReturnData {
|
||||
kotlin.runCatching {
|
||||
GSON.fromJsonArray<BookSource>(postData)?.let {
|
||||
GSON.fromJsonArray<BookSource>(postData).getOrThrow()?.let {
|
||||
it.forEach { source ->
|
||||
appDb.bookSourceDao.delete(source)
|
||||
}
|
||||
}
|
||||
}.onFailure {
|
||||
return ReturnData().setErrorMsg(it.localizedMessage ?: "数据格式错误")
|
||||
}
|
||||
return ReturnData().setData("已执行"/*okSources*/)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@ object AppLog {
|
||||
mLogs.add(0, Triple(System.currentTimeMillis(), message, throwable))
|
||||
if (throwable != null) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.e(message, throwable.stackTraceToString())
|
||||
val stackTrace = Thread.currentThread().stackTrace
|
||||
Log.e(stackTrace[3].className, message, throwable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.legado.app.data.dao
|
||||
|
||||
import androidx.room.*
|
||||
import io.legado.app.constant.AppConst
|
||||
import io.legado.app.constant.BookType
|
||||
import io.legado.app.data.entities.Book
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -8,6 +9,16 @@ import kotlinx.coroutines.flow.Flow
|
||||
@Dao
|
||||
interface BookDao {
|
||||
|
||||
@Query(
|
||||
"""
|
||||
select * from books where type != ${BookType.audio}
|
||||
and origin != '${BookType.local}'
|
||||
and ((SELECT sum(groupId) FROM book_groups where groupId > 0) & `group`) = 0
|
||||
and (select show from book_groups where groupId = ${AppConst.bookGroupNoneId}) != 1
|
||||
"""
|
||||
)
|
||||
fun flowRoot(): Flow<List<Book>>
|
||||
|
||||
@Query("SELECT * FROM books order by durChapterTime desc")
|
||||
fun flowAll(): Flow<List<Book>>
|
||||
|
||||
@@ -17,7 +28,13 @@ interface BookDao {
|
||||
@Query("SELECT * FROM books WHERE origin = '${BookType.local}'")
|
||||
fun flowLocal(): Flow<List<Book>>
|
||||
|
||||
@Query("select * from books where type != ${BookType.audio} and origin != '${BookType.local}' and ((SELECT sum(groupId) FROM book_groups where groupId > 0) & `group`) = 0")
|
||||
@Query(
|
||||
"""
|
||||
select * from books where type != ${BookType.audio}
|
||||
and origin != '${BookType.local}'
|
||||
and ((SELECT sum(groupId) FROM book_groups where groupId > 0) & `group`) = 0
|
||||
"""
|
||||
)
|
||||
fun flowNoGroup(): Flow<List<Book>>
|
||||
|
||||
@Query("SELECT bookUrl FROM books WHERE origin = '${BookType.local}'")
|
||||
|
||||
@@ -8,10 +8,7 @@ import io.legado.app.help.AppConfig
|
||||
import io.legado.app.help.CacheManager
|
||||
import io.legado.app.help.JsExtensions
|
||||
import io.legado.app.help.http.CookieStore
|
||||
import io.legado.app.utils.EncoderUtils
|
||||
import io.legado.app.utils.GSON
|
||||
import io.legado.app.utils.fromJsonArray
|
||||
import io.legado.app.utils.fromJsonObject
|
||||
import io.legado.app.utils.*
|
||||
import javax.script.SimpleBindings
|
||||
|
||||
/**
|
||||
@@ -30,7 +27,10 @@ interface BaseSource : JsExtensions {
|
||||
fun getKey(): String
|
||||
|
||||
fun loginUi(): List<RowUi>? {
|
||||
return GSON.fromJsonArray(loginUi)
|
||||
return GSON.fromJsonArray<RowUi>(loginUi)
|
||||
.onFailure {
|
||||
it.printOnDebug()
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
fun getLoginJs(): String? {
|
||||
@@ -64,7 +64,7 @@ interface BaseSource : JsExtensions {
|
||||
evalJS(it.substring(4, it.lastIndexOf("<"))).toString()
|
||||
else -> it
|
||||
}
|
||||
)?.let { map ->
|
||||
).getOrNull()?.let { map ->
|
||||
putAll(map)
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@ interface BaseSource : JsExtensions {
|
||||
|
||||
fun getLoginHeaderMap(): Map<String, String>? {
|
||||
val cache = getLoginHeader() ?: return null
|
||||
return GSON.fromJsonObject(cache)
|
||||
return GSON.fromJsonObject<Map<String, String>>(cache).getOrNull()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,7 +117,7 @@ interface BaseSource : JsExtensions {
|
||||
}
|
||||
|
||||
fun getLoginInfoMap(): Map<String, String>? {
|
||||
return GSON.fromJsonObject(getLoginInfo())
|
||||
return GSON.fromJsonObject<Map<String, String>>(getLoginInfo()).getOrNull()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -92,8 +92,8 @@ data class Book(
|
||||
@delegate:Transient
|
||||
@delegate:Ignore
|
||||
@IgnoredOnParcel
|
||||
override val variableMap by lazy {
|
||||
GSON.fromJsonObject<HashMap<String, String>>(variable) ?: HashMap()
|
||||
override val variableMap: HashMap<String, String> by lazy {
|
||||
GSON.fromJsonObject<HashMap<String, String>>(variable).getOrNull() ?: hashMapOf()
|
||||
}
|
||||
|
||||
override fun putVariable(key: String, value: String?) {
|
||||
@@ -307,6 +307,6 @@ data class Book(
|
||||
fun readConfigToString(config: ReadConfig?): String = GSON.toJson(config)
|
||||
|
||||
@TypeConverter
|
||||
fun stringToReadConfig(json: String?) = GSON.fromJsonObject<ReadConfig>(json)
|
||||
fun stringToReadConfig(json: String?) = GSON.fromJsonObject<ReadConfig>(json).getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@ data class BookChapter(
|
||||
@delegate:Transient
|
||||
@delegate:Ignore
|
||||
@IgnoredOnParcel
|
||||
override val variableMap by lazy {
|
||||
GSON.fromJsonObject<HashMap<String, String>>(variable) ?: HashMap()
|
||||
override val variableMap: HashMap<String, String> by lazy {
|
||||
GSON.fromJsonObject<HashMap<String, String>>(variable).getOrNull() ?: hashMapOf()
|
||||
}
|
||||
|
||||
override fun putVariable(key: String, value: String?) {
|
||||
|
||||
@@ -108,7 +108,7 @@ data class BookSource(
|
||||
}
|
||||
}
|
||||
if (ruleStr.isJsonArray()) {
|
||||
GSON.fromJsonArray<ExploreKind>(ruleStr)?.let {
|
||||
GSON.fromJsonArray<ExploreKind>(ruleStr).getOrThrow()?.let {
|
||||
kinds.addAll(it)
|
||||
}
|
||||
} else {
|
||||
@@ -219,34 +219,44 @@ data class BookSource(
|
||||
class Converters {
|
||||
|
||||
@TypeConverter
|
||||
fun exploreRuleToString(exploreRule: ExploreRule?): String = GSON.toJson(exploreRule)
|
||||
fun exploreRuleToString(exploreRule: ExploreRule?): String =
|
||||
GSON.toJson(exploreRule)
|
||||
|
||||
@TypeConverter
|
||||
fun stringToExploreRule(json: String?) = GSON.fromJsonObject<ExploreRule>(json)
|
||||
fun stringToExploreRule(json: String?) =
|
||||
GSON.fromJsonObject<ExploreRule>(json).getOrNull()
|
||||
|
||||
@TypeConverter
|
||||
fun searchRuleToString(searchRule: SearchRule?): String = GSON.toJson(searchRule)
|
||||
fun searchRuleToString(searchRule: SearchRule?): String =
|
||||
GSON.toJson(searchRule)
|
||||
|
||||
@TypeConverter
|
||||
fun stringToSearchRule(json: String?) = GSON.fromJsonObject<SearchRule>(json)
|
||||
fun stringToSearchRule(json: String?) =
|
||||
GSON.fromJsonObject<SearchRule>(json).getOrNull()
|
||||
|
||||
@TypeConverter
|
||||
fun bookInfoRuleToString(bookInfoRule: BookInfoRule?): String = GSON.toJson(bookInfoRule)
|
||||
fun bookInfoRuleToString(bookInfoRule: BookInfoRule?): String =
|
||||
GSON.toJson(bookInfoRule)
|
||||
|
||||
@TypeConverter
|
||||
fun stringToBookInfoRule(json: String?) = GSON.fromJsonObject<BookInfoRule>(json)
|
||||
fun stringToBookInfoRule(json: String?) =
|
||||
GSON.fromJsonObject<BookInfoRule>(json).getOrNull()
|
||||
|
||||
@TypeConverter
|
||||
fun tocRuleToString(tocRule: TocRule?): String = GSON.toJson(tocRule)
|
||||
fun tocRuleToString(tocRule: TocRule?): String =
|
||||
GSON.toJson(tocRule)
|
||||
|
||||
@TypeConverter
|
||||
fun stringToTocRule(json: String?) = GSON.fromJsonObject<TocRule>(json)
|
||||
fun stringToTocRule(json: String?) =
|
||||
GSON.fromJsonObject<TocRule>(json).getOrNull()
|
||||
|
||||
@TypeConverter
|
||||
fun contentRuleToString(contentRule: ContentRule?): String = GSON.toJson(contentRule)
|
||||
fun contentRuleToString(contentRule: ContentRule?): String =
|
||||
GSON.toJson(contentRule)
|
||||
|
||||
@TypeConverter
|
||||
fun stringToContentRule(json: String?) = GSON.fromJsonObject<ContentRule>(json)
|
||||
fun stringToContentRule(json: String?) =
|
||||
GSON.fromJsonObject<ContentRule>(json).getOrNull()
|
||||
|
||||
}
|
||||
}
|
||||
@@ -36,8 +36,8 @@ data class RssArticle(
|
||||
@delegate:Transient
|
||||
@delegate:Ignore
|
||||
@IgnoredOnParcel
|
||||
override val variableMap by lazy {
|
||||
GSON.fromJsonObject<HashMap<String, String>>(variable) ?: HashMap()
|
||||
override val variableMap: HashMap<String, String> by lazy {
|
||||
GSON.fromJsonObject<HashMap<String, String>>(variable).getOrNull() ?: hashMapOf()
|
||||
}
|
||||
|
||||
override fun putVariable(key: String, value: String?) {
|
||||
|
||||
@@ -29,7 +29,7 @@ data class RssStar(
|
||||
@delegate:Ignore
|
||||
@IgnoredOnParcel
|
||||
override val variableMap by lazy {
|
||||
GSON.fromJsonObject<HashMap<String, String>>(variable) ?: HashMap()
|
||||
GSON.fromJsonObject<HashMap<String, String>>(variable).getOrNull() ?: hashMapOf()
|
||||
}
|
||||
|
||||
override fun putVariable(key: String, value: String?) {
|
||||
|
||||
@@ -59,8 +59,8 @@ data class SearchBook(
|
||||
@delegate:Transient
|
||||
@delegate:Ignore
|
||||
@IgnoredOnParcel
|
||||
override val variableMap by lazy {
|
||||
GSON.fromJsonObject<HashMap<String, String>>(variable) ?: HashMap()
|
||||
override val variableMap: HashMap<String, String> by lazy {
|
||||
GSON.fromJsonObject<HashMap<String, String>>(variable).getOrNull() ?: HashMap()
|
||||
}
|
||||
|
||||
override fun putVariable(key: String, value: String?) {
|
||||
|
||||
@@ -79,7 +79,7 @@ class ContentProcessor private constructor(
|
||||
try {
|
||||
val name = Pattern.quote(book.name)
|
||||
val title = Pattern.quote(chapter.title)
|
||||
val titleRegex = "^(\\s|\\p{P}|${name})*${title}(\\s|\\p{P})+".toRegex()
|
||||
val titleRegex = "^(\\s|\\p{P}|${name})*${title}(\\s)+".toRegex()
|
||||
mContent = mContent.replace(titleRegex, "")
|
||||
} catch (e: Exception) {
|
||||
AppLog.put("去除重复标题出错\n${e.localizedMessage}", e)
|
||||
|
||||
@@ -28,7 +28,8 @@ object DefaultData {
|
||||
appCtx.assets.open("defaultData${File.separator}${ReadBookConfig.configFileName}")
|
||||
.readBytes()
|
||||
)
|
||||
GSON.fromJsonArray(json)!!
|
||||
GSON.fromJsonArray<ReadBookConfig.Config>(json).getOrNull()
|
||||
?: emptyList()
|
||||
}
|
||||
|
||||
val txtTocRules: List<TxtTocRule> by lazy {
|
||||
@@ -36,7 +37,7 @@ object DefaultData {
|
||||
appCtx.assets.open("defaultData${File.separator}$txtTocRuleFileName")
|
||||
.readBytes()
|
||||
)
|
||||
GSON.fromJsonArray(json)!!
|
||||
GSON.fromJsonArray<TxtTocRule>(json).getOrNull() ?: emptyList()
|
||||
}
|
||||
|
||||
val themeConfigs: List<ThemeConfig.Config> by lazy {
|
||||
@@ -44,15 +45,17 @@ object DefaultData {
|
||||
appCtx.assets.open("defaultData${File.separator}${ThemeConfig.configFileName}")
|
||||
.readBytes()
|
||||
)
|
||||
GSON.fromJsonArray(json)!!
|
||||
GSON.fromJsonArray<ThemeConfig.Config>(json).getOrNull() ?: emptyList()
|
||||
}
|
||||
|
||||
val rssSources: List<RssSource> by lazy {
|
||||
val json = String(
|
||||
appCtx.assets.open("defaultData${File.separator}rssSources.json")
|
||||
.readBytes()
|
||||
)
|
||||
RssSource.fromJsonArray(json)
|
||||
kotlin.runCatching {
|
||||
val json = String(
|
||||
appCtx.assets.open("defaultData${File.separator}rssSources.json")
|
||||
.readBytes()
|
||||
)
|
||||
RssSource.fromJsonArray(json)
|
||||
}.getOrDefault(emptyList())
|
||||
}
|
||||
|
||||
fun importDefaultHttpTTS() {
|
||||
|
||||
@@ -97,7 +97,7 @@ interface JsExtensions {
|
||||
|
||||
fun connect(urlStr: String, header: String?): StrResponse {
|
||||
return runBlocking {
|
||||
val headerMap = GSON.fromJsonObject<Map<String, String>>(header)
|
||||
val headerMap = GSON.fromJsonObject<Map<String, String>>(header).getOrNull()
|
||||
val analyzeUrl = AnalyzeUrl(urlStr, headerMapF = headerMap, source = getSource())
|
||||
kotlin.runCatching {
|
||||
analyzeUrl.getStrResponseAwait()
|
||||
|
||||
@@ -6,15 +6,17 @@ import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.annotation.Keep
|
||||
import io.legado.app.R
|
||||
import io.legado.app.constant.AppLog
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.help.coroutine.Coroutine
|
||||
import io.legado.app.model.NoStackTraceException
|
||||
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
||||
import io.legado.app.utils.*
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.withContext
|
||||
import splitties.init.appCtx
|
||||
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* 阅读界面配置
|
||||
@@ -60,9 +62,9 @@ object ReadBookConfig {
|
||||
if (configFile.exists()) {
|
||||
try {
|
||||
val json = configFile.readText()
|
||||
configs = GSON.fromJsonArray(json)
|
||||
configs = GSON.fromJsonArray<Config>(json).getOrThrow()
|
||||
} catch (e: Exception) {
|
||||
e.printOnDebug()
|
||||
AppLog.put("读取排版配置文件出错", e)
|
||||
}
|
||||
}
|
||||
(configs ?: DefaultData.readConfigs).let {
|
||||
@@ -77,7 +79,7 @@ object ReadBookConfig {
|
||||
if (configFile.exists()) {
|
||||
try {
|
||||
val json = configFile.readText()
|
||||
c = GSON.fromJsonObject(json)
|
||||
c = GSON.fromJsonObject<Config>(json).getOrThrow()
|
||||
} catch (e: Exception) {
|
||||
e.printOnDebug()
|
||||
}
|
||||
@@ -325,7 +327,7 @@ object ReadBookConfig {
|
||||
}
|
||||
|
||||
fun getExportConfig(): Config {
|
||||
val exportConfig = GSON.fromJsonObject<Config>(GSON.toJson(durConfig))!!
|
||||
val exportConfig = durConfig.deepCopy()
|
||||
if (shareLayout) {
|
||||
exportConfig.textFont = shareConfig.textFont
|
||||
exportConfig.textBold = shareConfig.textBold
|
||||
@@ -364,6 +366,7 @@ object ReadBookConfig {
|
||||
return exportConfig
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
suspend fun import(byteArray: ByteArray): Config {
|
||||
return withContext(IO) {
|
||||
val configZipPath = FileUtils.getPath(appCtx.externalCache, "readConfig.zip")
|
||||
@@ -376,7 +379,8 @@ object ReadBookConfig {
|
||||
ZipUtils.unzipFile(zipFile, FileUtils.createFolderIfNotExist(configDirPath))
|
||||
val configDir = FileUtils.createFolderIfNotExist(configDirPath)
|
||||
val configFile = configDir.getFile(configFileName)
|
||||
val config: Config = GSON.fromJsonObject(configFile.readText())!!
|
||||
val config: Config = GSON.fromJsonObject<Config>(configFile.readText()).getOrThrow()
|
||||
?: throw NoStackTraceException("排版配置格式错误")
|
||||
if (config.textFont.isNotEmpty()) {
|
||||
val fontName = FileUtils.getName(config.textFont)
|
||||
val fontPath =
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.legado.app.help
|
||||
import androidx.annotation.Keep
|
||||
import com.jayway.jsonpath.JsonPath
|
||||
import io.legado.app.constant.AppConst
|
||||
import io.legado.app.constant.AppLog
|
||||
import io.legado.app.constant.BookType
|
||||
import io.legado.app.data.entities.BookSource
|
||||
import io.legado.app.data.entities.rule.*
|
||||
@@ -31,11 +32,10 @@ object SourceAnalyzer {
|
||||
|
||||
fun jsonToBookSource(json: String): BookSource? {
|
||||
val source = BookSource()
|
||||
val sourceAny = try {
|
||||
GSON.fromJsonObject<BookSourceAny>(json.trim())
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
val sourceAny = GSON.fromJsonObject<BookSourceAny>(json.trim())
|
||||
.onFailure {
|
||||
AppLog.put("转化书源出错", it)
|
||||
}.getOrNull()
|
||||
try {
|
||||
if (sourceAny?.ruleToc == null) {
|
||||
source.apply {
|
||||
@@ -132,30 +132,40 @@ object SourceAnalyzer {
|
||||
source.weight = sourceAny.weight
|
||||
source.exploreUrl = sourceAny.exploreUrl
|
||||
source.ruleExplore = if (sourceAny.ruleExplore is String) {
|
||||
GSON.fromJsonObject(sourceAny.ruleExplore.toString())
|
||||
GSON.fromJsonObject<ExploreRule>(sourceAny.ruleExplore.toString())
|
||||
.getOrNull()
|
||||
} else {
|
||||
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleExplore))
|
||||
GSON.fromJsonObject<ExploreRule>(GSON.toJson(sourceAny.ruleExplore))
|
||||
.getOrNull()
|
||||
}
|
||||
source.searchUrl = sourceAny.searchUrl
|
||||
source.ruleSearch = if (sourceAny.ruleSearch is String) {
|
||||
GSON.fromJsonObject(sourceAny.ruleSearch.toString())
|
||||
GSON.fromJsonObject<SearchRule>(sourceAny.ruleSearch.toString())
|
||||
.getOrNull()
|
||||
} else {
|
||||
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleSearch))
|
||||
GSON.fromJsonObject<SearchRule>(GSON.toJson(sourceAny.ruleSearch))
|
||||
.getOrNull()
|
||||
}
|
||||
source.ruleBookInfo = if (sourceAny.ruleBookInfo is String) {
|
||||
GSON.fromJsonObject(sourceAny.ruleBookInfo.toString())
|
||||
GSON.fromJsonObject<BookInfoRule>(sourceAny.ruleBookInfo.toString())
|
||||
.getOrNull()
|
||||
} else {
|
||||
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleBookInfo))
|
||||
GSON.fromJsonObject<BookInfoRule>(GSON.toJson(sourceAny.ruleBookInfo))
|
||||
.getOrNull()
|
||||
}
|
||||
source.ruleToc = if (sourceAny.ruleToc is String) {
|
||||
GSON.fromJsonObject(sourceAny.ruleToc.toString())
|
||||
GSON.fromJsonObject<TocRule>(sourceAny.ruleToc.toString())
|
||||
.getOrNull()
|
||||
} else {
|
||||
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleToc))
|
||||
GSON.fromJsonObject<TocRule>(GSON.toJson(sourceAny.ruleToc))
|
||||
.getOrNull()
|
||||
}
|
||||
source.ruleContent = if (sourceAny.ruleContent is String) {
|
||||
GSON.fromJsonObject(sourceAny.ruleContent.toString())
|
||||
GSON.fromJsonObject<ContentRule>(sourceAny.ruleContent.toString())
|
||||
.getOrNull()
|
||||
} else {
|
||||
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleContent))
|
||||
GSON.fromJsonObject<ContentRule>(GSON.toJson(sourceAny.ruleContent))
|
||||
.getOrNull()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -83,10 +83,11 @@ object ThemeConfig {
|
||||
}
|
||||
|
||||
fun addConfig(json: String): Boolean {
|
||||
GSON.fromJsonObject<Config>(json.trim { it < ' ' })?.let {
|
||||
addConfig(it)
|
||||
return true
|
||||
}
|
||||
GSON.fromJsonObject<Config>(json.trim { it < ' ' }).getOrNull()
|
||||
?.let {
|
||||
addConfig(it)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -106,7 +107,7 @@ object ThemeConfig {
|
||||
if (configFile.exists()) {
|
||||
kotlin.runCatching {
|
||||
val json = configFile.readText()
|
||||
return GSON.fromJsonArray(json)
|
||||
return GSON.fromJsonArray<Config>(json).getOrThrow()
|
||||
}.onFailure {
|
||||
it.printOnDebug()
|
||||
}
|
||||
|
||||
@@ -172,9 +172,7 @@ object AppWebDav {
|
||||
WebDav(url).download()?.let { byteArray ->
|
||||
val json = String(byteArray)
|
||||
if (json.isJson()) {
|
||||
GSON.fromJsonObject<BookProgress>(json)?.let {
|
||||
return it
|
||||
}
|
||||
return GSON.fromJsonObject<BookProgress>(json).getOrNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ abstract class BackupRestore {
|
||||
val ignoreConfig: HashMap<String, Boolean> by lazy {
|
||||
val file = FileUtils.createFileIfNotExist(ignoreConfigPath)
|
||||
val json = file.readText()
|
||||
GSON.fromJsonObject<HashMap<String, Boolean>>(json) ?: hashMapOf()
|
||||
GSON.fromJsonObject<HashMap<String, Boolean>>(json).getOrNull() ?: hashMapOf()
|
||||
}
|
||||
|
||||
//忽略key
|
||||
|
||||
@@ -20,12 +20,9 @@ object OldReplace {
|
||||
}
|
||||
|
||||
private fun jsonToReplaceRule(json: String): ReplaceRule? {
|
||||
var replaceRule: ReplaceRule? = null
|
||||
val replaceRule: ReplaceRule? = GSON.fromJsonObject<ReplaceRule>(json.trim()).getOrNull()
|
||||
runCatching {
|
||||
replaceRule = GSON.fromJsonObject<ReplaceRule>(json.trim())
|
||||
}
|
||||
runCatching {
|
||||
if (replaceRule == null || replaceRule?.pattern.isNullOrBlank()) {
|
||||
if (replaceRule == null || replaceRule.pattern.isBlank()) {
|
||||
val jsonItem = jsonPath.parse(json.trim())
|
||||
val rule = ReplaceRule()
|
||||
rule.id = jsonItem.readLong("$.id") ?: System.currentTimeMillis()
|
||||
|
||||
@@ -6,6 +6,7 @@ import androidx.documentfile.provider.DocumentFile
|
||||
import io.legado.app.BuildConfig
|
||||
import io.legado.app.R
|
||||
import io.legado.app.constant.AppConst.androidId
|
||||
import io.legado.app.constant.AppLog
|
||||
import io.legado.app.constant.EventBus
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.data.appDb
|
||||
@@ -20,7 +21,6 @@ import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.withContext
|
||||
import splitties.init.appCtx
|
||||
|
||||
import java.io.File
|
||||
|
||||
|
||||
@@ -193,9 +193,10 @@ object Restore : BackupRestore() {
|
||||
try {
|
||||
val file = FileUtils.createFileIfNotExist(path + File.separator + fileName)
|
||||
val json = file.readText()
|
||||
return GSON.fromJsonArray(json)
|
||||
return GSON.fromJsonArray<T>(json).getOrThrow()
|
||||
} catch (e: Exception) {
|
||||
e.printOnDebug()
|
||||
AppLog.put("$fileName\n读取解析出错\n${e.localizedMessage}", e)
|
||||
appCtx.toastOnUi("$fileName\n读取文件出错\n${e.localizedMessage}")
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.Book
|
||||
import io.legado.app.data.entities.BookChapter
|
||||
import io.legado.app.data.entities.BookSource
|
||||
import io.legado.app.help.ContentProcessor
|
||||
import io.legado.app.help.coroutine.Coroutine
|
||||
import io.legado.app.service.AudioPlayService
|
||||
import io.legado.app.utils.postEvent
|
||||
@@ -148,7 +149,9 @@ object AudioPlay {
|
||||
book.durChapterTime = System.currentTimeMillis()
|
||||
Coroutine.async {
|
||||
appDb.bookChapterDao.getChapter(book.bookUrl, book.durChapterIndex)?.let {
|
||||
book.durChapterTitle = it.title
|
||||
book.durChapterTitle = it.getDisplayTitle(
|
||||
ContentProcessor.get(book.name, book.origin).getTitleReplaceRules()
|
||||
)
|
||||
}
|
||||
book.save()
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import kotlinx.coroutines.delay
|
||||
import splitties.init.appCtx
|
||||
|
||||
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
object ReadBook : CoroutineScope by MainScope() {
|
||||
var book: Book? = null
|
||||
@@ -422,7 +421,9 @@ object ReadBook : CoroutineScope by MainScope() {
|
||||
book.durChapterIndex = durChapterIndex
|
||||
book.durChapterPos = durChapterPos
|
||||
appDb.bookChapterDao.getChapter(book.bookUrl, durChapterIndex)?.let {
|
||||
book.durChapterTitle = it.title
|
||||
book.durChapterTitle = it.getDisplayTitle(
|
||||
ContentProcessor.get(book.name, book.origin).getTitleReplaceRules()
|
||||
)
|
||||
}
|
||||
appDb.bookDao.update(book)
|
||||
}
|
||||
|
||||
@@ -341,8 +341,11 @@ class AnalyzeRule(
|
||||
val putMatcher = putPattern.matcher(vRuleStr)
|
||||
while (putMatcher.find()) {
|
||||
vRuleStr = vRuleStr.replace(putMatcher.group(), "")
|
||||
val map = GSON.fromJsonObject<Map<String, String>>(putMatcher.group(1))
|
||||
map?.let { putMap.putAll(map) }
|
||||
GSON.fromJsonObject<Map<String, String>>(putMatcher.group(1))
|
||||
.getOrNull()
|
||||
?.let {
|
||||
putMap.putAll(it)
|
||||
}
|
||||
}
|
||||
return vRuleStr
|
||||
}
|
||||
@@ -379,7 +382,7 @@ class AnalyzeRule(
|
||||
* 分解规则生成规则列表
|
||||
*/
|
||||
fun splitSourceRule(ruleStr: String?, allInOne: Boolean = false): List<SourceRule> {
|
||||
if (ruleStr.isNullOrEmpty()) return ArrayList<SourceRule>()
|
||||
if (ruleStr.isNullOrEmpty()) return emptyList()
|
||||
val ruleList = ArrayList<SourceRule>()
|
||||
var mMode: Mode = Mode.Default
|
||||
var start = 0
|
||||
@@ -597,9 +600,9 @@ class AnalyzeRule(
|
||||
|
||||
private fun isRule(ruleStr: String): Boolean {
|
||||
return ruleStr.startsWith('@') //js首个字符不可能是@,除非是装饰器,所以@开头规定为规则
|
||||
|| ruleStr.startsWith("$.")
|
||||
|| ruleStr.startsWith("$[")
|
||||
|| ruleStr.startsWith("//")
|
||||
|| ruleStr.startsWith("$.")
|
||||
|| ruleStr.startsWith("$[")
|
||||
|| ruleStr.startsWith("//")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -167,34 +167,35 @@ class AnalyzeUrl(
|
||||
baseUrl = it
|
||||
}
|
||||
if (urlNoOption.length != ruleUrl.length) {
|
||||
GSON.fromJsonObject<UrlOption>(ruleUrl.substring(urlMatcher.end()))?.let { option ->
|
||||
option.method?.let {
|
||||
if (it.equals("POST", true)) method = RequestMethod.POST
|
||||
}
|
||||
option.headers?.let { headers ->
|
||||
if (headers is Map<*, *>) {
|
||||
headers.forEach { entry ->
|
||||
headerMap[entry.key.toString()] = entry.value.toString()
|
||||
GSON.fromJsonObject<UrlOption>(ruleUrl.substring(urlMatcher.end())).getOrNull()
|
||||
?.let { option ->
|
||||
option.method?.let {
|
||||
if (it.equals("POST", true)) method = RequestMethod.POST
|
||||
}
|
||||
option.headers?.let { headers ->
|
||||
if (headers is Map<*, *>) {
|
||||
headers.forEach { entry ->
|
||||
headerMap[entry.key.toString()] = entry.value.toString()
|
||||
}
|
||||
} else if (headers is String) {
|
||||
GSON.fromJsonObject<Map<String, String>>(headers).getOrNull()
|
||||
?.let { headerMap.putAll(it) }
|
||||
}
|
||||
}
|
||||
option.body?.let {
|
||||
body = if (it is String) it else GSON.toJson(it)
|
||||
}
|
||||
type = option.type
|
||||
charset = option.charset
|
||||
retry = option.retry
|
||||
useWebView = option.webView?.toString()?.isNotBlank() == true
|
||||
webJs = option.webJs
|
||||
option.js?.let { jsStr ->
|
||||
evalJS(jsStr, url)?.toString()?.let {
|
||||
url = it
|
||||
}
|
||||
} else if (headers is String) {
|
||||
GSON.fromJsonObject<Map<String, String>>(headers)
|
||||
?.let { headerMap.putAll(it) }
|
||||
}
|
||||
}
|
||||
option.body?.let {
|
||||
body = if (it is String) it else GSON.toJson(it)
|
||||
}
|
||||
type = option.type
|
||||
charset = option.charset
|
||||
retry = option.retry
|
||||
useWebView = option.webView?.toString()?.isNotBlank() == true
|
||||
webJs = option.webJs
|
||||
option.js?.let { jsStr ->
|
||||
evalJS(jsStr, url)?.toString()?.let {
|
||||
url = it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
headerMap[UA_NAME] ?: let {
|
||||
headerMap[UA_NAME] = AppConfig.userAgent
|
||||
@@ -510,7 +511,7 @@ class AnalyzeUrl(
|
||||
suspend fun upload(fileName: String, file: Any, contentType: String): StrResponse {
|
||||
return getProxyClient(proxy).newCallStrResponse(retry) {
|
||||
url(urlNoQuery)
|
||||
val bodyMap = GSON.fromJsonObject<HashMap<String, Any>>(body)!!
|
||||
val bodyMap = GSON.fromJsonObject<HashMap<String, Any>>(body).getOrNull()!!
|
||||
bodyMap.forEach { entry ->
|
||||
if (entry.value.toString() == "fileRequest") {
|
||||
bodyMap[entry.key] = mapOf(
|
||||
|
||||
@@ -141,8 +141,8 @@ object LocalBook {
|
||||
//将文件名注入到脚步的src变量中
|
||||
SimpleBindings().also { it["src"] = tempFileName }
|
||||
).toString()
|
||||
val bookMess =
|
||||
GSON.fromJsonObject<HashMap<String, String>>(jsonStr) ?: HashMap()
|
||||
val bookMess = GSON.fromJsonObject<HashMap<String, String>>(jsonStr)
|
||||
.getOrThrow() ?: HashMap()
|
||||
name = bookMess["name"] ?: tempFileName
|
||||
author = bookMess["author"]?.takeIf { it.length != tempFileName.length } ?: ""
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -37,7 +37,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener
|
||||
@Synchronized
|
||||
private fun initTts() {
|
||||
ttsInitFinish = false
|
||||
val engine = GSON.fromJsonObject<SelectItem<String>>(ReadAloud.ttsEngine)?.value
|
||||
val engine = GSON.fromJsonObject<SelectItem<String>>(ReadAloud.ttsEngine).getOrNull()?.value
|
||||
textToSpeech = if (engine.isNullOrBlank()) {
|
||||
TextToSpeech(this, this)
|
||||
} else {
|
||||
|
||||
@@ -19,11 +19,11 @@ abstract class BaseAssociationViewModel(application: Application) : BaseViewMode
|
||||
fun importTextTocRule(json: String, finally: (title: String, msg: String) -> Unit) {
|
||||
execute {
|
||||
if (json.isJsonArray()) {
|
||||
GSON.fromJsonArray<TxtTocRule>(json)?.let {
|
||||
GSON.fromJsonArray<TxtTocRule>(json).getOrThrow()?.let {
|
||||
appDb.txtTocRuleDao.insert(*it.toTypedArray())
|
||||
} ?: throw NoStackTraceException("格式不对")
|
||||
} else {
|
||||
GSON.fromJsonObject<TxtTocRule>(json)?.let {
|
||||
GSON.fromJsonObject<TxtTocRule>(json).getOrThrow()?.let {
|
||||
appDb.txtTocRuleDao.insert(it)
|
||||
} ?: throw NoStackTraceException("格式不对")
|
||||
}
|
||||
@@ -63,11 +63,11 @@ abstract class BaseAssociationViewModel(application: Application) : BaseViewMode
|
||||
fun importTheme(json: String, finally: (title: String, msg: String) -> Unit) {
|
||||
execute {
|
||||
if (json.isJsonArray()) {
|
||||
GSON.fromJsonArray<ThemeConfig.Config>(json)?.forEach {
|
||||
GSON.fromJsonArray<ThemeConfig.Config>(json).getOrThrow()?.forEach {
|
||||
ThemeConfig.addConfig(it)
|
||||
} ?: throw NoStackTraceException("格式不对")
|
||||
} else {
|
||||
GSON.fromJsonObject<ThemeConfig.Config>(json)?.let {
|
||||
GSON.fromJsonObject<ThemeConfig.Config>(json).getOrThrow()?.let {
|
||||
ThemeConfig.addConfig(it)
|
||||
} ?: throw NoStackTraceException("格式不对")
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ class ImportReplaceRuleDialog() : BaseDialogFragment(R.layout.dialog_recycler_vi
|
||||
|
||||
override fun onCodeSave(code: String, requestId: String?) {
|
||||
requestId?.toInt()?.let {
|
||||
GSON.fromJsonObject<ReplaceRule>(code)?.let { rule ->
|
||||
GSON.fromJsonObject<ReplaceRule>(code).getOrNull()?.let { rule ->
|
||||
viewModel.allRules[it] = rule
|
||||
adapter.setItem(it, rule)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ class ChangeCoverDialog() : BaseDialogFragment(R.layout.dialog_change_cover),
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
setLayout(0.98f, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
setLayout(1f, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
}
|
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
||||
@@ -57,7 +57,7 @@ class ChangeBookSourceDialog() : BaseDialogFragment(R.layout.dialog_book_change_
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
setLayout(0.98f, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
setLayout(1f, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
}
|
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
||||
@@ -81,7 +81,7 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
setLayout(0.98f, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
setLayout(1f, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
dialog?.setOnKeyListener(this)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.activity.viewModels
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.VMBaseActivity
|
||||
import io.legado.app.data.appDb
|
||||
@@ -22,8 +21,8 @@ import io.legado.app.ui.widget.recycler.ItemTouchCallback
|
||||
import io.legado.app.ui.widget.recycler.VerticalDivider
|
||||
import io.legado.app.utils.ACache
|
||||
import io.legado.app.utils.setEdgeEffectColor
|
||||
import io.legado.app.utils.snackbar
|
||||
import io.legado.app.utils.splitNotBlank
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -184,10 +183,8 @@ class TxtTocRuleActivity : VMBaseActivity<ActivityTxtTocRuleBinding, TxtTocRuleV
|
||||
cacheUrls.add(0, it)
|
||||
aCache.put(importTocRuleKey, cacheUrls.joinToString(","))
|
||||
}
|
||||
Snackbar.make(binding.root, R.string.importing, Snackbar.LENGTH_INDEFINITE)
|
||||
.show()
|
||||
viewModel.importOnLine(it) { msg ->
|
||||
binding.root.snackbar(msg)
|
||||
toastOnUi(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,14 +42,14 @@ class TxtTocRuleViewModel(app: Application) : BaseViewModel(app) {
|
||||
okHttpClient.newCallResponseBody {
|
||||
url(url)
|
||||
}.text("utf-8").let { json ->
|
||||
GSON.fromJsonArray<TxtTocRule>(json)?.let {
|
||||
GSON.fromJsonArray<TxtTocRule>(json).getOrThrow()?.let {
|
||||
appDb.txtTocRuleDao.insert(*it.toTypedArray())
|
||||
}
|
||||
}
|
||||
}.onSuccess {
|
||||
finally("导入成功")
|
||||
}.onError {
|
||||
finally("导入失败")
|
||||
finally("导入失败\n${it.localizedMessage}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class ContentEditDialog : BaseDialogFragment(R.layout.dialog_content_edit) {
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
setLayout(0.96f, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
setLayout(1f, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
}
|
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@@ -80,7 +80,7 @@ class ContentEditDialog : BaseDialogFragment(R.layout.dialog_content_edit) {
|
||||
ReadBook.loadContent(ReadBook.durChapterIndex, resetPageOffset = false)
|
||||
}
|
||||
R.id.menu_copy_all -> requireContext()
|
||||
.sendToClip("${binding.toolBar.title}\n${viewModel.content}")
|
||||
.sendToClip("${binding.toolBar.title}\n${binding.contentView.text}")
|
||||
}
|
||||
return@setOnMenuItemClickListener true
|
||||
}
|
||||
@@ -129,6 +129,7 @@ class ContentEditDialog : BaseDialogFragment(R.layout.dialog_content_edit) {
|
||||
.joinToString("\n")
|
||||
}
|
||||
}.onSuccess {
|
||||
content = it
|
||||
success.invoke(it ?: "")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class PhotoDialog() : BaseDialogFragment(R.layout.dialog_photo_view) {
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
setLayout(0.98f, 0.98f)
|
||||
setLayout(1f, 1f)
|
||||
}
|
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
||||
@@ -227,10 +227,8 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
|
||||
if (index < ReadBook.chapterSize) {
|
||||
ReadBook.clearTextChapter()
|
||||
ReadBook.callBack?.upContent()
|
||||
if (index != ReadBook.durChapterIndex) {
|
||||
ReadBook.durChapterIndex = index
|
||||
ReadBook.durChapterPos = durChapterPos
|
||||
}
|
||||
ReadBook.durChapterIndex = index
|
||||
ReadBook.durChapterPos = durChapterPos
|
||||
ReadBook.saveRead()
|
||||
ReadBook.loadContent(resetPageOffset = true) {
|
||||
success?.invoke()
|
||||
|
||||
@@ -65,7 +65,7 @@ class ReadAloudConfigDialog : DialogFragment() {
|
||||
return appDb.httpTTSDao.getName(ttsEngine.toLong())
|
||||
?: getString(R.string.system_tts)
|
||||
}
|
||||
return GSON.fromJsonObject<SelectItem<String>>(ttsEngine)?.title
|
||||
return GSON.fromJsonObject<SelectItem<String>>(ttsEngine).getOrNull()?.title
|
||||
?: getString(R.string.system_tts)
|
||||
}
|
||||
|
||||
|
||||
@@ -95,8 +95,8 @@ class SpeakEngineDialog(val callBack: CallBack) : BaseDialogFragment(R.layout.di
|
||||
labelSys.visible()
|
||||
cbName.text = engine.label
|
||||
cbName.tag = engine.name
|
||||
cbName.isChecked =
|
||||
GSON.fromJsonObject<SelectItem<String>>(ttsEngine)?.value == cbName.tag
|
||||
cbName.isChecked = GSON.fromJsonObject<SelectItem<String>>(ttsEngine)
|
||||
.getOrNull()?.value == cbName.tag
|
||||
cbName.setOnClickListener {
|
||||
upTts(GSON.toJson(SelectItem(engine.label, engine.name)))
|
||||
}
|
||||
@@ -192,7 +192,8 @@ class SpeakEngineDialog(val callBack: CallBack) : BaseDialogFragment(R.layout.di
|
||||
private fun upTts(tts: String) {
|
||||
ttsEngine = tts
|
||||
sysTtsViews.forEach {
|
||||
it.isChecked = GSON.fromJsonObject<SelectItem<String>>(ttsEngine)?.value == it.tag
|
||||
it.isChecked = GSON.fromJsonObject<SelectItem<String>>(ttsEngine)
|
||||
.getOrNull()?.value == it.tag
|
||||
}
|
||||
adapter.notifyItemRangeChanged(adapter.getHeaderCount(), adapter.itemCount)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import androidx.appcompat.widget.Toolbar
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BaseDialogFragment
|
||||
import io.legado.app.base.adapter.ItemViewHolder
|
||||
@@ -154,10 +153,8 @@ class TocRegexDialog() : BaseDialogFragment(R.layout.dialog_toc_regex),
|
||||
cacheUrls.add(0, it)
|
||||
aCache.put(importTocRuleKey, cacheUrls.joinToString(","))
|
||||
}
|
||||
Snackbar.make(binding.toolBar, R.string.importing, Snackbar.LENGTH_INDEFINITE)
|
||||
.show()
|
||||
viewModel.importOnLine(it) { msg ->
|
||||
binding.toolBar.snackbar(msg)
|
||||
toastOnUi(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,14 +33,14 @@ class TocRegexViewModel(application: Application) : BaseViewModel(application) {
|
||||
okHttpClient.newCallResponseBody {
|
||||
url(url)
|
||||
}.text("utf-8").let { json ->
|
||||
GSON.fromJsonArray<TxtTocRule>(json)?.let {
|
||||
GSON.fromJsonArray<TxtTocRule>(json).getOrThrow()?.let {
|
||||
appDb.txtTocRuleDao.insert(*it.toTypedArray())
|
||||
}
|
||||
}
|
||||
}.onSuccess {
|
||||
finally("导入成功")
|
||||
}.onError {
|
||||
finally("导入失败")
|
||||
finally("导入失败\n${it.localizedMessage}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application)
|
||||
private fun importBookshelfByJson(json: String, groupId: Long) {
|
||||
execute {
|
||||
val bookSources = appDb.bookSourceDao.allEnabled
|
||||
GSON.fromJsonArray<Map<String, String?>>(json)?.forEach { bookInfo ->
|
||||
GSON.fromJsonArray<Map<String, String?>>(json).getOrThrow()?.forEach { bookInfo ->
|
||||
if (!isActive) return@execute
|
||||
val name = bookInfo["name"] ?: ""
|
||||
val author = bookInfo["author"] ?: ""
|
||||
@@ -143,6 +143,8 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.onError {
|
||||
it.printOnDebug()
|
||||
}.onFinally {
|
||||
context.toastOnUi(R.string.success)
|
||||
}
|
||||
|
||||
@@ -73,6 +73,14 @@ abstract class BaseBooksAdapter<VH : RecyclerView.ViewHolder>(
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return callBack.getItemCount()
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return callBack.getItemType(position)
|
||||
}
|
||||
|
||||
|
||||
interface CallBack {
|
||||
fun onItemClick(position: Int)
|
||||
@@ -80,6 +88,6 @@ abstract class BaseBooksAdapter<VH : RecyclerView.ViewHolder>(
|
||||
fun isUpdate(bookUrl: String): Boolean
|
||||
fun getItemCount(): Int
|
||||
fun getItemType(position: Int): Int
|
||||
fun getItem(position: Int): Any
|
||||
fun getItem(position: Int): Any?
|
||||
}
|
||||
}
|
||||
@@ -17,14 +17,6 @@ import splitties.views.onLongClick
|
||||
class BooksAdapterGrid(context: Context, callBack: CallBack) :
|
||||
BaseBooksAdapter<RecyclerView.ViewHolder>(context, callBack) {
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return callBack.getItemCount()
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return callBack.getItemType(position)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
@@ -67,7 +59,7 @@ class BooksAdapterGrid(context: Context, callBack: CallBack) :
|
||||
|
||||
private fun onBindBook(binding: ItemBookshelfGridBinding, position: Int, bundle: Bundle) {
|
||||
binding.run {
|
||||
val item = callBack.getItem(position) as Book
|
||||
val item = callBack.getItem(position) as? Book ?: return
|
||||
bundle.keySet().forEach {
|
||||
when (it) {
|
||||
"name" -> tvName.text = item.name
|
||||
|
||||
@@ -19,14 +19,6 @@ import splitties.views.onLongClick
|
||||
class BooksAdapterList(context: Context, callBack: CallBack) :
|
||||
BaseBooksAdapter<RecyclerView.ViewHolder>(context, callBack) {
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return callBack.getItemCount()
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return callBack.getItemType(position)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return when (viewType) {
|
||||
1 -> GroupViewHolder(
|
||||
@@ -65,7 +57,7 @@ class BooksAdapterList(context: Context, callBack: CallBack) :
|
||||
|
||||
private fun onBindBook(binding: ItemBookshelfListBinding, position: Int, bundle: Bundle) {
|
||||
binding.run {
|
||||
val item = callBack.getItem(position) as Book
|
||||
val item = callBack.getItem(position) as? Book ?: return
|
||||
tvRead.text = item.durChapterTitle
|
||||
tvLast.text = item.latestChapterTitle
|
||||
bundle.keySet().forEach {
|
||||
|
||||
@@ -43,6 +43,7 @@ class BookshelfFragment2 : BaseBookshelfFragment(R.layout.fragment_bookshelf1),
|
||||
BaseBooksAdapter.CallBack {
|
||||
|
||||
private val binding by viewBinding(FragmentBookshelf1Binding::bind)
|
||||
private val rootGroupId = -100L
|
||||
private val bookshelfLayout by lazy {
|
||||
getPrefInt(PreferKey.bookshelfLayout)
|
||||
}
|
||||
@@ -55,7 +56,7 @@ class BookshelfFragment2 : BaseBookshelfFragment(R.layout.fragment_bookshelf1),
|
||||
}
|
||||
private var bookGroups: List<BookGroup> = emptyList()
|
||||
private var booksFlowJob: Job? = null
|
||||
override var groupId = AppConst.bookGroupNoneId
|
||||
override var groupId = rootGroupId
|
||||
override var books: List<Book> = emptyList()
|
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@@ -108,7 +109,7 @@ class BookshelfFragment2 : BaseBookshelfFragment(R.layout.fragment_bookshelf1),
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun initBooksData() {
|
||||
if (groupId == AppConst.bookGroupNoneId) {
|
||||
if (groupId == -100L) {
|
||||
binding.titleBar.title = getString(R.string.bookshelf)
|
||||
} else {
|
||||
bookGroups.forEach {
|
||||
@@ -120,6 +121,7 @@ class BookshelfFragment2 : BaseBookshelfFragment(R.layout.fragment_bookshelf1),
|
||||
booksFlowJob?.cancel()
|
||||
booksFlowJob = launch {
|
||||
when (groupId) {
|
||||
rootGroupId -> appDb.bookDao.flowRoot()
|
||||
AppConst.bookGroupAllId -> appDb.bookDao.flowAll()
|
||||
AppConst.bookGroupLocalId -> appDb.bookDao.flowLocal()
|
||||
AppConst.bookGroupAudioId -> appDb.bookDao.flowAudio()
|
||||
@@ -152,8 +154,8 @@ class BookshelfFragment2 : BaseBookshelfFragment(R.layout.fragment_bookshelf1),
|
||||
}
|
||||
|
||||
fun back(): Boolean {
|
||||
if (groupId != AppConst.bookGroupNoneId) {
|
||||
groupId = AppConst.bookGroupNoneId
|
||||
if (groupId != -100L) {
|
||||
groupId = -100L
|
||||
initBooksData()
|
||||
return true
|
||||
}
|
||||
@@ -210,7 +212,7 @@ class BookshelfFragment2 : BaseBookshelfFragment(R.layout.fragment_bookshelf1),
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return if (groupId == AppConst.bookGroupNoneId) {
|
||||
return if (groupId == rootGroupId) {
|
||||
bookGroups.size + books.size
|
||||
} else {
|
||||
books.size
|
||||
@@ -218,23 +220,23 @@ class BookshelfFragment2 : BaseBookshelfFragment(R.layout.fragment_bookshelf1),
|
||||
}
|
||||
|
||||
override fun getItemType(position: Int): Int {
|
||||
return if (groupId == AppConst.bookGroupNoneId) {
|
||||
if (position < bookGroups.size) 1 else 0
|
||||
} else {
|
||||
0
|
||||
if (groupId != rootGroupId) {
|
||||
return 0
|
||||
}
|
||||
if (position < bookGroups.size) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun getItem(position: Int): Any {
|
||||
return if (groupId == AppConst.bookGroupNoneId) {
|
||||
if (position < bookGroups.size) {
|
||||
bookGroups[position]
|
||||
} else {
|
||||
books[position - bookGroups.size]
|
||||
}
|
||||
} else {
|
||||
books[position]
|
||||
override fun getItem(position: Int): Any? {
|
||||
if (groupId != rootGroupId) {
|
||||
return books.getOrNull(position)
|
||||
}
|
||||
if (position < bookGroups.size) {
|
||||
return bookGroups[position]
|
||||
}
|
||||
return books.getOrNull(position - bookGroups.size)
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
|
||||
@@ -29,7 +29,7 @@ class CodeDialog() : BaseDialogFragment(R.layout.dialog_code_view) {
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
setLayout(0.96f, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
setLayout(1f, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
}
|
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
||||
41
app/src/main/java/io/legado/app/utils/DataExtensions.kt
Normal file
@@ -0,0 +1,41 @@
|
||||
package io.legado.app.utils
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.full.primaryConstructor
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : Any> T.deepCopy(): T {
|
||||
//如果不是数据类,直接返回
|
||||
if (!this::class.isData) {
|
||||
return this
|
||||
}
|
||||
|
||||
//拿到构造函数
|
||||
return this::class.primaryConstructor!!.let { primaryConstructor ->
|
||||
//转换类型
|
||||
//memberProperties 返回非扩展属性中的第一个并将构造函数赋值给其
|
||||
//最终value=第一个参数类型的对象
|
||||
|
||||
//如果当前类(这里的当前类指的是参数对应的类型,比如说这里如果非基本类型时)是数据类
|
||||
|
||||
//最终返回一个新的映射map,即返回一个属性值重新组合的map,并调用callBy返回指定的对象
|
||||
primaryConstructor.parameters.associate { parameter ->
|
||||
//转换类型
|
||||
//memberProperties 返回非扩展属性中的第一个并将构造函数赋值给其
|
||||
//最终value=第一个参数类型的对象
|
||||
val value = (this::class as KClass<T>).memberProperties.first {
|
||||
it.name == parameter.name
|
||||
}.get(this)
|
||||
|
||||
//如果当前类(这里的当前类指的是参数对应的类型,比如说这里如果非基本类型时)是数据类
|
||||
if ((parameter.type.classifier as? KClass<*>)?.isData == true) {
|
||||
parameter to value?.deepCopy()
|
||||
} else {
|
||||
parameter to value
|
||||
}
|
||||
|
||||
//最终返回一个新的映射map,即返回一个属性值重新组合的map,并调用callBy返回指定的对象
|
||||
}.let(primaryConstructor::callBy)
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import com.google.gson.*
|
||||
import com.google.gson.internal.LinkedTreeMap
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.google.gson.stream.JsonWriter
|
||||
|
||||
import java.io.OutputStream
|
||||
import java.io.OutputStreamWriter
|
||||
import java.lang.reflect.ParameterizedType
|
||||
@@ -26,22 +25,16 @@ val GSON: Gson by lazy {
|
||||
|
||||
inline fun <reified T> genericType(): Type = object : TypeToken<T>() {}.type
|
||||
|
||||
inline fun <reified T> Gson.fromJsonObject(json: String?): T? {//可转成任意类型
|
||||
json ?: return null
|
||||
inline fun <reified T> Gson.fromJsonObject(json: String?): Result<T?> {
|
||||
return kotlin.runCatching {
|
||||
fromJson(json, genericType<T>()) as? T
|
||||
}.onFailure {
|
||||
DebugLog.e("GSON解析出错", json, it)
|
||||
}.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T> Gson.fromJsonArray(json: String?): List<T>? {
|
||||
json ?: return null
|
||||
inline fun <reified T> Gson.fromJsonArray(json: String?): Result<List<T>?> {
|
||||
return kotlin.runCatching {
|
||||
fromJson(json, ParameterizedTypeImpl(T::class.java)) as? List<T>
|
||||
}.onFailure {
|
||||
DebugLog.e("GSON解析出错", json, it)
|
||||
}.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
fun Gson.writeToOutputStream(out: OutputStream, any: Any) {
|
||||
|
||||
@@ -12,10 +12,10 @@ fun Intent.putJson(key: String, any: Any?) {
|
||||
|
||||
inline fun <reified T> Intent.getJsonObject(key: String): T? {
|
||||
val value = getStringExtra(key)
|
||||
return GSON.fromJsonObject<T>(value)
|
||||
return GSON.fromJsonObject<T>(value).getOrNull()
|
||||
}
|
||||
|
||||
inline fun <reified T> Intent.getJsonArray(key: String): List<T>? {
|
||||
val value = getStringExtra(key)
|
||||
return GSON.fromJsonArray(value)
|
||||
return GSON.fromJsonArray<T>(value).getOrNull()
|
||||
}
|
||||
@@ -49,7 +49,8 @@ class BookSourceDebugWebSocket(handshakeRequest: NanoHTTPD.IHTTPSession) :
|
||||
close(NanoWSD.WebSocketFrame.CloseCode.NormalClosure, "调试结束", false)
|
||||
return@launch
|
||||
}
|
||||
val debugBean = GSON.fromJsonObject<Map<String, String>>(message.textPayload)
|
||||
val debugBean =
|
||||
GSON.fromJsonObject<Map<String, String>>(message.textPayload).getOrNull()
|
||||
if (debugBean != null) {
|
||||
val tag = debugBean["tag"]
|
||||
val key = debugBean["key"]
|
||||
|
||||
@@ -49,7 +49,8 @@ class RssSourceDebugWebSocket(handshakeRequest: NanoHTTPD.IHTTPSession) :
|
||||
close(NanoWSD.WebSocketFrame.CloseCode.NormalClosure, "调试结束", false)
|
||||
return@launch
|
||||
}
|
||||
val debugBean = GSON.fromJsonObject<Map<String, String>>(message.textPayload)
|
||||
val debugBean =
|
||||
GSON.fromJsonObject<Map<String, String>>(message.textPayload).getOrNull()
|
||||
if (debugBean != null) {
|
||||
val tag = debugBean["tag"]
|
||||
if (tag.isNullOrBlank()) {
|
||||
|
||||
@@ -38,6 +38,7 @@ class AssetsWeb(rootPath: String) {
|
||||
suffix.equals(".js", ignoreCase = true) -> "text/javascript"
|
||||
suffix.equals(".css", ignoreCase = true) -> "text/css"
|
||||
suffix.equals(".ico", ignoreCase = true) -> "image/x-icon"
|
||||
suffix.equals(".jpg", ignoreCase = true) -> "image/jpg"
|
||||
else -> "text/html"
|
||||
}
|
||||
}
|
||||
|
||||