@@ -13,6 +13,7 @@ import {
1313 wait ,
1414} from 'helper' ;
1515import { request , toast , useInit } from 'main' ;
16+ import { decryptData , getImglistByHtml } from 'userscript/copyApi' ;
1617
1718// API 参考:https://github.com/fumiama/copymanga/blob/279e08b06a70307bf20162900103ec1fdcb97751/app/src/main/res/values/strings.xml
1819
@@ -51,62 +52,6 @@ const pcApi = new (class {
5152 ) ;
5253} ) ( ) ;
5354
54- // by: https://github.com/MapoMagpie/comic-looms/blob/7799f87fdd5a8ac73c878f338b7ae6aa5c0b2d18/src/platform/matchers/mangacopy.ts#L96-L125
55- const decryptData = async (
56- raw : string ,
57- key : string = unsafeWindow . cct || 'oppzzivv.nzm.oip' ,
58- ) => {
59- const cipher = raw . slice ( 16 ) ;
60- const iv = raw . slice ( 0 , 16 ) ;
61-
62- const decryptedBuffer = await crypto . subtle . decrypt (
63- { name : 'AES-CBC' , iv : new TextEncoder ( ) . encode ( iv ) } ,
64- await crypto . subtle . importKey (
65- 'raw' ,
66- new TextEncoder ( ) . encode ( key ) ,
67- { name : 'AES-CBC' } ,
68- false ,
69- [ 'decrypt' ] ,
70- ) ,
71- new Uint8Array (
72- cipher . match ( / .{ 1 , 2 } / g) ! . map ( ( byte ) => Number . parseInt ( byte , 16 ) ) ,
73- ) . buffer ,
74- ) ;
75- return JSON . parse ( new TextDecoder ( ) . decode ( decryptedBuffer ) ) ;
76- } ;
77-
78- declare const contentKey : string ;
79- declare const cct : string ;
80-
81- /** 通过解析网页变量获取图片列表 */
82- const getImglistByHtml = async ( comicName : string , id : string ) => {
83- const getKeys = async ( ) : Promise < [ string , string ] > => {
84- // 移动端没有 contentKey,就从 PC 端的网页获取
85- if ( ! unsafeWindow . contentKey ) {
86- const html = await request (
87- `${ location . origin } /comic/${ comicName } /chapter/${ id } ` ,
88- {
89- fetch : false ,
90- headers : {
91- 'User-Agent' :
92- 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.79 Safari/537.36' ,
93- } ,
94- } ,
95- ) ;
96- const [ script ] = html . responseText . match (
97- / (?< = < s c r i p t > \s + ) ( v a r .+ ?c o n t e n t K e y = .+ ?) (? = < \/ s c r i p t ) / gs,
98- ) ! ;
99- eval ( script ) ; // oxlint-disable-line no-eval
100- }
101-
102- return [ contentKey , cct ] ;
103- } ;
104-
105- const keys = await getKeys ( ) ;
106- const res : { url : string } [ ] = await decryptData ( ...keys ) ;
107- return res . map ( ( { url } ) => url . replace ( / (?< = ( \/ | \. ) ) c 8 0 0 x / , 'c1500x' ) ) ;
108- } ;
109-
11055// 在目录页显示上次阅读记录
11156const handleLastChapter = ( comicName : string ) => {
11257 let a : HTMLAnchorElement ;
@@ -496,7 +441,9 @@ const buildChapters = async (comicName: string, hiddenType: HiddenType) => {
496441 if ( titleDom ) return getImglistByApi ( ) ;
497442 // 其他普通漫画优先通过解析网页变量加载,避免触发 api 的限制
498443 try {
499- const imgList = await getImglistByHtml ( comicName , id ) ;
444+ const imgList = await getImglistByHtml (
445+ `${ location . origin } /comic/${ comicName } /chapter/${ id } ` ,
446+ ) ;
500447 if ( imgList . length === 0 ) throw new Error ( '解析网页变量失败' ) ;
501448 return imgList ;
502449 } catch ( error ) {
0 commit comments