deleted folder

This commit is contained in:
lem85930 2024-05-22 19:53:52 +08:00
parent 03fe9c8c4e
commit aeb70c2987
137 changed files with 0 additions and 91354 deletions

View File

@ -1,186 +0,0 @@
name: Spider
on:
workflow_dispatch:
jobs:
build:
name: TVSpider
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
os: [ "ubuntu-latest" ]
steps:
- name: Clone Base Repository
uses: actions/checkout@v3
with:
repository: ${{ secrets.GH_PATH}}
fetch-depth: 0
token: ${{ secrets.GH_TOKEN}}
- name: Clone TVSpider Repository
uses: actions/checkout@v3
with:
repository: jadehh/TVSpider
path: tmp
fetch-depth: 0 # 显示所有提交的日志
- name: Build JS Config
run: |
cp -r ./tmp ./code
cd code
pip install -r requirements.txt
python build.py --aliToken "${{ secrets.ALI_TOKEN }}" --biliCookie "${{ secrets.BILI_COOKIE}}"
python build.py --aliToken "${{ secrets.ALI_TOKEN }}" --biliCookie "${{ secrets.BILI_COOKIE}}" --is_18 True
- name: Commit JS Config files
run: |
git config --global user.email "${{ secrets.GT_EMAIL }}"
git config --global user.name "${{ secrets.GT_ACTOR }}"
checkname=$(git rev-list --max-parents=0 HEAD)
git checkout $checkname -b js ##分支不存在用这个
cp -r code/18_open_config.json ./
cp -r code/18_tv_config.json ./
cp -r code/open_config.json ./
cp -r code/tv_config.json ./
cp -r code/js/ ./
cp -r code/lib ./
cp -r code/README.md ./README.md
cp -r code/resources ./
git add 18_open_config.json
git add 18_tv_config.json
git add open_config.json
git add tv_config.json
git add resources
git add js
git add lib
git add README.md
commit_msg="* 更新TVConfig和OpenConfig"
git commit -a -m "$commit_msg"
- name: Push JS Config Changes To Gitee
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GE_TOKEN }}
repository: ${{ secrets.GE_PATH }}
directory: .
branch: js
force: true
github_url: https://gitee.com
env:
GITHUB_ACTOR: ${{ secrets.GH_ACTOR }}
- name: Push JS Config Changes To Github
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GH_TOKEN }}
repository: ${{ secrets.GH_PATH }}
directory: .
branch: js
force: true
env:
GITHUB_ACTOR: ${{ secrets.GH_ACTOR }}
- name: Build NodeJS Config files
run: |
rm -r ./code
cp -r ./tmp ./code
cd code/
python build.py --aliToken "${{ secrets.ALI_TOKEN }}" --biliCookie "${{ secrets.BILI_COOKIE}}"
cd nodejs
npm install qs --save
npm install tunnel --save
npm install
npm run build
- name: Commit NodeJS Config files
run: |
git config --global user.email "${{ secrets.GT_EMAIL }}"
git config --global user.name "${{ secrets.GT_ACTOR }}"
checkname=$(git rev-list --max-parents=0 HEAD)
git checkout $checkname -b dist ##分支不存在用这个
cp -r code/nodejs/dist/* ./
cp -r code/nodejs/readme.md ./README.md
git add index.config.js
git add index.config.js.md5
git add index.js
git add index.js.md5
git add README.md
commit_msg="* 发布 CatVodOpen新源"
git commit -a -m "$commit_msg"
- name: Push NodelJS Config Changes To Gitee
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GE_TOKEN }}
repository: ${{ secrets.GE_PATH }}
directory: .
branch: dist
force: true
github_url: https://gitee.com
env:
GITHUB_ACTOR: ${{ secrets.GH_ACTOR }}
- name: Push NodelJS Config Changes To Github
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GH_TOKEN }}
repository: ${{ secrets.GH_PATH }}
directory: .
branch: dist
force: true
env:
GITHUB_ACTOR: ${{ secrets.GH_ACTOR }}
- name: Build 18+ NodeJS Config files
run: |
rm -r ./code
cp -r ./tmp ./code
cd code/
python build.py --aliToken "${{ secrets.ALI_TOKEN }}" --biliCookie "${{ secrets.BILI_COOKIE}}" --is_18 True
cd nodejs
npm install qs --save
npm install tunnel --save
npm install
npm run build
- name: Commit 18+ NodeJS Config files
run: |
git config --global user.email "${{ secrets.GT_EMAIL }}"
git config --global user.name "${{ secrets.GT_ACTOR }}"
checkname=$(git rev-list --max-parents=0 HEAD)
git checkout $checkname -b 18_dist ##分支不存在用这个
cp -r code/nodejs/dist/* ./
cp -r code/nodejs/readme.md ./README.md
git add index.config.js
git add index.config.js.md5
git add index.js
git add index.js.md5
git add README.md
commit_msg="* 发布 CatVodOpen 18+ 新源"
git commit -a -m "$commit_msg"
- name: Push NodelJS Config Changes To Gitee
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GE_TOKEN }}
repository: ${{ secrets.GE_PATH }}
directory: .
branch: 18_dist
force: true
github_url: https://gitee.com
env:
GITHUB_ACTOR: ${{ secrets.GH_ACTOR }}
- name: Push NodelJS Config Changes To Github
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GH_TOKEN }}
repository: ${{ secrets.GH_PATH }}
directory: .
branch: 18_dist
force: true
env:
GITHUB_ACTOR: ${{ secrets.GH_ACTOR }}

20
JN/CATJS/.gitignore vendored
View File

@ -1,20 +0,0 @@
local
node_modules
.idea
log
local
open_config.json
test.py
tv_config.json
nodejs/dist
nodejs/node_modules
nodejs/src
releases/日志上传服务V1.0.1/Windows/

View File

@ -1,16 +0,0 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: 当前文件",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": true
}
]
}

View File

@ -1,366 +0,0 @@
### 更新日志
### V1.0.7.0 - 2024-04-23
* 新增69书吧源
----
<details onclose>
### V1.0.6.9 - 2024-04-16
* 修复bilibili登录失败仍然显示历史记录的bug
----
### V1.0.6.8 - 2024-04-16
* 解决豆瓣搜索问题,并支持翻页
----
### V1.0.6.7 - 2024-04-15
* 支持哔哩哔哩搜索翻页 #45
----
### V1.0.6.6 - 2024-04-15
* 支持南瓜影视搜索翻页 #46
* 优化南瓜搜索部分图片加载不出来的bug
* 新增格式化url的方法
----
### V1.0.6.5 - 2024-04-15
* 新增天天影视源
----
### V1.0.6.4 - 2024-04-14
* 修复SP360弹幕加载
* 修复bilibili在TV无法播放的问题,并删除相关和DASH播放的视频链接
----
### V1.0.6.3 - 2024-04-14
* 修复360无法播放的bug,使用sniff解析URL
----
### V1.0.6.2 - 2024-04-14
* 修复含羞草类别问题
----
### V1.0.6.1 - 2024-04-13
* 新增含羞草源
* 支持搜索页面的翻页
----
### V1.0.6.0 - 2024-04-13
* 新增磁力熊源
----
### V1.0.5.9 - 2024-04-13
* 支持Log日志上传
----
### V1.0.5.8 - 2024-04-02
* 修复玩偶姐姐和jable源
----
### V1.0.5.7 - 2024-04-02
* 完成哔哩哔哩爬虫,优化播放列表格式
----
### V1.0.5.6 - 2024-04-02
* 新增哔哩哔哩源
* 支持哔哩哔哩登录,Cookie传入
----
### V1.0.5.5 - 2024-04-02
* 解决玩偶哥哥无法登录阿里的bug
----
### V1.0.5.4 - 2024-04-02
* 修复阿里盘无法加载的bug
----
### V1.0.5.3 - 2024-04-02
* 修复爱看机器人部分详情无法打开的bug
----
### V1.0.5.2 - 2024-04-02
* 修改海外看名称
----
### V1.0.5.1 - 2024-04-02
* 新增海外看
* 解决采集网站搜索图片加载不出来的bug
* 去除log日志输出
----
### V1.0.5.0 - 2024-04-01
* 解决动漫加载不出来的bug
----
### V1.0.4.9 - 2024-04-01
* 合并MX动漫分支到主分支中
----
### V1.0.4.8 - 2024-04-01
* 添加sniff方法
----
### V1.0.4.7 - 2024-04-01
* 新增MX动漫源
----
### V1.0.4.6 - 2024-04-01
* 优化nodejs Spider
* 解决拷贝漫画
----
### V1.0.4.5 - 2024-03-29
* 解决笔趣阁历史记录无法加载的bug
----
### V1.0.4.4 - 2024-03-29
* 修复笔趣阁
----
### V1.0.4.3 - 2024-03-29
* 取消日志输出解决IOS上的问题
----
### V1.0.4.2 - 2024-03-29
* 支持小说和音乐代码转nodejs
* 支持push操作
----
### V1.0.4.1 - 2024-03-29
* 解决图书和音乐加载失败的bug
----
### V1.0.4.0 - 2024-03-27
* 去除已失效链接
----
### V1.0.3.9 - 2024-03-27
* 解决电影港首页无法加载图片的bug
* 去除已失效链接
----
### V1.0.3.8 - 2024-03-27
* 切换到主分支,其他分支都是用来发布
----
### V1.0.3.7 - 2024-03-27
* 解决豆瓣类别无法加载的bug
* 解决豆瓣无法加载第二页的bug
* 解决阿里盘搜无法播放的bug
* 解决阿里纸条无法加载的bug
* 解决爱看机器人分类加载不正常的bug,爱看机器人部分无法播放待解决
----
### V1.0.3.6 - 2024-03-27
* 解决酷云无法打开的bug
----
### V1.0.3.5 - 2024-03-27
* 解决proxy代理设置的bug #19
* 使用db替代local所有的方法
* 取消log日志的输出
----
### V1.0.3.4 - 2024-03-27
* 完成阿里类的资源
----
### V1.0.3.3 - 2024-03-27
* 日志正常输出,使用数据库管理阿里云盘的缓存信息
----
### V1.0.3.2 - 2024-03-27
* 使用数据库来存储阿里云盘的值
----
### V1.0.3.1 - 2024-03-27
* 取消文件写入的日志输出
----
### V1.0.3.0 - 2024-03-27
* 完成quick js 转 node js代码
----
### V1.0.2.9 - 2024-03-27
* 同步Gitee分支和Github分支
----
### V1.0.2.8 - 2024-03-27
* 自动发布支持新版本CatVodOpen源
----
### V1.0.2.7 - 2024-03-18
* 新增南瓜影视
---
### V1.0.2.6 - 2024-03-13
* 修复详情界面,返回episodeUrl需要带上VodDetail和episodeId
* 播放页面,解析其他信息
---
### V1.0.2.5 - 2024-03-07
* 完成jable所有功能
* 新增虎牙直播源
---
### V1.0.2.4 - 2024-03-06
* 修复阿里云盘分享网的详情图片无法加载的问题
* 新增本地源推送
---
### V1.0.2.4 - 2024-02-29
* 新增磁力狗源
* 新增Jable源
* 更新荐片二级菜单
---
### V1.0.2.3 - 2024-02-29
* 修改影视车新地址
---
### V1.0.2.2 - 2024-02-21
* 支持星视界采集
* 新增电影港采集
---
### V1.0.2.1 - 2024-02-20
* 支持6080采集
---
### V1.0.2.0 - 2024-02-19
* 支持Mp4电影采集
---
### V1.0.1.9 - 2024-02-06
* 以非凡采集作为采集的基础类,后续基于非凡采集开发
* CatVodOpen无法解决皮皮虾M3u8跨域的问题
---
### V1.0.1.8 - 2024-02-06
* 新增加菲猫资源
---
### V1.0.1.7 - 2024-02-04
* 厂长资源支持阿里云盘和磁力连接播放
---
### V1.0.1.6 - 2024-02-01
* 去除玩偶哥哥介绍视频
---
### V1.0.1.5 - 2024-02-01
* 电影天堂详情页面解析
---
### V1.0.1.4 - 2024-01-26
* 添加Audiomack音乐爬虫
---
### V1.0.1.3 - 2024-01-26
* 阿里云盘分享首页和类别爬虫
---
### V1.0.1.3 - 2024-01-24
* 待完成色花堂和电影天堂爬虫
---
### V1.0.1.2 - 2024-01-24
* 新增4k资源网站
---
### V1.0.1.1 - 2024-01-24
* 新增量子资源网
---
### V1.0.1.0 - 2024-01-22
* freeok 搜索难点在与验证码的识别
---
### V1.0.0.9 - 2024-01-19
* 新增OK资源源
---
### V1.0.0.8 - 2024-01-03
* 阿里云盘分享链接带file id,导致会保存整个分享链接的文件
* 如果有file id,只保存当前文件夹下的文件
---
### V1.0.0.7 - 2024-01-03
* 新增阿里纸条爬虫
---
### V1.0.0.6 - 2024-01-03
* 修复70看看无法播放的bug
* 解决搜索关键词因存在空格导致无法搜索不出结果的bug
---
### V1.0.0.6 - 2024-01-03
* 新增爱看机器人源
* 新增爱影视源
---
### V1.0.0.5 - 2024-01-03
* 修复阿里字幕的问题
* 阿里云盘初始化时,不在删除文件夹,使用默认的文件夹File ID
---
### V1.0.0.4 - 2023-12-22
* 完成泥巴的视频播放功能
* 支持自动发布功能
---
### V1.0.0.3 - 2023-12-21
* 支持泥巴首页解析
* ext区分TVBox和CatOpen
* 解决ext的数据类型的bug
* 泥巴二级菜单添加全部按钮
---
### V1.0.0.3 - 2023-12-14
* 支持玩偶二级菜单,支持分类页面下一页
* 支持TVBox接口
* 先初始化阿里云盘,在清空缓存文件
* TV客户端使用requests请求,code为undefined的bug
* 根据Content内容自定义Code码
* 分享文件字幕和视频文件去重复
---
### V1.0.0.2 - 2023-12-14
* 转存文件如果存在,无需在转存一遍
---
### V1.0.0.1 - 2023-12-14
* 完善阿里日志输出
* 完善玩偶哥哥日志输出
---
### V1.0.0.0 - 2023-12-13
* 完成阿里Api的优化,不重复刷新Token
* 修改阿里玩偶的地址
* 阿里玩偶使用req2来进行解析
* 还原index.js内容
* 解决阿里玩偶分类页加载不出来的bug
* 优化阿里Api
* 解决带字幕的bug
---
</details>

View File

@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View File

@ -1,80 +0,0 @@
# CatVodOpen和TvBox
## 食用前阅读
&ensp;&ensp;授人以鱼不如授人以渔本仓意指在教会大家学会Spider也欢迎大家提ISSUE一起学习一起进步。<br>
&ensp;&ensp;以下资源不能保证内容的合法性、准确性、完整性和有效性,请根据情况自行判断。
仅用于测试和学习研究,禁止用于商业用途,不得将其用于违反国家、地区、组织等的法律法规或相关规定的其他用途。
使用任何第三方硬件、软件、所造成的一切后果由使用的个人或组织承担,与本文内容无关。
所有直接或间接使用本内容的个人和组织,应 24 小时内完成学习和研究,并及时删除本文内容。
所有基于本内容的源代码,进行的任何修改,为其他个人或组织的自发行为,与本内容没有任何直接或间接的关系,所造成的一切后果亦与本内容和本管理者无关。
本管理者保留随时更改或补充此免责声明的权利。一旦使用、复制、转载、发布、修改了本文内容,则视为您已接受此免责声明。否则后果自负。
本接口无公众号、无盈利、无引流、免费分享给小白使用,请勿轻信他人,谨防上当受骗。
[使用教程见Wiki](https://github.com/jadehh/TVSpider/wiki)
## TVBox互联网发布地址
[TV发布地址](https://github.com/FongMi/Release/tree/main/apk/release)
```bash
https://gh.con.sh/https://raw.githubusercontent.com/jadehh/TVSpider/js/tv_config.json
```
> 配置信息见js分支分支
## CatVodOpen
[CatVodOpen发布地址](https://github.com/catvod/CatVodOpen/releases)
> 注意使用Gitee或Github导入并设置为私有仓库<font color="red">CatVodOpen仅支持私有仓库</font>
V1.1.3版本以上
```bash
gitee://Token@gitee.com/jadehh_743/TVSpider/dist/index.js.md5
```
<font color="red">**改动**</font>
* quickjs改为nodejsproxy设置修改
* 在ios上无法使用local使用db替换local所有方法
* nodejs 的优势在于更加灵活
> 配置信息见dist分支
V1.1.2版本以下
```bash
gitee://Token@gitee.com/jadehh_743/TVSpider/js/open_config.json
```
> 配置信息见js分支分支
## config文件生成
```bash
python build.py --aliToken aliToken
```
> Token如果失效,需要重新获取阿里Token
>
> [阿里Token获取](https://alist.nn.ci/zh/guide/drivers/aliyundrive.html)
>
> nodejs 部分只生成代码需要手动build区分18+
## 直播源生成
> 见[jadehh/LiveSpider](https://github.com/jadehh/LiveSpider)
## 遇到的问题
* 玩偶姐姐播放不了,需要切换VPN节点
* m3u8遇到跨域的问题可以尝试使用代理来进行加载如果没有跨域使用代理会引起死循环
* 虎牙弹幕功能无法实现,现在并不支持WebSocket来监听弹幕
* SP360启用嗅探解析,CatVodOpen目前还不支持嗅探
* CatVodOpen Windows无法预览Jable和Doll图片,需要手动开启代理加载。
* TV影视暂不不支持哔哩哔哩DASH文件播放
* 老版本的CatVodOpen cfg参数类型为:string,TV参数类型为[object],所有需要区分,初始化的时候还是用this.cfgObj
## 特别说明
* 近期CatVodOpen更新移除了quickjs,导致无法使用,请尝试使用旧版本
* 或切换至nodejs目录下编译生成dist目录dist目录发布到dist分支下
* main分支用于代码测试(不包含任何配置信息)js分支发布支持quickjs爬虫配置信息dist分支发布支持nodejs爬虫配置信息
* 所有的配置信息都通过Github Actions发布通过创建tag来生成新的配置信息并自动发布
* fork仓库时去掉仅复制main分支的&#x2714;这样就可以fork所有的分支了
## 赞助
如果觉得此项目有用可以考虑赞助我喝杯咖啡感谢star❤
<img src="./resources/wechat.jpg" alt="微信" width="256" height="256" align="left" />

View File

@ -1,228 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File : buildConfig.py
# @Author : jade
# @Date : 2024/4/22 10:53
# @Email : jadehh@1ive.com
# @Software : Samples
# @Desc : 生成配置文件包含Config,Dist分支
import json
import os
from jade import str_to_bool, CreateSavePath, GetLastDir, GetTimeStamp
import argparse
class JSMoudle():
def __init__(self, js_file):
self.js_file = js_file
self.js_name = GetLastDir(js_file).split(".")[0]
self.is_18 = False
self.getContent()
def getContent(self):
with open(self.js_file, "rb") as f:
self.js_str = str(f.read(), encoding="utf-8")
if "🔞" in self.js_str:
self.is_18 = True
def getName(self):
try:
name = (self.js_str.split("getName()")[-1].split("}")[0].split("return")[-1].split('"')[1])
return name
except:
return None
def getAppName(self):
try:
name = (self.js_str.split("getAppName()")[-1].split("}")[0].split("return")[-1].split('"')[1])
return name
except Exception as e:
return None
def getJSName(self):
try:
name = (self.js_str.split("getJSName()")[-1].split("}")[0].split("return")[-1].split('"')[1])
return name
except:
return None
def getType(self):
try:
name = (self.js_str.split("getType()")[-1].split("}")[0].split("return")[-1])
return int(name.strip())
except:
return None
class Build():
def __init__(self, channelKey,aliToken, biliCookie, is_18="False"):
self.is_18 = str_to_bool(is_18)
self.aliToken = aliToken
self.biliCookie = biliCookie
self.jsMouleList = self.getJsFile(channelKey)
super().__init__()
def getJsFile(self,channelKey):
jsMoudleList = []
js_path = "js"
fileList = os.listdir(js_path)
for fileName in fileList:
jsMoudle = JSMoudle(js_path + "/" + fileName)
if jsMoudle.getName() is not None:
if len(channelKey):
if channelKey == jsMoudle.getJSName():
jsMoudleList.append(jsMoudle)
else:
jsMoudleList.append(jsMoudle)
return jsMoudleList
def getBaseConfig(self, baseObj, jsMoudle, tvType="TVBox"):
baseObj["key"] = jsMoudle.js_name
baseObj["name"] = jsMoudle.getName()
baseObj["ext"] = {"box": tvType}
baseObj["api"] = "./" + jsMoudle.js_file
baseObj["type"] = jsMoudle.getType()
return baseObj
def getCustomConfig(self, baseObj, jsMoudle):
if "阿里" in jsMoudle.getAppName() or "厂长直连" in jsMoudle.getAppName():
baseObj["ext"]["token"] = self.aliToken
elif jsMoudle.getAppName() == "泥视频":
baseObj["ext"]["code"] = int(self.is_18)
elif jsMoudle.getAppName() == "量子资源":
baseObj["ext"]["code"] = int(self.is_18)
elif jsMoudle.getAppName() == "哔哩哔哩":
baseObj["ext"]["cookie"] = self.biliCookie
return baseObj
def getConfig(self, tyType="TVBox", type=3):
baseObj = {"key": "", "name": "", "api": "", "timeout": 30, "ext": {}}
if type == 3:
baseObj["playerType"] = 0
siteList = []
for jsMoudle in self.jsMouleList:
if jsMoudle.is_18 == self.is_18 and jsMoudle.getType() == type:
siteObj = baseObj.copy()
siteObj = self.getBaseConfig(siteObj, jsMoudle, tyType)
siteObj = self.getCustomConfig(siteObj, jsMoudle)
siteList.append(siteObj)
return siteList
def getJsList(self, tyType="TVBox", type=3):
jsList = []
for jsMoudle in self.jsMouleList:
if jsMoudle.is_18 == self.is_18 and jsMoudle.getType() == type:
jsList.append(jsMoudle)
return jsList
def getConfigByTvType(self, tvType):
videoConfig = self.getConfig(tvType, 3)
bookConfig = self.getConfig(tvType, 10)
carToonConfig = self.getConfig(tvType, 20)
jsonConfig = self.getJsonConfigByTvType(tvType)
return videoConfig, bookConfig, carToonConfig, jsonConfig
def getJsonConfigByTvType(self, tvType):
jsonPath = "json"
with open(os.path.join(jsonPath, "{}.json".format(tvType)), "rb") as f:
return json.load(f)
def writeJsonConfig(self, tvType, jsonConfig):
config_name = "{}_config.json".format(tvType)
if self.is_18:
config_name = "18_" + config_name
with open(config_name, "wb") as f:
f.write(json.dumps(jsonConfig, indent=4, ensure_ascii=False).encode("utf-8"))
def writeTVConfig(self):
print("Write TV Config")
tvType = "TVBox"
videoConfig, bookConfig, carToonConfig, jsonConfig = self.getConfigByTvType(tvType)
jsonConfig["sites"] = videoConfig
self.writeJsonConfig("tv", jsonConfig)
def writeOpenConfig(self):
print("Write Open Config")
tvType = "CatOpen"
videoConfig, bookConfig, carToonConfig, jsonConfig = self.getConfigByTvType(tvType)
jsonConfig["video"]["sites"] = videoConfig
jsonConfig["read"]["sites"] = bookConfig
self.writeJsonConfig("open", jsonConfig)
def jsToNodejs(self, jsList, typeName="video"):
nodejsPath = "nodejs/src/spider/"
savePath = CreateSavePath(os.path.join(nodejsPath, typeName))
for jsMoudle in jsList:
write_content = ""
with open(os.path.join(nodejsPath, "tmpSpider.txt"), "rb") as f:
contentlist = f.readlines()
for content in contentlist:
write_content = write_content + str(content, encoding="utf-8").replace("temp",
jsMoudle.getJSName()).replace(
"updateTime", GetTimeStamp())
saveJsPath = os.path.join(nodejsPath, typeName, GetLastDir(jsMoudle.js_file))
with open(saveJsPath, "wb") as f:
f.write(write_content.encode("utf-8"))
fileList = []
fileNameList = os.listdir(os.path.join(nodejsPath, typeName))
for fileName in fileNameList:
fileList.append(fileName)
writeContent,spiderList = self.getImportNameByType(fileList,typeName)
return writeContent,spiderList
def getImportNameByType(self,fileList,typeName="video"):
writeRoutersContent = ""
spiderList = []
for fileName in fileList:
jsName = fileName.split(".")[0]
spiderList.append(jsName)
importStr = "import {} from './spider/{}/{}.js';\n".format(jsName, typeName, jsName)
writeRoutersContent = writeRoutersContent + importStr
return writeRoutersContent,spiderList
def writeRouterJs(self,writeRouterStr,spiderList):
writeRouterStr = writeRouterStr + "const spiders = [{}];".format(",".join(spiderList)) + "\n"
with open("nodejs/src/router.txt", "rb") as f:
contentlist = f.readlines()
for content in contentlist:
writeRouterStr = writeRouterStr + str(content, encoding="utf-8")
with open("nodejs/src/router.js", "wb") as f:
f.write(writeRouterStr.encode("utf-8"))
def writeNodeConfig(self):
writeContent = ""
with open("nodejs/src/index.config.txt", "rb") as f:
contentlist = f.readlines()
for content in contentlist:
writeContent = writeContent + str(content, encoding="utf-8").replace("temp", self.aliToken).replace(
"bilitmep", self.biliCookie) + "\n"
with open("nodejs/src/index.config.js", "wb") as f:
f.write(writeContent.encode("utf-8"))
def writeDistConfig(self):
tvType = "CatOpen"
videoWriteContent,videoSpiderList = self.jsToNodejs(self.getJsList(tvType, type=3), "video")
self.jsToNodejs(self.getJsList(tvType, type=10), "book")
bookWriteContent,bookSpiderList = self.jsToNodejs(self.getJsList(tvType, type=20), "book")
panWriteContent,panSpiderList = self.jsToNodejs([], "pan")
videoSpiderList.extend(bookSpiderList)
videoSpiderList.extend(panSpiderList)
self.writeRouterJs(videoWriteContent+bookWriteContent+panWriteContent,videoSpiderList)
self.writeNodeConfig()
def build(self):
self.writeTVConfig()
self.writeOpenConfig()
self.writeDistConfig()
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--key', type=str, default="") ## 添加环境变量
parser.add_argument('--aliToken', type=str, default="51427b95ab9d47a6921a27951ebd3f1e") ## 添加环境变量
parser.add_argument('--is_18', type=str, default="False") ## 添加
parser.add_argument('--biliCookie', type=str,
default="buvid3=02675249-8ED3-C418-87F5-59E18316459714816infoc; b_nut=1704421014; _uuid=5D435F74-F574-D9AB-62C1-B9294DE465D913102infoc; buvid_fp=e8c5650c749398e9b5cad3f3ddb5081e; buvid4=007E85D1-52C1-7E6E-07CF-837FFBC9349516677-024010502-J5vTDSZDCw4fNnXRejbSVg%3D%3D; rpdid=|()kYJmulRu0J'u~|RRJl)JR; PVID=1; SESSDATA=3be091d3%2C1720332009%2C699ed%2A11CjAcCdwXG5kY1umhCOpQHOn_WP7L9xFBfWO7KKd4BPweodpR6VyIfeNyPiRmkr5jCqsSVjg0R0dZOVVHRUo3RnhPRTZFc3JPbGdiUjFCdHpiRDhiTkticmdKTjVyS1VhbDdvNjFMSDJlbUJydUlRdjFUNGFBNkJlV2ZTa0N1Q1BEVi1QYTQzTUh3IIEC; bili_jct=b0ee7b5d3f27df893545d811d95506d4; DedeUserID=78014638; DedeUserID__ckMd5=4c8c5d65065e468a; enable_web_push=DISABLE; header_theme_version=CLOSE; home_feed_column=5; CURRENT_BLACKGAP=0; CURRENT_FNVAL=4048; b_lsid=75E916AA_18EA1A8D995; bsource=search_baidu; FEED_LIVE_VERSION=V_HEADER_LIVE_NO_POP; browser_resolution=1507-691; bili_ticket=eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTIzNjk5MTMsImlhdCI6MTcxMjExMDY1MywicGx0IjotMX0.8zQW_fNTCSBlK_JkHnzu3gDw62wuTK1qgKcbGec3swM; bili_ticket_expires=171236985") ## 添加
args = parser.parse_args()
build = Build(channelKey=args.key,aliToken=args.aliToken, biliCookie=args.biliCookie, is_18=args.is_18)
build.build()

File diff suppressed because it is too large Load Diff

View File

@ -1,238 +0,0 @@
/*
* @File : 4kysxz.js.js
* @Author : jade
* @Date : 2024/1/24 16:47
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 4k高清网 (已失效)
*/
import {_} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class YSXZSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://4kysxz.top"
}
getAppName() {
return `4K高清网`
}
getName() {
return `🚄┃4K高清网┃🚄`
}
getJSName() {
return "4kysxz"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
}
async parseVodShortListFromDoc($) {
const cards = $('div.row.posts-wrapper >div > article > div.entry-media > div > a')
return _.map(cards, (n) => {
let id = n.attribs['href'];
let name = $($(n).find('img')[0]).attr('alt').replaceAll('<strong>', '').replaceAll('</strong>', '').split(' ')[0];
let pic = $($(n).find('img')[0]).attr('data-src');
return {
vod_id: id, vod_name: name, vod_pic: pic, vod_remarks: '',
};
});
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let vodElement = $("[class=\"entry-content u-text-format u-clearfix\"]")
let text = "";
for (const vodEle of vodElement) {
text = text + $(vodEle).text().replaceAll("", ":") + "\n"
}
vodDetail.vod_name = $($("[class=\"article-title\"]")).text()
vodDetail.vod_pic = $($("[class=\"entry-content u-text-format u-clearfix\"]")).find("img")[0].attribs["src"]
vodDetail.vod_area = Utils.getStrByRegex(/上映地区(.*?)\n/, text).replaceAll(":", "")
vodDetail.vod_director = Utils.getStrByRegex(/导演(.*?)\n/, text).replaceAll(":", "")
vodDetail.vod_actor = Utils.getStrByRegex(/主演(.*?)\n/, text).replaceAll(":", "")
vodDetail.vod_content = Utils.getStrByRegex(/剧情简介(.*?)\n/, text).replaceAll(":", "").replaceAll("·", "")
let actors = _.map($('div.entry-content.u-text-format.u-clearfix > div:nth-child(10) > div > span > span'), (n) => {
return $(n).text().split(' ')[0];
});
vodDetail.vod_actor = actors.join('/');
let directors = _.map($('div.entry-content.u-text-format.u-clearfix > div:nth-child(6) > div > span'), (n) => {
return $(n).text().split(' ')[0];
});
vodDetail.vod_director = directors.join('/');
vodDetail.vod_name = $('div.site-content > section > div > header > h1').text().trim();
let playUrlStr = '';
let playFromStr = '';
//高清直播
const cards = $('div.entry-content.u-text-format.u-clearfix > custag > ul > li > a');
if (cards.length > 0) {
let playUrls = _.map(cards, (n) => {
let playUrl = n.attribs['href'];
if (playUrl.indexOf('url=') > 0) {
playUrl = playUrl.split('url=')[1].split('&name')[0];
}
return $(n).text() + '$' + playUrl;
});
playUrlStr = playUrls.join('#');
playFromStr = '高清直播';
}
if (!this.catOpenStatus) {
//磁力链接
const tbs = $('loginshow > table');
let playFrom = '';
let nameUrls = [];
for (let i = 0; i < tbs.length; i++) {
if (i % 2 == 0) {
playFrom = $(tbs[i]).find('tbody > tr >td').text().replaceAll('WEB', '磁力');
} else if (i % 2 == 1) {
const tds = $(tbs[i]).find('tbody > tr >td');
let nameUrl = '';
for (let j = 0; j < tds.length; j++) {
if (j % 2 == 0) {
nameUrl = $(tds[j]).text().split('.')[0].split(' ')[0];
} else if (j % 2 == 1) {
nameUrl = nameUrl + '$' + $(tds[j]).text().split('【')[0];
nameUrls.push(nameUrl);
}
}
if (playFromStr.length > 0) {
playFromStr += '$$$';
playUrlStr += '$$$';
}
playFromStr += playFrom;
playUrlStr += nameUrls.join('#');
}
}
}
vodDetail.vod_play_from = playFromStr
vodDetail.vod_play_url = playUrlStr
return vodDetail
}
async setClasses() {
this.classes = []
this.classes.push(this.getTypeDic("首页", "/#"))
}
async getFilter(typeElements) {
let value_list = []
value_list.push({
"n": "全部", "v": "全部",
})
for (const typeElement of typeElements) {
value_list.push({
"n": typeElement.attribs["title"],
"v": typeElement.attribs["href"].split("/").slice(-1)[0].split(".")[0],
})
}
return [{"key": "1", "name": "类型", "value": value_list}]
}
async setFilterObj() {
let $ = await this.getHtml()
let navElements = $("[class=\"navbar-item menu-item-has-children\"]")
let extent_list = []
for (const navElement of navElements) {
let type_name = $($(navElement).find("a")[0]).text()
if (type_name.indexOf("影视") > -1) {
let extend_dic = {"key": "1", "name": type_name, "value": []}
let type_elements = $($(navElement).find("ul")).find("a")
for (const type_element of type_elements) {
extend_dic["value"].push({"n": $(type_element).text(), "v": type_element.attribs["href"]})
}
extent_list.push(extend_dic)
}
}
this.filterObj["/#"] = extent_list
}
async setCategory(tid, pg, filter, extend) {
let url;
if (extend["1"] === undefined) {
url = this.siteUrl + tid
} else {
if (extend["1"].indexOf("category") > -1) {
url = this.siteUrl + extend["1"].split(".")[0] + "_" + pg + ".html"
} else {
url = this.siteUrl + extend["1"]
}
}
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
const $ = await this.getHtml(id);
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setSearch(wd, quick) {
let $ = await this.getHtml(this.siteUrl + '/search.php?q=' + wd)
this.vodList = await this.parseVodShortListFromDoc($)
}
}
let spider = new YSXZSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,299 +0,0 @@
/*
* @Author: samples jadehh@live.com
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples jadehh@live.com
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: js/aiyingshi.js
* @Description: 爱影视爬虫类
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class AiYingShiSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://aiyingshis.com';
}
getName() {
return "🚀‍┃爱影视┃🚀"
}
getAppName() {
return "爱影视"
}
getJSName() {
return "aiyingshi"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let items = $('.module-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
let oneA = $(item).find('.module-item-cover .module-item-pic a').first();
vodShort.vod_id = oneA.attr('href');
vodShort.vod_name = oneA.attr('title');
let pic = $(item).find('.module-item-cover .module-item-pic img').first().attr('data-src')
if (pic.indexOf("img.php?url=") > 0) {
pic = pic.split("img.php?url=")[1]
}else if (pic.indexOf("https:") === -1 && pic.indexOf("http:") === -1){
pic = "https:" + pic
}
vodShort.vod_pic = pic
vodShort.vod_remarks = $(item).find('.module-item-text').first().text();
if (vodShort.vod_name !== undefined){
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
vodDetail.vod_name = $('.page-title')[0].children[0].data
vodDetail.vod_pic = $($("[class=\"video-cover\"]")).find(".lazyload")[0].attribs["data-src"]
let video_info_list = $($(".video-info-aux")).text().replaceAll("\t","").split("\n")
let type_list = []
for (const video_info of video_info_list){
if (!_.isEmpty(video_info.replaceAll(" ","").replaceAll("/",""))){
type_list.push(video_info.replaceAll(" ","").replaceAll("/",""))
}
}
vodDetail.type_name = type_list.slice(0,2).join("*")
let video_items = $("[class=\"video-info-items\"]")
vodDetail.vod_director = $(video_items[0]).find("a")[0].children[0].data
let vidoe_info_actor_list = $(video_items[1]).find("a")
let actor_list = []
for (const vidoe_info_actor of vidoe_info_actor_list) {
actor_list.push(vidoe_info_actor.children[0].data)
}
vodDetail.vod_actor = actor_list.join(" * ")
vodDetail.vod_year = type_list[2]
vodDetail.vod_remarks = $($(video_items[3]).find(".video-info-item")).text()
vodDetail.vod_content = $($(video_items[5]).find(".video-info-item")).text()
vodDetail.vod_area = type_list[3]
vodDetail.vod_content = vodDetail.vod_content.replace("[收起部分]", "").replace("[展开全部]", "").replaceAll("\t","").replaceAll("\n","")
let playElements = $($("[class=\"module-tab-content\"]")[0]).find("span")
let urlElements = $("[class=\"module-list module-player-list tab-list sort-list \"]")
let form_list = []
for (const playerElement of playElements){
form_list.push($(playerElement).text())
}
let play_url_list = []
for (const urlElement of urlElements){
let playUrlElements = $($(urlElement).find("[class=\"sort-item\"]")).find("a")
let vodItems = []
for (const playUrlElement of playUrlElements){
let name = $(playUrlElement).text()
let url = playUrlElement.attribs["href"]
let play_url = name + "$" + url
vodItems.push(play_url)
}
play_url_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = form_list.join('$$$');
vodDetail.vod_play_url = _.values(play_url_list).join('$$$');
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let items = $('.module-search-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
vodShort.vod_id = $(item).find(".video-serial")[0].attribs.href;
vodShort.vod_name = $(item).find(".video-serial")[0].attribs.title;
vodShort.vod_pic = $(item).find(".module-item-pic > img")[0].attribs['data-src']
vodShort.vod_remarks = $($(item).find(".video-serial")[0]).text();
vod_list.push(vodShort);
}
return vod_list
}
async setClasses() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
let elements = $($("[class=\"nav-menu-items\"]")[0]).find("li")
for (const element of elements.slice(0,6)) {
let type_name = $($(element).find("span")).text()
if (type_name !== "首页"){
let type_id = $(element).find("a")[0].attribs["href"].split("/").slice(-1)[0].split(".")[0]
let type_dic = {"type_id": type_id, "type_name": type_name}
this.classes.push(type_dic)
}
}
}
}
async getFilter($) {
let elements = $("[class=\"scroll-content\"]").slice(1)
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": "", "value": []}
if (i < elements.length - 1) {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(elements[i]).find("a").slice(1)) {
if ($($(elements[i]).find("a")[0]).text() === "全部类型"){
extend_dic["value"].push({"n": $(ele).text(), "v":ele.attribs["href"].split("/").slice(-1)[0].split(".")[0]})
}else{
extend_dic["value"].push({"n": $(ele).text(), "v":$(ele).text()})
}
}
extend_list.push(extend_dic)
} else {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"] = [{"n": "全部", "v": "0"}, {
"n": $($(elements[i]).find("a")[1]).text(),
"v": "hits"
}, {"n": $($(elements[i]).find("a")[2]).text(), "v": "score"}]
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "/" && type_id !== "最近更新") {
let url = this.siteUrl + `/vodshow/id/${type_id}.html`
let html = await this.fetch(url, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
}
async setHomeVod() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
getExtend(value,defaultvalue,key = ""){
if (value !== undefined && value !== "0"){
return key + value
}else{
return defaultvalue
}
}
async getCateUrl(tid,pg,extend){
tid = this.getExtend(extend["1"],tid)
let area = this.getExtend(extend["2"],"","/area/")
let lanuage = this.getExtend(extend["3"],"","/lang/")
let year = this.getExtend(extend["4"],"","/year/")
let letter = this.getExtend(extend["5"],"","/letter/")
let time = this.getExtend(extend['6'],"","/by/")
return this.siteUrl + `/vodshow${time}${area}/id/${tid}${lanuage}${letter}${year}/page/${pg}.html`
}
async setCategory(tid, pg, filter, extend) {
let reqUrl = await this.getCateUrl(tid,pg,extend)
let html = await this.fetch(reqUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
let total = Utils.getStrByRegex(/\$\("\.mac_total"\)\.text\('(\d+)'\)/, html)
this.limit = 72;
if (total.length > 0) {
this.total = parseInt(total)
}
if (this.total <= this.limit) {
this.count = 1
} else {
this.count = Math.ceil(this.total / this.limit)
}
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id;
let html = await this.fetch(detailUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setPlay(flag, id, flags) {
let html = await this.fetch(this.siteUrl + id,null,this.getHeader())
if (!_.isEmpty(html)){
let player_str = Utils.getStrByRegex(/<script type="text\/javascript">var player_aaaa=(.*?)<\/script>/,html)
let play_dic = JSON.parse(player_str)
this.playUrl = play_dic["url"]
}
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + `/vodsearch/wd/${wd}.html`
let html = await this.fetch(searchUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
}
let spider = new AiYingShiSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,proxy:proxy
};
}
export {spider}

View File

@ -1,230 +0,0 @@
/*
* @File : alipansou.js
* @Author : jade
* @Date : 2024/1/18 13:20
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 猫狸盘搜
*/
import {_, load} from "../lib/cat.js";
import {Spider} from "./spider.js";
import {detailContent, initAli, playContent} from "../lib/ali.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class GitCafeSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.alipansou.com"
}
getSearchHeader(id) {
let headers = this.getHeader()
headers["Referer"] = id
headers["Postman-Token"] = "5f1bb291-ce30-44c7-8885-6db1f3a50785"
headers["Host"] = "www.alipansou.com"
return headers
}
getName() {
return "😸┃阿里猫狸┃😸"
}
getAppName() {
return "阿里猫狸"
}
getJSName() {
return "alipansou"
}
getType() {
return 3
}
getHeader() {
return {
"User-Agent":Utils.CHROME,
"Connection": "keep-alive",
"Cookie":"mysession=MTcxNTQwNTU3N3xEdi1CQkFFQ180SUFBUkFCRUFBQUxmLUNBQUVHYzNSeWFXNW5EQXdBQ25ObFlYSmphRjlyWlhrR2MzUnlhVzVuREFzQUNlZVVoT1dzbS1TOG9BPT183zSLJi-U9NmKMODipFB6EPuVUbUbmCgYTaJrdiPwsLU="}
}
async getContentHtml() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
return load(html)
}
}
async spiderInit() {
this.content_html = await this.getContentHtml()
}
async init(cfg) {
await this.spiderInit()
await super.init(cfg);
await initAli(this.cfgObj["token"]);
}
async parseClassFromDoc($) {
let tap_elemets = $($("[id=\"app\"]")[0]).find("van-tab")
let index = 0
for (const tap_element of tap_elemets) {
let type_name = tap_element.attribs["title"]
if (type_name.indexOf("热搜") === -1 && type_name !== "游戏" && type_name !== "小说") {
this.classes.push({"type_name": type_name, "type_id": index})
}
index = index + 1
}
}
async parseVodShortListFromDoc(doc) {
let vod_list = []
let elements = this.content_html(doc).find("a")
for (const element of elements) {
let vodShort = new VodShort()
vodShort.vod_id = element.attribs["href"]
vodShort.vod_name = this.content_html(element).text().split(".").slice(-1)[0]
vod_list.push(vodShort)
}
return vod_list
}
async getAliUrl(id) {
let url = this.siteUrl + id.replace("/s/", "/cv/")
let headers = this.getSearchHeader(url)
let content = await req(url,{postType:"get",headers:headers,redirect:2})
await this.jadeLog.debug(`回复内容为:${JSON.stringify(content)}`)
// let url = await this.fetch(this.siteUrl + id.replace("/s/", "/cv/"), null, headers, true)
return content.headers.location
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail();
vodDetail.vod_name = obj["name"]
vodDetail.vod_remarks = obj["remarks"]
let ali_url = await this.getAliUrl(obj["id"])
await this.jadeLog.debug(`阿里分享链接为:${ali_url}`)
if (!_.isEmpty(ali_url)) {
let aliVodDetail = await detailContent([ali_url])
vodDetail.vod_play_url = aliVodDetail.vod_play_url
vodDetail.vod_play_from = aliVodDetail.vod_play_from
}
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let elements = $($($("[id=\"app\"]")[0]).find("van-row")).find("a")
let vod_list = []
for (const element of elements) {
let id = element.attribs["href"]
let matches = id.match(/(\/s\/[^"])/);
if (!_.isEmpty(matches) && id.indexOf("https") === -1) {
let text = $(element).text().replaceAll("\n", "").replaceAll(" ", "")
if (text.indexOf("时间") > -1 && text.indexOf("文件夹") > -1) {
let textList = text.split("时间")
let vodShort = new VodShort()
vodShort.vod_name = textList[0]
vodShort.vod_remarks = textList[1].split("格式")[0].replaceAll(":", "").replaceAll(" ", "").replaceAll("", "").replaceAll(" ", "")
vodShort.vod_id = JSON.stringify({
"name": vodShort.vod_name, "remarks": vodShort.vod_remarks, "id": id
})
vod_list.push(vodShort)
}
}
}
return vod_list
}
async setClasses() {
await this.parseClassFromDoc(this.content_html)
}
async setHomeVod() {
let tap_elemets = this.content_html(this.content_html("[id=\"app\"]")[0]).find("van-tab")
this.homeVodList = await this.parseVodShortListFromDoc(tap_elemets[0])
}
async setDetail(id) {
if (id.indexOf("search") > -1) {
let url = this.siteUrl + "/search"
let params = {"k":decodeURIComponent(id.split("search?k=").slice(-1)[0]) }
let html = await this.fetch(url, params, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
let vod_list = await this.parseVodShortListFromDocBySearch($)
if (vod_list.length > 0) {
id = vod_list[0]["vod_id"]
} else {
id = ""
}
}
}
if (!_.isEmpty(id)) {
let json_content = JSON.parse(id)
this.vodDetail = await this.parseVodDetailfromJson(json_content)
}
}
async setCategory(tid, pg, filter, extend) {
let tap_elemets = this.content_html(this.content_html("[id=\"app\"]")[0]).find("van-tab")
this.vodList = await this.parseVodShortListFromDoc(tap_elemets[parseInt(tid)])
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/search"
let params = {"k": wd}
let html = await this.fetch(url, params, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
async setPlay(flag, id, flags) {
let playObjStr = await playContent(flag, id, flags);
this.playUrl = JSON.parse(playObjStr)["url"]
}
}
let spider = new GitCafeSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,226 +0,0 @@
/*
* @File : aliyunpanshare.js
* @Author : jade
* @Date : 2024/1/26 13:06
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 阿里云盘分享
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import {detailContent, initAli, playContent} from "../lib/ali.js";
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {patternAli} from "../lib/utils.js";
let remark_list = ["4k", "4K"]
class AliyunpanShare extends Spider {
constructor() {
super();
this.siteUrl = 'https://www.alypw.com';
}
async init(cfg) {
await super.init(cfg);
await initAli(this.cfgObj["token"]);
}
getName() {
return "🥏‍┃阿里云盘分享┃🥏‍"
}
getAppName() {
return "阿里云盘分享"
}
getJSName() {
return "aliyunpanshare"
}
getType() {
return 3
}
getRemarks(name, title) {
if (_.isEmpty(name)) {
for (const remark of remark_list) {
if (title.indexOf(remark) > -1) {
return remark
}
}
} else {
return name
}
}
parseVodName(name) {
let vod_name = Utils.getStrByRegex(/\[阿里云盘](.*?) /, name)
if (name.indexOf("合集") > -1) {
return ""
}
if (_.isEmpty(vod_name)) {
vod_name = Utils.getStrByRegex(/\[阿里云盘](.*?)/, name)
}
if (vod_name.indexOf("[") > -1) {
vod_name = vod_name.split("[")[0]
}
if (vod_name.indexOf("【") > -1) {
vod_name = vod_name.split("【")[0]
}
if (vod_name === "4K") {
return ""
}
return vod_name
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $($("[class=\"hometab\"]").find("[class=\"box\"]")).find("li")
for (const vodElement of vodElements) {
let ele = $(vodElement).find("[class=\"imgr\"]")[0]
let vodShort = new VodShort();
vodShort.vod_id = $(ele).find("a")[0].attribs["href"]
let name = $(ele).find("a")[0].attribs["title"]
vodShort.vod_name = this.parseVodName(name)
vodShort.vod_pic = $(vodElement).find("img")[0].attribs["src"]
vodShort.vod_remarks = this.getRemarks(Utils.getStrByRegex(/【(.*?)】/, name), name)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let mainElement = $("[class=\"main container\"]")
let vodElements = $($(mainElement).find("[class=\"list\"]")).find("li")
if (vodElements.length === 0) {
vodElements = $(mainElement).find("li")
}
for (const vodElement of vodElements) {
let name = $(vodElement).find("img")[0].attribs["alt"].replaceAll("<strong>", "").replaceAll("</strong>", "")
let vodShort = new VodShort();
vodShort.vod_id = $(vodElement).find("a")[0].attribs["href"]
vodShort.vod_name = this.parseVodName(name)
vodShort.vod_pic = $(vodElement).find("img")[0].attribs["src"]
vodShort.vod_remarks = this.getRemarks(Utils.getStrByRegex(/【(.*?)】/, name), name)
if (!_.isEmpty(vodShort.vod_name)) {
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailFromDoc($) {
let mainElements = $("[class=\"mainl\"]")
let name = $($(mainElements).find("[class=\"title\"]")[0]).text()
let vodDetail = new VodDetail();
vodDetail.vod_name = Utils.getStrByRegex(/\[阿里云盘](.*?) /, name)
vodDetail.vod_remarks = this.getRemarks(Utils.getStrByRegex(/【(.*?)】/, name), name)
let articleElement = $(mainElements).find("[class=\"article_content\"]")
vodDetail.vod_pic = $(articleElement).find("p>img")[0].attribs["src"]
let articleElements = $(articleElement).find("p")
let articleContent = ""
for (const articleEle of articleElements) {
articleContent = articleContent + $(articleEle).text() + "\n"
}
let share_ali_url_list = []
let share_url_list = Utils.getStrByRegex(Utils.patternAli, articleContent).split("\n")
for (const share_url of share_url_list) {
let matches = share_url.match(Utils.patternAli);
if (!_.isEmpty(matches)) share_ali_url_list.push(matches[1])
}
let aliVodDetail = await detailContent(share_ali_url_list)
vodDetail.vod_play_url = aliVodDetail.vod_play_url
vodDetail.vod_play_from = aliVodDetail.vod_play_from
vodDetail.type_name = Utils.getStrByRegex(/标签(.*?)\n/, articleContent).replaceAll("", "")
vodDetail.vod_content = Utils.getStrByRegex(/描述(.*?)\n/, articleContent).replaceAll("", "")
return vodDetail
}
async setClasses() {
let $ = await this.getHtml()
let typeElements = $("[id^='navbar-category']").find("a")
let key_list = ["影", "剧", "4K", "视", "音", "演", "动漫"]
for (const typeElement of typeElements) {
let type_name = $(typeElement).text()
let type_id = typeElement.attribs["href"]
let is_show = false
for (const key of key_list) {
if (type_name.indexOf(key) > -1) {
is_show = true
}
}
if (is_show) {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let cateUrl = tid.split(".html")[0] + "_" + pg + ".html"
let $ = await this.getHtml(cateUrl)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setPlay(flag, id, flags) {
let playObjStr = await playContent(flag, id, flags);
this.playUrl = JSON.parse(playObjStr)["url"]
}
async setSearch(wd, quick) {
let url = this.siteUrl + `/search.php?q=${wd}`
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
}
let spider = new AliyunpanShare()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,183 +0,0 @@
/*
* @Author: samples jadehh@live.com
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples jadehh@live.com
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: js/asianx.js
* @Description: asianx
*/
import {Spider} from "./spider.js";
import {Crypto, _, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class AsianXSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://cn.asianx.tube/"
}
getName() {
return "🔞┃海外宅┃🔞"
}
getAppName() {
return "海外宅"
}
getJSName() {
return "asianx"
}
getType() {
return 3
}
async getFilter($) {
let navElements = $($("[class=\"menu m-0 mb-2 mb-lg-0\"]")).find("a").slice(6)
let extend_dic = {"key": "1", "name": "分类", "value": [{"n": "全部", "v": "全部"}]}
for (const navElement of navElements) {
let type_name = $($(navElement).find("span")).text()
let type_id = navElement.attribs["href"]
extend_dic["value"].push({"n": type_name, "v": type_id})
}
return [extend_dic]
}
async parseVodShortListFromDoc($,is_home=false) {
let vod_list = []
let vodShortElements;
if (is_home){
vodShortElements = $($("[class=\"gal-box\"]")).slice(12)
}else{
vodShortElements = $($("[class=\"gal-box\"]"))
}
for (const vodShortElement of vodShortElements) {
let vodShort = new VodShort()
let vodElements = $(vodShortElement).find("a")
vodShort.vod_id = vodElements[0].attribs["href"]
vodShort.vod_pic = $(vodElements[0]).find("img")[0].attribs["data-src"]
vodShort.vod_name = vodElements[1].attribs["title"]
vodShort.vod_remarks = $($(vodShortElement).find("[class=\"meta text-muted text-truncate\"]")).text()
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc(html) {
let vodDetail = new VodDetail();
let content = Utils.getStrByRegex(/<script type="application\/ld\+json">(.*?)<\/script>/,html)
let content_json = JSON.parse(content)
let textList = content_json["name"].split(" ")
vodDetail.vod_name = textList[0]
vodDetail.vod_play_from = ["未加密线路","加密线路"].join("$$$")
let playUrl1 = content_json["contentUrl"]
let playUrl2 = content_json["embedUrl"]
vodDetail.vod_play_url = [`${textList[0]}$${playUrl1}`,`${textList[0]}$${playUrl2}`].join("$$$")
vodDetail.vod_remarks = content_json["uploadDate"]
vodDetail.vod_content = content_json["description"]
return vodDetail
}
async setClasses() {
this.classes = []
this.classes.push({"type_name": "首页", "type_id": "/"})
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
let navElements = $($("[class=\"menu m-0 mb-2 mb-lg-0\"]")).find("a").slice(0, 5)
for (const navElement of navElements) {
let type_name = $($(navElement).find("span")).text()
let type_id = navElement.attribs["href"]
this.classes.push({"type_name": type_name, "type_id": type_id})
}
this.filterObj[this.classes[0].type_id] = await this.getFilter($)
}
}
async setHomeVod() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.homeVodList = await this.parseVodShortListFromDoc($,true)
}
}
getExtend(pg,extend){
if (extend["1"] !== undefined){
if (extend["1"] === "全部"){
return this.siteUrl
}else{
return this.siteUrl + extend["1"] + "/" + pg
}
}else{
return this.siteUrl
}
}
async setDetail(id) {
let html = await this.fetch(id,null,this.getHeader())
if (!_.isEmpty(html)){
this.vodDetail = await this.parseVodDetailFromDoc(html)
}
}
async setCategory(tid, pg, filter, extend) {
let url;
if (tid === "/") {
url = this.getExtend(pg,extend)
} else {
url = this.siteUrl + tid + "/" + pg
}
let html = await this.fetch(url, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($,false)
}
}
}
let spider = new AsianXSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
};
}
export {spider}

View File

@ -1,258 +0,0 @@
/*
* @File : audiomack.js
* @Author : jade
* @Date : 2024/1/31 15:56
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 音乐之声
*/
import {Spider} from "./spider.js";
import {BookShort} from "../lib/book.js";
import {Crypto} from "../lib/cat.js";
function u(e) {
(this._parameters = {}), this._loadParameters(e || {});
}
u.prototype = {
_loadParameters: function (e) {
e instanceof Array ? this._loadParametersFromArray(e) : "object" == typeof e && this._loadParametersFromObject(e);
}, _loadParametersFromArray: function (e) {
var n;
for (n = 0; n < e.length; n++) this._loadParametersFromObject(e[n]);
}, _loadParametersFromObject: function (e) {
var n;
for (n in e) if (e.hasOwnProperty(n)) {
var r = this._getStringFromParameter(e[n]);
this._loadParameterValue(n, r);
}
}, _loadParameterValue: function (e, n) {
var r;
if (n instanceof Array) {
for (r = 0; r < n.length; r++) {
var i = this._getStringFromParameter(n[r]);
this._addParameter(e, i);
}
0 == n.length && this._addParameter(e, "");
} else this._addParameter(e, n);
}, _getStringFromParameter: function (e) {
var n = e || "";
try {
("number" == typeof e || "boolean" == typeof e) && (n = e.toString());
} catch (e) {
}
return n;
}, _addParameter: function (e, n) {
this._parameters[e] || (this._parameters[e] = []), this._parameters[e].push(n);
}, get: function () {
return this._parameters;
},
};
function _decode(e) {
return e ? decodeURIComponent(e) : "";
}
function getNormalizedParams(parameters) {
const sortedKeys = [];
const normalizedParameters = [];
for (let e in parameters) {
sortedKeys.push(_encode(e));
}
sortedKeys.sort();
for (let idx = 0; idx < sortedKeys.length; idx++) {
const e = sortedKeys[idx];
var n, r, i = _decode(e), a = parameters[i];
for (a.sort(), n = 0; n < a.length; n++) (r = _encode(a[n])), normalizedParameters.push(e + "=" + r);
}
return normalizedParameters.join("&");
}
function nonce(e = 10) {
let n = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", r = "";
for (let i = 0; i < e; i++) r += n.charAt(Math.floor(Math.random() * n.length));
return r;
}
function _encode(e) {
return e ? encodeURIComponent(e)
.replace(/[!'()]/g, escape)
.replace(/\*/g, "%2A") : "";
}
function getSignature(method, urlPath, params, secret = "f3ac5b086f3eab260520d8e3049561e6") {
urlPath = urlPath.split("?")[0];
urlPath = urlPath.startsWith("http") ? urlPath : "https://api.audiomack.com/v1" + urlPath;
const r = new u(params).get();
const httpMethod = method.toUpperCase();
const normdParams = getNormalizedParams(r);
const l = _encode(httpMethod) + "&" + _encode(urlPath) + "&" + _encode(normdParams);
return Crypto.HmacSHA1(l, secret + "&").toString(Crypto.enc.Base64);
}
class AudioMackSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.audiomack.com/v1";
}
getName() {
return "🎵┃音声┃🎵"
}
getAppName() {
return "音声"
}
getJSName() {
return "audiomack"
}
getType() {
return 10
}
async parseVodShortListFromJson(obj) {
let books = []
for (const data of obj["results"]["playlists"]) {
let bookShort = new BookShort()
bookShort.book_id = data["id"]
bookShort.book_pic = data["image"]
bookShort.book_name = data["title"]
bookShort.book_remarks = data["description"]
books.push(bookShort)
}
return books
}
async setClasses() {
this.classes = [{"type_name": "推荐榜单", "type_id": "最近更新"}]
const genres = [{
title: "All Genres", url_slug: "null",
}, {
title: "Afrosounds", url_slug: "afrobeats",
}, {
title: "Hip-Hop/Rap", url_slug: "rap",
}, {
title: "Latin", url_slug: "latin",
}, {
title: "Caribbean", url_slug: "caribbean",
}, {
title: "Pop", url_slug: "pop",
}, {
title: "R&B", url_slug: "rb",
}, {
title: "Gospel", url_slug: "gospel",
}, {
title: "Electronic", url_slug: "electronic",
}, {
title: "Rock", url_slug: "rock",
}, {
title: "Punjabi", url_slug: "punjabi",
}, {
title: "Country", url_slug: "country",
}, {
title: "Instrumental", url_slug: "instrumental",
}, {
title: "Podcast", url_slug: "podcast",
},];
for (const genre of genres) {
this.classes.push(this.getTypeDic(genre["title"], genre["url_slug"]))
}
}
/*
* */
async setHomeVod() {
let tag = {id: "34", title: "What's New", url_slug: "whats-new"};
const params = {
featured: "yes",
limit: 20,
oauth_consumer_key: "audiomack-js",
oauth_nonce: nonce(32),
oauth_signature_method: "HMAC-SHA1",
oauth_timestamp: Math.round(Date.now() / 1e3),
oauth_version: "1.0",
page: 1,
slug: tag.url_slug,
};
const oauth_signature = getSignature("GET", "/playlist/categories", params);
let url = this.siteUrl + "/playlist/categories"
let content = await this.fetch(url, Object.assign(Object.assign({}, params), {oauth_signature}), this.getHeader());
this.homeVodList = await this.parseVodShortListFromJson(JSON.parse(content))
}
async setCategory(tid, pg, filter, extend) {
let partialUrl;
if (tid === "null"){
partialUrl = `/music/page/${pg}`;
}else{
partialUrl = `/music/${tid}/page/${pg}`;
}
const url = `https://api.audiomack.com/v1${partialUrl}`;
const params = {
oauth_consumer_key: "audiomack-js",
oauth_nonce: nonce(32),
oauth_signature_method: "HMAC-SHA1",
oauth_timestamp: Math.round(Date.now() / 1e3),
oauth_version: "1.0",
type: "song",
};
const oauth_signature = getSignature("GET", partialUrl, params);
const results = await this.fetch(url, Object.assign(Object.assign({}, params), {oauth_signature}),this.getHeader())
let x = 0
}
}
let spider = new AudioMackSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,85 +0,0 @@
/*
* @File : base_spider.js.js
* @Author : jade
* @Date : 2024/1/4 14:13
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {JadeLogging} from "../lib/log.js";
import {Result, SpiderInit} from "../lib/spider_object.js";
const JadeLog = new JadeLogging(getAppName(), "DEBUG")
let result = new Result()
let CatOpenStatus = false
function getName() {
return `🍥┃基础┃🍥`
}
function getAppName() {
return `基础`
}
async function init(cfg) {
let obj = await SpiderInit(cfg)
CatOpenStatus = obj.CatOpenStatus
// 读取缓存
}
async function home(filter) {
await JadeLog.info("正在解析首页类别", true)
try{
await JadeLog.debug(`首页类别内容为:${result.home()}`)
await JadeLog.info("首页类别解析完成", true)
return result.homeVod()
}catch (e){
await this.jadeLog.error(`首页内容解析失败,失败原因为:{e}`)
}
}
async function homeVod() {
let vod_list = []
if (!CatOpenStatus) {
await JadeLog.info("正在解析首页内容")
}
await JadeLog.debug(`首页内容为:${JSON.stringify({"list": vod_list})}`)
return JSON.stringify({"list": vod_list})
}
async function category(tid, pg, filter, extend) {
let url = ""
await JadeLog.info(`正在解析分类页面,tid = ${tid},pg = ${pg},filter = ${filter},extend = ${JSON.stringify(extend)},url = ${url}`)
}
async function detail(id) {
return JSON.stringify({})
}
async function play(flag, id, flags) {
return JSON.stringify({});
}
async function search(wd, quick) {
let url = ""
await JadeLog.info(`正在解析搜索页面,关键词为 = ${wd},quick = ${quick},url = ${url}`)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
};
}

View File

@ -1,571 +0,0 @@
/*
* @File : bilibili.js
* @Author : jade
* @Date : 2024/4/3 9:27
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 哔哩哔哩
*/
import {Spider} from "./spider.js";
import * as Utils from "../lib/utils.js";
import {Crypto, _, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
class BilibiliSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.bilibili.com"
this.apiUrl = "https://api.bilibili.com"
this.cookie = ""
this.bili_jct = '';
this.is_login = false
this.is_vip = false
this.vod_audio_id = {
30280: 192000,
30232: 132000,
30216: 64000,
};
this.vod_codec = {
// 13: 'AV1',
12: 'HEVC',
7: 'AVC',
};
this.play_url_obj = {
80: "1080P 高清",
64: "720P 高清",
32: "420P 清晰",
16: "360P 流畅"
}
}
getHeader() {
const headers = super.getHeader();
if (!_.isEmpty(this.cookie)) {
headers["cookie"] = this.cookie;
}
return headers;
}
initCookie(cookie) {
this.cookie = cookie
if (cookie.includes('bili_jct')) {
this.bili_jct = cookie.split('bili_jct=')[1].split(";")[0];
}
}
async spiderInit(Req) {
this.is_login = await this.checkLogin()
if (this.is_login) {
await this.jadeLog.info("哔哩哔哩登录成功", true)
} else {
await this.jadeLog.error("哔哩哔哩登录失败", true)
}
if (Req === null) {
// dash mpd 代理
this.js2Base = await js2Proxy(true, this.siteType, this.siteKey, 'dash/', this.getHeader());
} else {
this.js2Base = await js2Proxy(Req, "dash", this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.initCookie(this.cfgObj["cookie"])
await this.spiderInit(null)
this.danmuStaus = true
}
getName() {
return "🏰┃哔哩哔哩┃🏰"
}
getAppName() {
return "哔哩哔哩"
}
getJSName() {
return "bilibili"
}
getType() {
return 3
}
async setClasses() {
let $ = await this.getHtml(this.siteUrl)
let navElements = $("[class=\"channel-items__left\"]").find("a")
for (const navElement of navElements) {
this.classes.push(this.getTypeDic($(navElement).text(), $(navElement).text()))
}
if (!_.isEmpty(this.bili_jct) && this.is_login) {
this.classes.push(this.getTypeDic("历史记录", "历史记录"))
}
}
async getFilter($) {
return [
{
key: 'order',
name: '排序',
value: [
{n: '综合排序', v: '0'},
{n: '最多点击', v: 'click'},
{n: '最新发布', v: 'pubdate'},
{n: '最多弹幕', v: 'dm'},
{n: '最多收藏', v: 'stow'},
],
},
{
key: 'duration',
name: '时长',
value: [
{n: '全部时长', v: '0'},
{n: '60分钟以上', v: '4'},
{n: '30~60分钟', v: '3'},
{n: '10~30分钟', v: '2'},
{n: '10分钟以下', v: '1'},
],
},
];
}
async setFilterObj() {
for (const typeDic of this.classes) {
let type_id = typeDic["type_name"]
if (type_id !== "最近更新" && type_id !== "历史记录") {
this.filterObj[type_id] = await this.getFilter()
}
}
}
getFullTime(numberSec) {
let totalSeconds = '';
try {
let timeParts = numberSec.split(":");
let min = parseInt(timeParts[0]);
let sec = parseInt(timeParts[1]);
totalSeconds = min * 60 + sec;
} catch (e) {
totalSeconds = parseInt(numberSec);
}
if (isNaN(totalSeconds)) {
return '无效输入';
}
if (totalSeconds >= 3600) {
const hours = Math.floor(totalSeconds / 3600);
const remainingSecondsAfterHours = totalSeconds % 3600;
const minutes = Math.floor(remainingSecondsAfterHours / 60);
const seconds = remainingSecondsAfterHours % 60;
return `${hours}小时 ${minutes}分钟 ${seconds}`;
} else {
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
return `${minutes}分钟 ${seconds}`;
}
}
removeTags(input) {
return input.replace(/<[^>]*>/g, '');
}
async parseVodShortListFromJson(objList) {
let vod_list = []
for (const vodData of objList) {
let vodShort = new VodShort()
vodShort.vod_id = vodData["bvid"]
if (vodData.hasOwnProperty("rcmd_reason")) {
vodShort.vod_remarks = vodData["rcmd_reason"]["content"]
} else {
vodShort.vod_remarks = this.getFullTime(vodData["duration"])
}
vodShort.vod_name = this.removeTags(vodData["title"])
let imageUrl = vodData["pic"];
if (imageUrl.startsWith('//')) {
imageUrl = 'https:' + imageUrl;
}
vodShort.vod_pic = imageUrl
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailfromJson(obj, bvid) {
let cd = this.getFullTime(obj["duration"]);
const aid = obj.aid;
let vodDetail = new VodDetail()
vodDetail.vod_name = obj["title"]
vodDetail.vod_pic = obj["pic"]
vodDetail.type_name = obj["tname"]
vodDetail.vod_remarks = cd
vodDetail.vod_content = obj["desc"]
let params = {"avid": aid, "cid": obj["cid"], "qn": "127", "fnval": 4048, "fourk": 1}
let playUrlDatas = JSON.parse(await this.fetch(this.apiUrl + "/x/player/playurl", params, this.getHeader()));
let playUrldDataList = playUrlDatas["data"];
const accept_quality = playUrldDataList["accept_quality"];
const accept_description = playUrldDataList["accept_description"];
const qualityList = [];
const descriptionList = [];
for (let i = 0; i < accept_quality.length; i++) {
if (!this.is_vip) {
if (this.is_login) {
if (accept_quality[i] > 80) continue;
} else {
if (accept_quality[i] > 32) continue;
}
}
descriptionList.push(Utils.base64Encode(accept_description[i]));
qualityList.push(accept_quality[i]);
}
let treeMap = {};
const jSONArray = obj["pages"];
let playList = [];
for (let j = 0; j < jSONArray.length; j++) {
const jSONObject6 = jSONArray[j];
const cid = jSONObject6.cid;
const playUrl = j + '$' + aid + '+' + cid + '+' + qualityList.join(':') + '+' + descriptionList.join(':');
playList.push(playUrl);
}
if (this.catOpenStatus) {
for (let quality of qualityList) {
treeMap[`dash - ${this.play_url_obj[quality]}`] = playList.join("#")
}
} else {
await this.jadeLog.warning("TV暂不支持Dash播放")
}
for (let quality of qualityList) {
treeMap[`mp4 - ${this.play_url_obj[quality]}`] = playList.join("#")
}
let relatedParams = {"bvid": bvid}
const relatedData = JSON.parse(await this.fetch(this.apiUrl + "/x/web-interface/archive/related", relatedParams, this.getHeader())).data;
playList = [];
for (let j = 0; j < relatedData.length; j++) {
const jSONObject6 = relatedData[j];
const cid = jSONObject6.cid;
const title = jSONObject6.title;
const aaid = jSONObject6.aid;
const playUrl = title + '$' + aaid + '+' + cid + '+' + qualityList.join(':') + '+' + descriptionList.join(':');
playList.push(playUrl);
}
if (this.catOpenStatus) {
for (let quality of qualityList) {
treeMap["相关" + ` - ${this.play_url_obj[quality]}`] = playList.join("#")
}
} else {
await this.jadeLog.warning("TV暂不支持相关播放")
}
vodDetail.vod_play_from = Object.keys(treeMap).join("$$$");
vodDetail.vod_play_url = Object.values(treeMap).join("$$$");
return vodDetail
}
async setHomeVod() {
let params = {"ps": 20}
let content = await this.fetch(this.apiUrl + "/x/web-interface/popular", params, this.getHeader())
this.homeVodList = await this.parseVodShortListFromJson(JSON.parse(content)["data"]["list"])
}
async setDetail(id) {
const detailUrl = this.apiUrl + "/x/web-interface/view";
let params = {"bvid": id}
const detailData = JSON.parse(await this.fetch(detailUrl, params, this.getHeader())).data
// 记录历史
if (!_.isEmpty(this.bili_jct)) {
const historyReport = this.apiUrl + '/x/v2/history/report';
let dataPost = {
aid: detailData.aid,
cid: detailData.cid,
csrf: this.bili_jct,
}
await this.post(historyReport, dataPost, this.getHeader(), "form");
}
this.vodDetail = await this.parseVodDetailfromJson(detailData, id)
}
findKeyByValue(obj, value) {
for (const key in obj) {
if (obj[key] === value) {
return key;
}
}
return null;
}
async setPlay(flag, id, flags) {
const ids = id.split('+');
const aid = ids[0];
const cid = ids[1];
let quality_name = flag.split(" - ")[1]
let quality_id = this.findKeyByValue(this.play_url_obj, quality_name)
this.danmuUrl = this.apiUrl + '/x/v1/dm/list.so?oid=' + cid;
this.result.header = this.getHeader()
if (flag.indexOf("dash") > -1 || flag.indexOf('相关') > -1) {
// dash mpd 代理
if (this.catOpenStatus) {
this.playUrl = this.js2Base + Utils.base64Encode(aid + '+' + cid + '+' + quality_id)
}
} else if (flag.indexOf('mp4') > -1) {
// 直链
const url = this.apiUrl + `/x/player/playurl`;
let params = {"avid": aid, "cid": cid, "qn": parseInt(quality_id), "fourk": "1"}
const resp = JSON.parse(await this.fetch(url, params, this.getHeader()));
const data = resp.data;
this.playUrl = data["durl"][0].url;
} else {
// 音频外挂
let urls = [];
let audios = [];
const url = this.siteUrl + "/x/player/playurl"
let params = {"avid": aid, "cid": cid, "qn": quality_id, "fnval": 4048, "fourk": 1};
let resp = JSON.parse(await this.fetch(url, params, this.getHeader()));
const dash = resp.data.dash;
const video = dash.video;
const audio = dash.audio;
for (let j = 0; j < video.length; j++) {
const dashjson = video[j];
if (dashjson.id === quality_id) {
for (const key in this.vod_codec) {
if (dashjson["codecid"] === key) {
urls.push(Utils.base64Decode(quality_id) + ' ' + this.vod_codec[key], dashjson["baseUrl"]);
}
}
}
}
if (audios.length === 0) {
for (let j = 0; j < audio.length; j++) {
const dashjson = audio[j];
for (const key in this.vod_audio_id) {
if (dashjson.id === key) {
audios.push({
title: _.floor(parseInt(this.vod_audio_id[key]) / 1024) + 'Kbps',
bit: this.vod_audio_id[key],
url: dashjson["baseUrl"],
});
}
}
}
audios = _.sortBy(audios, 'bit');
}
this.playUrl = urls
this.extra = {"audio": audios}
}
}
async checkLogin() {
let result = JSON.parse(await this.fetch('https://api.bilibili.com/x/web-interface/nav', null, this.getHeader()));
this.is_vip = result["data"]["vipStatus"]
return result["data"]["isLogin"]
}
async setCategory(tid, pg, filter, extend) {
let page;
if (parseInt(pg) < 1) {
page = 1;
} else {
page = parseInt(pg)
}
if (Object.keys(extend).length > 0 && extend.hasOwnProperty('tid') && extend['tid'].length > 0) {
tid = extend['tid'];
}
let url = '';
url = this.apiUrl + `/x/web-interface/search/type?search_type=video&keyword=${encodeURIComponent(tid)}`;
if (Object.keys(extend).length > 0) {
for (const k in extend) {
if (k === 'tid') {
continue;
}
url += `&${encodeURIComponent(k)}=${encodeURIComponent(extend[k])}`;
}
}
url += `&page=${encodeURIComponent(page)}`;
if (tid === "历史记录") {
url = this.apiUrl + "/x/v2/history?pn=" + page;
}
const data = JSON.parse(await this.fetch(url, null, this.getHeader())).data;
let items = data.result;
if (tid === "历史记录") {
items = data;
}
this.vodList = await this.parseVodShortListFromJson(items)
}
async setSearch(wd, quick, pg) {
const ext = {
duration: '0',
};
let page = parseInt(pg)
const limit = 20
let resp = JSON.parse(await this.category(wd, page, true, ext));
this.vodList = resp["list"]
let pageCount = page;
if (this.vodList.length === limit) {
pageCount = page + 1;
}
this.result.setPage(page, pageCount, limit, pageCount)
}
getDashMedia(dash) {
try {
let qnid = dash.id;
const codecid = dash["codecid"];
const media_codecs = dash["codecs"];
const media_bandwidth = dash["bandwidth"];
const media_startWithSAP = dash["startWithSap"];
const media_mimeType = dash.mimeType;
const media_BaseURL = dash["baseUrl"].replace(/&/g, '&amp;');
const media_SegmentBase_indexRange = dash["SegmentBase"]["indexRange"];
const media_SegmentBase_Initialization = dash["SegmentBase"]["Initialization"];
const mediaType = media_mimeType.split('/')[0];
let media_type_params = '';
if (mediaType === 'video') {
const media_frameRate = dash.frameRate;
const media_sar = dash["sar"];
const media_width = dash.width;
const media_height = dash.height;
media_type_params = `height='${media_height}' width='${media_width}' frameRate='${media_frameRate}' sar='${media_sar}'`;
} else if (mediaType === 'audio') {
for (const key in this.vod_audio_id) {
if (qnid === key) {
const audioSamplingRate = this.vod_audio_id[key];
media_type_params = `numChannels='2' sampleRate='${audioSamplingRate}'`;
}
}
}
qnid += '_' + codecid;
return `<AdaptationSet lang="chi">
<ContentComponent contentType="${mediaType}"/>
<Representation id="${qnid}" bandwidth="${media_bandwidth}" codecs="${media_codecs}" mimeType="${media_mimeType}" ${media_type_params} startWithSAP="${media_startWithSAP}">
<BaseURL>${media_BaseURL}</BaseURL>
<SegmentBase indexRange="${media_SegmentBase_indexRange}">
<Initialization range="${media_SegmentBase_Initialization}"/>
</SegmentBase>
</Representation>
</AdaptationSet>`;
} catch (e) {
// Handle exceptions here
}
}
getDash(ja, videoList, audioList) {
const duration = ja.data.dash["duration"];
const minBufferTime = ja.data.dash["minBufferTime"];
return `<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mpeg:dash:schema:mpd:2011" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" type="static" mediaPresentationDuration="PT${duration}S" minBufferTime="PT${minBufferTime}S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">
<Period duration="PT${duration}S" start="PT0S">
${videoList}
${audioList}
</Period>
</MPD>`;
}
async proxy(segments, headers) {
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'dash') {
const ids = url.split('+');
const aid = ids[0];
const cid = ids[1];
const str5 = ids[2];
const urls = this.apiUrl + `/x/player/playurl?avid=${aid}&cid=${cid}&qn=${str5}&fnval=4048&fourk=1`;
let videoList = '';
let audioList = '';
let content = await this.fetch(urls, null, headers);
let resp = JSON.parse(content)
const dash = resp.data.dash;
const video = dash.video;
const audio = dash.audio;
for (let i = 0; i < video.length; i++) {
// if (i > 0) continue; // 只取一个
const dashjson = video[i];
if (dashjson.id.toString() === str5) {
videoList += this.getDashMedia(dashjson);
}
}
for (let i = 0; i < audio.length; i++) {
// if (i > 0) continue;
const ajson = audio[i];
for (const key in this.vod_audio_id) {
if (ajson.id.toString() === key) {
audioList += this.getDashMedia(ajson);
}
}
}
let mpd = this.getDash(resp, videoList, audioList);
return JSON.stringify({
code: 200,
content: mpd,
headers: {
'Content-Type': 'application/dash+xml',
},
});
}
return JSON.stringify({
code: 500,
content: '',
});
}
}
let spider = new BilibiliSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,152 +0,0 @@
/*
* @File : bookan.js
* @Author : jade
* @Date : 2024/1/31 13:44
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_} from '../lib/cat.js';
import {Spider} from "./spider.js";
function formatPlayUrl(name) {
return name
.trim()
.replace(/<|>|《|》/g, '')
.replace(/\$|#/g, ' ')
.trim();
}
class BooKanSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.bookan.com.cn";
}
getName() {
return "🎵┃看书┃🎵"
}
getAppName() {
return "看书"
}
getJSName() {
return "bookan"
}
getType() {
return 10
}
async parseVodShortListFromJson(obj) {
let books = [];
for (const book of obj.list) {
books.push({
book_id: book.id, book_name: book.name, book_pic: book.cover, book_remarks: book.extra.author,
});
}
return books
}
async setClasses() {
{
this.classes = [{type_id: '1305', type_name: '少年读物'}, {
type_id: '1304', type_name: '儿童文学'
}, {type_id: '1320', type_name: '国学经典'}, {type_id: '1306', type_name: '文艺少年'}, {
type_id: '1309', type_name: '育儿心经'
}, {type_id: '1310', type_name: '心理哲学'}, {type_id: '1307', type_name: '青春励志'}, {
type_id: '1312', type_name: '历史小说'
}, {type_id: '1303', type_name: '故事会'}, {type_id: '1317', type_name: '音乐戏剧'}, {
type_id: '1319', type_name: '相声评书'
},]
}
}
async setCategory(tid, pg, filter, extend) {
let content = await this.fetch(`${this.siteUrl}/voice/book/list?instance_id=25304&page=${pg}&category_id=${tid}&num=24`, null, this.getHeader());
let data = JSON.parse(content).data;
this.vodList = await this.parseVodShortListFromJson(data)
}
async parseVodDetailfromJson(obj) {
let book = {
audio: 1,
type_name: '',
book_year: '',
book_area: '',
book_remarks: '',
book_actor: '',
book_director: '',
book_content: '',
};
let us = _.map(obj.list, function (b) {
return formatPlayUrl(b.title) + '$' + b.file;
}).join('#');
book.volumes = '书卷';
book.urls = us;
return book
}
async setDetail(id) {
let content = await this.fetch(`${this.siteUrl}/voice/album/units?album_id=${id}&page=1&num=200&order=1`, null, this.getHeader());
let data = JSON.parse(content).data;
this.vodDetail = await this.parseVodDetailfromJson(data)
this.vodDetail.book_id = id
}
async play(flag, id, flags) {
return JSON.stringify({
parse: 0, url: id,
});
}
async setSearch(wd, quick) {
let content = await this.fetch(`https://es.bookan.com.cn/api/v3/voice/book?instanceId=25304&keyword=${wd}&pageNum=1&limitNum=20`,null,this.getHeader());
let data = JSON.parse(content).data;
this.vodList = await this.parseVodShortListFromJson(data)
}
}
let spider = new BooKanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
};
}
export {spider}

View File

@ -1,268 +0,0 @@
/*
* @File : bqg_open.js.js
* @Author : jade
* @Date : 2024/1/30 15:38
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_} from '../lib/cat.js';
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {BookDetail, BookShort} from "../lib/book.js";
class BQQSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://m.13bqg.com"
}
getAppName() {
return "笔趣阁"
}
getJSName() {
return "bqg_open"
}
getType() {
return 10
}
getName() {
return "📚︎┃笔趣阁┃📚︎"
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
async parseVodShortListFromDoc($) {
let books = []
let bookElements = $("[class=\"block\"]")
for (const bookElement of $(bookElements[0]).find("li")) {
let bookShort = new BookShort()
let bookShortElements = $(bookElement).find("span")
bookShort.book_remarks = $(bookShortElements[0]).text()
bookShort.book_name = $(bookShortElements[1]).text()
bookShort.book_id = $(bookShortElements[1]).find("a")[0].attribs.href
bookShort.book_pic = this.jsBase + Utils.base64Encode(bookShort.book_id)
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocByCategory($) {
let books = [];
for (const item of $('div.item')) {
let bookShort = new BookShort()
bookShort.book_id = $(item).find('a:first')[0].attribs.href;
const img = $(item).find('img:first')[0];
bookShort.book_name = img.attribs.alt
bookShort.book_pic = img.attribs.src
bookShort.book_remarks = $(item).find('span:first')[0].children[0].data.trim();
books.push(bookShort)
}
return books
}
async parseVodDetailFromDoc($, id) {
let bookDetail = new BookDetail()
bookDetail.book_name = $('[property$=book_name]')[0].attribs.content
bookDetail.book_year = $('[property$=update_time]')[0].attribs.content
bookDetail.book_director = $('[property$=author]')[0].attribs.content
bookDetail.book_content = $('[property$=description]')[0].attribs.content
bookDetail.book_pic = $($("[class=\"cover\"]")).find("img")[0].attribs.src
bookDetail.book_id = id
let playBook = {}
if (id !== undefined) {
$ = await this.getHtml(this.siteUrl + id + `list.html`);
let urls = [];
const links = $('dl>dd>a[href*="/html/"]');
for (const l of links) {
const name = $(l).text().trim();
const link = l.attribs.href;
urls.push(name + '$' + link);
}
playBook["最新章节"] = urls.slice(-10).join('#');
playBook["目录"] = urls.join('#');
}
bookDetail.volumes = _.keys(playBook).join('$$$');
bookDetail.urls = _.values(playBook).join('$$$');
return bookDetail
}
async setClasses() {
let $ = await this.getHtml()
for (const a of $('div.nav > ul > li > a[href!="/"]')) {
this.classes.push({
type_id: a.attribs.href.replace(/\//g, ''), type_name: a.children[0].data.trim(), tline: 2,
});
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($, id)
}
async setCategory(tid, pg, filter, extend) {
let $ = await this.getHtml(this.siteUrl + `/${tid}/${pg}.html`);
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setPlay(flag, id, flags) {
try {
let content = '';
while (true) {
let $ = await this.getHtml(this.siteUrl + id)
content += $('#chaptercontent')
.html()
.replace(/<br>|请收藏.*?<\/p>/g, '\n')
.trim();
id = $('a.Readpage_down')[0].attribs.href;
if (id.indexOf('_') < 0) break;
}
this.playUrl = {"content":content + '\n\n'}
} catch (e) {
this.playUrl = {"content":""}
}
}
async search(wd, quick) {
const cook = await req(`${this.siteUrl}/user/hm.html?q=${encodeURIComponent(wd)}`, {
headers: {
accept: 'application/json',
'User-Agent': Utils.MOBILEUA,
Referer: `${this.siteUrl}/s?q=${encodeURIComponent(wd)}`,
},
});
const set_cookie = _.isArray(cook.headers['set-cookie']) ? cook.headers['set-cookie'].join(';;;') : cook.headers['set-cookie'];
const cks = set_cookie.split(';;;');
const cookie = {};
for (const c of cks) {
const tmp = c.trim();
const idx = tmp.indexOf('=');
const k = tmp.substr(0, idx);
cookie[k] = tmp.substr(idx + 1, tmp.indexOf(';') - idx - 1);
}
const resp = await req(`${this.siteUrl}/user/search.html?q=${encodeURIComponent(wd)}&so=undefined`, {
headers: {
accept: 'application/json',
'User-Agent': Utils.MOBILEUA,
cookie: 'hm=' + cookie['hm'],
Referer: `${this.siteUrl}/s?q=${encodeURIComponent(wd)}`,
},
});
let data = JSON.parse(resp.content);
let books = [];
for (const book of data) {
books.push({
book_id: book["url_list"],
book_name: book["articlename"],
book_pic: book["url_img"],
book_remarks: book["author"],
});
}
return {
tline: 2, list: books,
};
}
async proxy(segments, headers) {
await this.jadeLog.debug(`正在设置反向代理 segments = ${segments.join(",")},headers = ${JSON.stringify(headers)}`)
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'img') {
await this.jadeLog.debug(`反向代理ID为:${url}`)
let $ = await this.getHtml(this.siteUrl + url)
let bookDetail = await this.parseVodDetailFromDoc($)
let resp;
if (!_.isEmpty(headers)) {
resp = await req(bookDetail.book_pic, {
buffer: 2, headers: headers
});
} else {
resp = await req(bookDetail.book_pic, {
buffer: 2, headers: {
Referer: url, 'User-Agent': Utils.CHROME,
},
});
}
return JSON.stringify({
code: resp.code, buffer: 2, content: resp.content, headers: resp.headers,
});
}
return JSON.stringify({
code: 500, content: '',
});
}
}
let spider = new BQQSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,347 +0,0 @@
/*
* @File : changzhang.js
* @Author : jade
* @Date : 2024/2/2 16:02
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {Spider} from "./spider.js";
import {_, Crypto, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
import {detailContent, initAli, playContent} from "../lib/ali.js";
function cryptJs(text, key, iv, type) {
let key_value = Crypto.enc.Utf8.parse(key || 'PBfAUnTdMjNDe6pL');
let iv_value = Crypto.enc.Utf8.parse(iv || 'sENS6bVbwSfvnXrj');
let content
if (type) {
content = Crypto.AES.encrypt(text, key_value, {
iv: iv_value, mode: Crypto.mode.CBC, padding: Crypto.pad.Pkcs7
})
} else {
content = Crypto.AES.decrypt(text, key_value, {
iv: iv_value, padding: Crypto.pad.Pkcs7
}).toString(Crypto.enc.Utf8)
}
return content
}
class ChangZhangSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.czys.top"
}
async init(cfg) {
await super.init(cfg);
await initAli(this.cfgObj["token"]);
}
getName() {
return "🏭️┃厂长直连┃🏭️"
}
getAppName() {
return "厂长直连"
}
getJSName() {
return "changzhang"
}
getType() {
return 3
}
async getHtml(url = this.siteUrl, headers = this.getHeader()) {
let response = await this.fetch(url, null, headers,false,true);
let html = response["content"]
if (!_.isEmpty(html) && html.indexOf("人机验证")===-1) {
return load(html)
} else {
await this.jadeLog.error(`html获取失败`, true)
}
}
getSearchHeader() {
return {
"Cookie": "cf_clearance=otYZbHg1safCIxkCtZfy9DPKbf1Gs_zUskkVDc0MVKM-1707026063-1-ATOpKnTLv9+pv171YE/rzxN/nmvGN9Mucx7vpwp0kW2vZb/cbtz5e2md2/ym7EE+9dT7pPBV+kQOg9vJx2v8cks=;myannoun=1;PHPSESSID=73386nobqugs7r3pb2ljcsp5q4",
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/100.0.4896.77 Mobile/15E148 Safari/604.1",
"Connection":"keep-alive",
"Host":"www.czzy55.com"
}
}
parseVodShortFromElement($, element) {
let vodShort = new VodShort()
let imgElement = $($(element).find("a")).find("img")[0]
vodShort.vod_name = imgElement.attribs.alt
vodShort.vod_pic = imgElement.attribs["data-original"]
vodShort.vod_remarks = $($($(element).find("[class='hdinfo']")).find("span")).text()
vodShort.vod_id = $(element).find("a")[0].attribs.href
return vodShort
}
async parseVodShortListFromDoc($) {
let vod_list = []
let aList = $($("[class=\"mi_cont\"]").find("ul")).find("li")
for (const a of aList) {
vod_list.push(this.parseVodShortFromElement($, a))
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let aList = $($("[class=\"mi_cont \"]").find("ul")).find("li")
for (const a of aList) {
vod_list.push(this.parseVodShortFromElement($, a))
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let nodeElement = $("[class='dyxingq']")
vodDetail.vod_pic = $(nodeElement).find("img")[0].attribs.src
vodDetail.vod_name = $($(nodeElement).find("h1")[0]).text()
vodDetail.vod_content = $($($("[class='yp_context']")).find("p")).text()
let infoArray = $(nodeElement).find("[class='moviedteail_list']").find("li")
let x = $(infoArray).text()
for (const info of infoArray) {
let content = $(info).text()
if (content.indexOf("类型") > -1) {
vodDetail.type_name = content.replaceAll("类型", "").replaceAll("", "")
} else if (content.indexOf("年份") > -1) {
vodDetail.vod_year = content.replaceAll("年份", "").replaceAll("", "")
} else if (content.indexOf("地区") > -1) {
vodDetail.vod_area = content.replaceAll("地区", "").replaceAll("", "")
} else if (content.indexOf("豆瓣") > -1) {
vodDetail.vod_remarks = content.replaceAll("豆瓣", "").replaceAll("", "")
} else if (content.indexOf("主演") > -1) {
vodDetail.vod_actor = content.replaceAll("主演", "").replaceAll("", "")
} else if (content.indexOf("导演") > -1) {
vodDetail.vod_director = content.replaceAll("导演", "").replaceAll("", "")
} else if (content.indexOf("剧情") > -1) {
vodDetail.vod_content = content.replaceAll("剧情", "").replaceAll("", "")
}
}
let vod_play_from_list = ["厂长资源"]
let vodPlayList = $("[class='paly_list_btn']")
let vod_play_list = []
for (const v1 of vodPlayList) {
let vodItems = []
let aList = $(v1).find("a")
for (const tA of aList) {
let episodeUrl = tA.attribs.href
let episodeName = $(tA).text().replaceAll("立即播放  (", "").replaceAll(")", "")
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
let valify_formt_list = ["磁力链接", "阿里网盘"]
let otherPlayList = $("[class=\"ypbt_down_list\"]").find("li")
for (const otherPlay of otherPlayList) {
let form_name = $(otherPlay).text()
let is_valify = false
for (const valify_format_name of valify_formt_list) {
if (form_name.indexOf(valify_format_name) > -1) {
is_valify = true
if (form_name.indexOf("阿里网盘") === -1) {
vod_play_from_list.push(valify_format_name)
}
}
}
if (is_valify) {
let vodItems = []
for (const ciliPlayUrl of $(otherPlay).find("a")) {
let episodeUrl = ciliPlayUrl.attribs.href
if ($(otherPlay).text().indexOf("阿里网盘")) {
let aliVodDetail = await detailContent([episodeUrl])
let aliPlayUrlList = aliVodDetail.vod_play_url.split("$$$")
let is_exists = false
for (const aliPlayUrl of aliPlayUrlList) {
if (!_.isEmpty(aliPlayUrl)) {
is_exists = true
vod_play_list.push(aliPlayUrl)
}
}
if (is_exists) {
for (const aliFormatName of aliVodDetail.vod_play_from.split("$$$")) {
vod_play_from_list.push("阿里云盘-" + aliFormatName)
}
}
} else {
let episodeName = Utils.getStrByRegex(/\[(.*?)]/, $(ciliPlayUrl).text())
vodItems.push(episodeName + "$" + episodeUrl)
vod_play_list.push(vodItems.join("#"))
}
}
}
}
vodDetail.vod_play_url = vod_play_list.join("$$$")
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
const items = $('div.search_list > ul > li');
return _.map(items, (item) => {
const img = $(item).find('img:first')[0];
const a = $(item).find('a:first')[0];
const hdinfo = $($(item).find('div.hdinfo')[0]).text().trim();
const jidi = $($(item).find('div.jidi')[0]).text().trim();
return {
vod_id: a.attribs.href,
vod_name: img.attribs.alt,
vod_pic: img.attribs['data-original'],
vod_remarks: jidi || hdinfo || '',
};
})
}
async setClasses() {
const $ = await this.getHtml(this.siteUrl + '/movie_bt');
const series = $('div#beautiful-taxonomy-filters-tax-movie_bt_series > a[cat-url*=movie_bt_series]');
const tags = $('div#beautiful-taxonomy-filters-tax-movie_bt_tags > a');
let tag = {
key: 'tag', name: '类型', value: _.map(tags, (n) => {
let v = n.attribs['cat-url'] || '';
v = v.substring(v.lastIndexOf('/') + 1);
return {n: n.children[0].data, v: v};
}),
};
tag['init'] = tag.value[0].v;
let classes = _.map(series, (s) => {
let typeId = s.attribs['cat-url'];
typeId = typeId.substring(typeId.lastIndexOf('/') + 1);
this.filterObj[typeId] = [tag];
return {
type_id: typeId, type_name: s.children[0].data,
};
});
const sortName = ['电影', '电视剧', '国产剧', '美剧', '韩剧', '日剧', '海外剧(其他)', '华语电影', '印度电影', '日本电影', '欧美电影', '韩国电影', '动画', '俄罗斯电影', '加拿大电影'];
let sort_classes = _.sortBy(classes, (c) => {
const index = sortName.indexOf(c.type_name);
return index === -1 ? sortName.length : index;
});
for (const sort_class of sort_classes){
let type_name = sort_class["type_name"]
if (type_name!=="会员专区" && type_name !== "站长推荐"){
this.classes.push(sort_class)
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
if (pg <= 0) pg = 1;
const tag = extend.tag || '';
const link = this.siteUrl + '/movie_bt' + (tag.length > 0 ? `/movie_bt_tags/${tag}` : '') + '/movie_bt_series/' + tid + (pg > 1 ? `/page/${pg}` : '');
let $ = await this.getHtml(link)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setSearch(wd, quick) {
const $ = await this.getHtml(this.siteUrl + '/xssearch?q=' + wd,this.getSearchHeader());
let html = $.html()
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
async setPlay(flag, id, flags) {
if (flag.indexOf("阿里云盘") > -1) {
flag = flag.replaceAll("阿里云盘-","")
this.playUrl = JSON.parse(await playContent(flag, id, flags))["url"];
} else {
if (id.indexOf("magnet") > -1) {
this.playUrl = id
} else {
let $ = await this.getHtml(id)
const iframe = $('body iframe[src*=https]');
if (iframe.length > 0) {
const iframeHtml = (await req(iframe[0].attribs.src, {
headers: {
Referer: id, 'User-Agent': Utils.CHROME,
},
})).content;
let player = Utils.getStrByRegex(/var player = "(.*?)"/, iframeHtml)
let rand = Utils.getStrByRegex(/var rand = "(.*?)"/, iframeHtml)
let content = JSON.parse(cryptJs(player, "VFBTzdujpR9FWBhe", rand))
this.playUrl = content["url"]
} else {
const js = $('script:contains(window.wp_nonce)').html();
const group = js.match(/(var.*)eval\((\w*\(\w*\))\)/);
const md5 = Crypto;
const result = eval(group[1] + group[2]);
this.playUrl = result.match(/url:.*?['"](.*?)['"]/)[1];
}
}
}
}
}
let spider = new ChangZhangSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

View File

@ -1,191 +0,0 @@
/*
* @File : ciliduo.js
* @Author : jade
* @Date : 2024/3/1 13:26
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 磁力多
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class CiliDuoSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://of.cilido.top"
this.apiUrl = ""
this.vodShortObj = {}
}
getName() {
return "🔞┃磁力多BT┃🔞"
}
getAppName() {
return "磁力多BT"
}
getJSName() {
return "ciliduo"
}
getType() {
return 3
}
getProxy(src) {
return Utils.base64Decode(src)
}
async home(filter) {
try {
await this.jadeLog.info("正在解析首页类别", true)
let $ = await this.getHtml()
let proxy_src = Utils.getStrByRegex(/var proxy = atob\('(.*?)'\)/, $.html())
this.apiUrl = this.getProxy(proxy_src)
let params = `/?host=${Utils.getHost(this.siteUrl).split("://").slice(-1)[0]}&v=1`
let homeContent = await this.fetch(this.apiUrl, params, this.getHeader())
return await this.parseVodShortListFromDoc(load(homeContent))
} catch (e) {
await this.jadeLog.error(`首页解析失败,失败原因为:${e}`)
}
}
async parseVodShortListFromDoc($) {
let rootElemet = $("[class=\"htab\"]")
let navElements = rootElemet.find("a")
let vodElements = $("[class=\"hotwords\"]").find("ul")
for (let i = 0; i < navElements.length; i++) {
let navElement = navElements[i]
if (i !== navElements.length - 1) {
let type_name = $(navElement).text()
if (type_name === "热门") {
type_name = "最近更新"
}
this.classes.push(this.getTypeDic(type_name, type_name))
let vodElement = vodElements[i]
let vod_list = []
for (const vodShorElement of $(vodElement).find("a")) {
let vodShort = new VodShort()
vodShort.vod_id = vodShorElement.attribs.href
vodShort.vod_name = $(vodShorElement).html()
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/cili.jpg"
vod_list.push(vodShort)
}
this.vodShortObj[type_name] = vod_list
}
}
return this.result.home(this.classes, [], this.filterObj)
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"ssbox\"]")
for (const vodElement of vodElements.slice(0, -1)) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
vodShort.vod_name = $($(vodElement).find("a")[0]).text()
vodShort.vod_remarks = $($(vodElement).find("span")[0]).text()
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/cili.jpg"
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let html = $.html()
let vodDetail = new VodDetail()
vodDetail.vod_name = $($("[class=\"bt_title\"]")).text()
vodDetail.vod_pic = Utils.RESOURCEURL + "/resources/cili.jpg"
vodDetail.vod_remarks = Utils.getStrByRegex(/<br>收录时间:<span>(.*?)<\/span>/, $.html())
vodDetail.vod_content = "下载速度:" + Utils.getStrByRegex(/下载速度:<span>(.*?)<\/span>/, $.html())
vodDetail.vod_play_from = ["磁力连接"].join("$$$")
let vodItems = []
let contentElement = $("[class=\"content\"]").find("span")[0]
let episodeUrl = contentElement.attribs.href;
let episodeName = contentElement.attribs.title;
vodItems.push(episodeName + "$" + episodeUrl);
vodDetail.vod_play_url = [vodItems.join("#")].join("$$$")
return vodDetail
}
async setHomeVod() {
this.homeVodList = this.vodShortObj["最近更新"]
}
async setCategory(tid, pg, filter, extend) {
this.vodList = this.vodShortObj[tid]
}
async setDetail(id) {
if (id.indexOf("search") > -1) {
let content = await this.fetch(this.apiUrl + id, null, this.getHeader())
let vod_list = await this.parseVodShortListFromDocBySearch(load(content))
id = vod_list[0].vod_id
}
await this.jadeLog.debug(id)
let detailUrl = this.apiUrl + id
let detailContent = await this.fetch(detailUrl, null, this.getHeader())
this.vodDetail = await this.parseVodDetailFromDoc(load(detailContent))
}
async setSearch(wd, quick) {
let searchUrl = this.apiUrl + `search?word=${wd}`
let content = await this.fetch(searchUrl, null, this.getHeader())
this.vodList = await this.parseVodShortListFromDocBySearch(load(content))
}
}
let spider = new CiliDuoSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

View File

@ -1,253 +0,0 @@
/*
* @File : cilixiong.js
* @Author : jade
* @Date : 2024/4/13 14:52
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js"
class CiliXiongSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.cilixiong.com"
this.cateObj = {"/movie/": "1", "/drama/": "2"}
}
getAppName() {
return "磁力熊"
}
getName() {
return "🐻┃磁力熊┃🐻"
}
getJSName() {
return "cilixiong"
}
getType() {
return 3
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $("[class=\"nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0\"]").find("li")
for (const navElement of navElements) {
let element = $(navElement).find("a")[0]
let type_name = $(element).text()
let type_id = element.attribs.href
if (type_name !== "首页" && type_name !== "榜单" && type_name !== "留言") {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($) {
let extend_list = []
let filerElements = $("[class=\"nav small\"]")
let i = 1
for (const filetElement of filerElements) {
let extend_name = $($(filetElement).find("li")[0]).text().replaceAll("", "")
let extend_dic = {"key": (i).toString(), "name": extend_name, "value": []}
for (const typeElement of $(filetElement).find("li").slice(1)) {
let element = $(typeElement).find("a")[0]
let type_id = element.attribs.href.split("-")[i]
extend_dic["value"].push({"n": $(element).text(), "v": type_id})
}
i = i + 1
extend_list.push(extend_dic)
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let $ = await this.getHtml(this.siteUrl + type_id)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"col\"]")
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
vodShort.vod_pic = Utils.getStrByRegex(/background-image: url\('(.*?)'\)/, $(vodElement).find("[class=\"card-img\"]")[0].attribs["style"])
vodShort.vod_name = $($(vodElement).find("h2")).text()
let remarks = $($(vodElement).find("[class=\"rank bg-success p-1\"]")).text()
vodShort.vod_remarks = "评分:" + remarks
if (remarks !== "AD") {
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"card card-cover h-100 overflow-hidden text-bg-dark rounded-4 shadow-lg position-relative\"]")
for (const vodElement of vodElements){
let vodShort= new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
vodShort.vod_name = $($(vodElement).find("[class=\"pt-5 lh-1 pb-2 h4\"]")).text()
vodShort.vod_pic = Utils.getStrByRegex(/background-image: url\('(.*?)'\)/,$(vodElement).find("[class=\"card-img\"]")[0].attribs.style)
vodShort.vod_remarks = "评分:" + $($(vodElement).find("[class=\"rank bg-success p-1\"]")).text()
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let vodDetailElement = $("[class=\"row row-cols-1 row-cols-lg-3 align-items-stretch g-4 p-5 text-white\"]")
vodDetail.vod_pic = $(vodDetailElement).find("img")[0].attribs.src
vodDetail.vod_name = $($(vodDetailElement).find("h1")).text()
let vodContentElements = $(vodDetailElement).find("[class=\"mb-2\"]").slice(1)
for (const contentElement of vodContentElements) {
let name = $(contentElement).text()
if (name.indexOf("豆瓣评分") > -1) {
vodDetail.vod_remarks = name
}
if (name.indexOf("类型") > -1) {
vodDetail.type_name = name.replaceAll("", "").replace("类型", "").replaceAll(":", "")
}
if (name.indexOf("上映地区") > -1) {
vodDetail.vod_area = name.replaceAll("", "").replace("上映地区", "").replaceAll(":", "")
}
if (name.indexOf("主演") > -1) {
vodDetail.vod_actor = name.replaceAll("", "").replace("主演", "").replaceAll(":", "")
}
if (name.indexOf("上映日期") > -1){
vodDetail.vod_year = name.replaceAll("", "").replace("上映日期", "").replaceAll(":", "")
}
}
vodDetail.vod_content = $($(vodDetailElement).find("[class=\"mv_card_box\"]")).text()
let playerMap = {}
let emebedVideoElements = $("[class=\"row col-md-12 embed_video\"]")
let index = 1
for (const emebedVideoElement of emebedVideoElements){
let vodItems = []
let playUrl = $($(emebedVideoElement).find("iframe"))[0].attribs["src"]
vodItems.push("播放" + "$" + playUrl);
playerMap["在线播放" + index.toString()+ "第一集在线播放预览"] = vodItems.join("#")
index = index + 1
}
let mangetIndex = 1
let mangetElements = $("[class=\"row col-md-12 text-white p-3 pt-1\"]").find("[class=\"container\"]")
for (const mangenment of mangetElements){
let vodItems = []
let playElement = $($(mangenment).find("a"))[0]
let playUrl = playElement.attribs.href
let playName = $(playElement).text()
if (playUrl.startsWith("magnet")){
vodItems.push(playName + "$" + playUrl);
}
if (vodItems.length > 0){
playerMap["磁力链接" + "-" + mangetIndex] = vodItems.join("#")
mangetIndex = mangetIndex + 1
}
}
vodDetail.vod_play_from = Object.keys(playerMap).join("$$$");
vodDetail.vod_play_url = Object.values(playerMap).join("$$$");
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let type = extend["1"] ?? "0"
let area = extend["2"] ?? "0"
let page = parseInt(pg) - 1
let url = this.siteUrl + "/" + this.cateObj[tid] + `-${type}-${area}-${page}.html`
await this.jadeLog.debug(`分类URL:${url}`)
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setPlay(flag, id, flags) {
if (flag.indexOf("在线播放") > -1){
let $ = await this.getHtml(this.siteUrl + id)
this.playUrl = Utils.getStrByRegex(/const source = '(.*?)'/,$.html())
}else{
this.playUrl = id
}
}
async setSearch(wd, quick) {
let params = {"classid":"1,2","show":"title","tempid":"1","keyboard":wd}
let response = await this.post(this.siteUrl + "/e/search/index.php",params,this.getHeader())
let $ = load(response)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new CiliXiongSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,364 +0,0 @@
/*
* @File : cntv.js
* @Author : jade
* @Date : 2024/4/25 10:26
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {Spider} from "./spider.js";
import {_} from "../lib/cat.js";
import * as Utils from "../lib/utils.js";
import {VodDetail, VodShort} from "../lib/vod.js";
class CNTVSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://tv.cctv.com/m/index.shtml"
this.apiUrl = "https://api.app.cctv.com"
this.liveJsonUrl = "https://gh.con.sh/https://github.com/jadehh/LiveSpider/blob/main/json/live.json"
}
getName() {
return "🤵‍♂️┃中央影视┃🤵‍♂️"
}
getAppName() {
return "中央影视"
}
getJSName() {
return "cntv"
}
getType() {
return 3
}
async spiderInit() {
await super.spiderInit();
this.liveJson = JSON.parse(await this.fetch(this.liveJsonUrl, null, null))
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit()
}
async getFilterByLive(dataList) {
let extend_list = []
let extend_dic = {"key": "live", "name": "直播", "value": []}
for (const data of dataList) {
if (data["appBarTitle"] !== "最近常看") {
extend_dic["value"].push({"n": data["appBarTitle"], "v": data["pageId"]})
}
}
extend_list.push(extend_dic)
return extend_list
}
arrayIsinclude(str, items) {
let isInclude = false
for (const data of items) {
if (str === data["title"]) {
return true
}
}
return isInclude
}
async getFilterByTv(dataList) {
let extend_list = []
for (const data of dataList) {
let add_year_status = false
let extend_dic = {"key": data["classname"], "name": data["title"], "value": []}
for (const extendData of data["items"]) {
if (data["classname"] === "nianfen") {
if (!this.arrayIsinclude("2024", data["items"]) && extendData["title"] !== "全部" && !add_year_status) {
extend_dic["value"].push({"n": "2024", "v": "2024"})
add_year_status = true
}
}
extend_dic["value"].push({"n": extendData["title"], "v": extendData["title"]})
}
extend_list.push(extend_dic)
}
return extend_list
}
async setClasses() {
let liveTypeId = "cctvlive"
let liveApi = this.apiUrl + `/api/navigation/iphone/AppStore/7.9.4/${liveTypeId}`
let liveJson = JSON.parse(await this.fetch(liveApi, null, this.getHeader()))
let extend_list = await this.getFilterByLive(liveJson["data"]["templates"])
let defaultLiveId = extend_list[0]["value"][0]["v"]
this.classes.push(this.getTypeDic("直播", defaultLiveId))
this.filterObj[defaultLiveId] = extend_list
let tvApi = "https://cbox.cctv.com/cboxpcvip/online2022/yxg/data1.jsonp?=pk"
let tvContent = await this.fetch(tvApi, null, this.getHeader())
let tvJSon = JSON.parse(tvContent.replaceAll("pk(", "").replaceAll(")", ""))
for (const data of tvJSon["data"]) {
let typeName = data["title"]
this.classes.push(this.getTypeDic(typeName, typeName))
this.filterObj[typeName] = await this.getFilterByTv(data["templates"])
}
}
parseVodShortByJson(items) {
let vod_list = []
for (const item of items) {
let vodShort = new VodShort()
vodShort.vod_pic = item["img1"]
if (_.isEmpty(vodShort.vod_pic)) {
vodShort.vod_pic = item["epgHorizontalPic"]
vodShort.vod_id = "live-" + item["epgChnlChar"] + "-" + vodShort.vod_pic
} else {
vodShort.vod_id = "play-" + item["playid"] + "-" + vodShort.vod_pic
vodShort.vod_pic = item["img1"]
}
vodShort.vod_name = item["title"]
vod_list.push(vodShort)
}
return vod_list
}
parseVodShortByTvJson(items) {
let vod_list = []
for (const item of items) {
let vodShort = new VodShort()
//关键是如何获取GUID 2d3224585904496ea837f682da0c4aa6
vodShort.vod_id = "url-" + item["vsetid"]
vodShort.vod_name = item["title"]
vodShort.vod_pic = item["image"]
vodShort.vod_remarks = item["sc"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromJson(objList) {
let vod_list = []
let top_status = false
for (const data of objList) {
if (data["title"] === "今日热点") {
top_status = true
} else if (!_.isEmpty(data["title"])) {
if (top_status) {
break
}
}
if (top_status) {
vod_list = [...vod_list, ...this.parseVodShortByJson(data["items"])]
}
}
return vod_list
}
async getLiveUrl(channel_id, obj) {
let liveApiUrl = `https://vdn.live.cntv.cn/api2/live.do?channel=pd://cctv_p2p_hd${channel_id}&client=iosapp`
let liveResponse = await req(liveApiUrl, {"headers": this.getHeader()})
let liveJson = JSON.parse(liveResponse["content"])
let playList = {}
let channelName = obj["channelName"].split(" ")[0].replaceAll("-", "").toLowerCase()
let liveUrl = this.liveJson[channelName] ?? liveJson["hls_url"]["hls2"]
playList["直播"] = ["点击播放$" + liveUrl]
await this.jadeLog.info(`liveJson:${JSON.stringify(liveJson)}`)
let vod_items = []
if (this.liveJson[channelName] !== undefined) {
} else {
for (const data of obj["program"]) {
let episodeName = data["showTime"] + "-" + data["t"]
let episodeUrl = liveUrl + `?begintimeabs=${data["st"] * 1000}&endtimeabs=${data["et"] * 1000}`
vod_items.push(episodeName + "$" + episodeUrl)
}
}
if (vod_items.length > 0){
playList["点播"] = vod_items.join("#")
}
return playList
}
async getVideoUrl(guid) {
return {"中央影视": ['点击播放' + '$' + guid].join("#")}
}
async parseVodDetailfromJson(id, obj, pic) {
let vodDetail = new VodDetail()
let $;
let guid;
if (obj["url"] !== undefined) {
vodDetail.vod_name = obj["title"]
vodDetail.vod_pic = obj["img"]
vodDetail.type_name = obj["tags"]
vodDetail.vod_year = obj["time"]
vodDetail.vod_content = obj["vset_brief"]
vodDetail.vod_director = obj["vset_title"]
$ = await this.getHtml(obj["url"])
} else {
if (_.isEmpty(obj["lvUrl"])) {
vodDetail.vod_name = obj["channelName"]
vodDetail.vod_pic = pic
} else {
$ = await this.getHtml(obj["lvUrl"])
vodDetail.vod_name = $('[property$=title]')[0].attribs.content
vodDetail.vod_content = $('[property$=description]')[0].attribs.content
let pic = $('[property$=image]')[0].attribs.content
if (!pic.startsWith("http")) {
pic = "https:" + pic
}
vodDetail.vod_pic = pic
}
}
if (!_.isEmpty($)) {
guid = Utils.getStrByRegex(/var guid = "(.*?)"/, $.html())
}
let playlist
if (_.isEmpty(guid) && obj["url"] === undefined) {
playlist = await this.getLiveUrl(id, obj)
} else {
playlist = await this.getVideoUrl(guid)
}
vodDetail.vod_play_url = _.values(playlist).join('$$$');
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
return vodDetail
}
async parseVodDetailFromJsonByTv(obj) {
let vodDetail = new VodDetail()
vodDetail.vod_name = obj["videoSetInfo"]["title"]
vodDetail.type_name = obj["videoSetInfo"]["sc"]
vodDetail.vod_pic = obj["videoSetInfo"]["image"]
vodDetail.vod_content = obj["videoSetInfo"]["brief"]
vodDetail.vod_area = obj["videoSetInfo"]["area"]
let playlist = {}
let vodItems = []
for (const data of obj["videoRoughCut"]) {
let title = data["title"].split("》").slice(-1)[0]
vodItems.push(title + "$" + data["guid"])
}
playlist["中央影视"] = vodItems.join("#")
vodDetail.vod_play_url = _.values(playlist).join('$$$');
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
return vodDetail
}
async setHomeVod() {
let resJson = JSON.parse(await this.fetch(this.apiUrl + "/api/page/iphone/HandheldApplicationSink/7.0.0/158", null, this.getHeader()))
this.homeVodList = await this.parseVodShortListFromJson(resJson["data"]["templates"])
}
getExtendValue(extend, key) {
if (extend[key] !== undefined && extend[key] !== "全部") {
return extend[key]
}
return ""
}
async setCategory(tid, pg, filter, extend) {
if (Utils.isNumeric(tid)) {
tid = extend["live"] ?? tid
let url = this.apiUrl + `/api/page/iphone/HandheldApplicationSink/7.0.0/${tid}`
let response = JSON.parse(await this.fetch(url, null, this.getHeader()))
this.vodList = this.parseVodShortByJson(response["data"]["templates"][0]["items"])
} else {
let letter = this.getExtendValue(extend, "zimu")
let area = this.getExtendValue(extend, "diqu")
let type = this.getExtendValue(extend, "leixing")
let year = this.getExtendValue(extend, "nianfen")
const limit = 12
let url = "https://api.cntv.cn" + `/newVideoset/getCboxVideoAlbumList`
let params = {
"channelid": "",
"sc": type,
"fc": tid,
"p": pg,
"n": limit,
"fl": letter,
"area": area,
"year": year,
"serviceId": "cbox"
}
let resJson = JSON.parse(await this.fetch(url, params, this.getHeader()))
this.vodList = this.parseVodShortByTvJson(resJson["data"]["list"])
}
}
async setDetail(id) {
//区分直播还是点播
let aList = id.split("-")
let playType = aList[0]
let pic = aList[2]
id = aList[1]
if (playType === "play") {
let resJson = JSON.parse(await this.fetch(`https://api.cntv.cn/video/videoinfoByGuid?serviceId=cbox&guid=${id}`, null, this.getHeader()))
this.vodDetail = await this.parseVodDetailfromJson(id, resJson, pic)
} else if (playType === "url") {
let url = `https://api.app.cctv.com/api/getVideoPageDetail?videoSetContentId=${id}`
let resJson = JSON.parse(await this.fetch(url, null, this.getHeader()))
this.vodDetail = await this.parseVodDetailFromJsonByTv(resJson["data"])
} else {
let content = (await this.fetch(`https://api.cntv.cn/epg/epginfo3?serviceId=shiyi&c=${id}&cb=LiveTileShow.prototype.getEpg`, null, this.getHeader())).replaceAll("LiveTileShow.prototype.getEpg(", "").replaceAll(");", "")
this.vodDetail = await this.parseVodDetailfromJson(id, JSON.parse(content)[id], pic)
}
}
async setSearch(wd, quick, pg) {
}
async setPlay(flag, id, flags) {
if (id.startsWith("http")) {
this.playUrl = id
let headers = this.getHeader()
headers["Referer"] = "https://tv.cctv.com/"
this.result.header = headers
} else {
this.playUrl = 'https://hls.cntv.myhwcdn.cn/asp/hls/2000/0303000a/3/default/' + id + '/2000.m3u8'
}
}
}
let spider = new CNTVSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider, CNTVSpider}

View File

@ -1,233 +0,0 @@
import {Spider} from "./spider.js";
import {BookDetail, BookShort} from "../lib/book.js";
import {Crypto} from "../lib/cat.js";
class CopyManhuaSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://www.copymanga.tv';
}
getName() {
return "🧑‍🎨|拷贝漫画|🧑‍🎨"
}
getAppName() {
return "拷贝漫画"
}
getJSName() {
return "copymanga"
}
getType() {
return 20
}
async setClasses() {
this.classes.push(this.getTypeDic("全部", "c1"))
}
async getFilter($) {
let region = {
key: 'region', name: '地區', init: '',
};
let regionValues = [];
regionValues.push({n: '全部', v: ''});
regionValues.push({n: '日漫', v: '0'});
regionValues.push({n: '韓漫', v: '1'});
regionValues.push({n: '美漫', v: '2'});
region['value'] = regionValues;
let ordering = {
key: 'ordering', name: '排序', init: '-datetime_updated',
};
let orderingValues = [];
orderingValues.push({n: '更新時間↓', v: '-datetime_updated'});
orderingValues.push({n: '更新時間↑', v: 'datetime_updated'});
orderingValues.push({n: '熱門↓', v: '-popular'});
orderingValues.push({n: '熱門↑', v: 'popular'});
ordering['value'] = orderingValues;
let status = {
key: 'sort', name: '狀態', init: '',
};
let statusValues = [];
statusValues.push({n: '全部', v: ''});
statusValues.push({n: '連載中', v: '0'});
statusValues.push({n: '已完結', v: '1'});
statusValues.push({n: '短篇', v: '2'});
status['value'] = statusValues;
let extend_list = []
let themeValues = [{n: '全部', v: ''}];
for (const a of $('div.classify-right>a[href*="theme="]')) {
themeValues.push({
n: $(a).text().trim(), v: a.attribs.href.match(/.*?theme=(.*)&/)[1],
});
}
extend_list.push({
key: 'theme', name: '', init: '', wrap: 1, value: themeValues,
});
extend_list.push(region);
extend_list.push(status);
extend_list.push(ordering);
return extend_list
}
async setFilterObj() {
let $ = await this.getHtml(this.siteUrl + '/comics');
this.filterObj['c1'] = await this.getFilter($);
}
parseVodShortFromJson(obj) {
let bookShort = new BookShort()
bookShort.book_id = obj["path_word"]
bookShort.book_name = obj["name"]
bookShort.book_pic = obj["cover"]
bookShort.book_remarks = obj.author ? obj.author[0].name : '';
return bookShort
}
async parseVodShortListFromDocByCategory($) {
const list = eval($('div[class="row exemptComic-box"]')[0].attribs.list);
let books = [];
for (const book of list) {
let bookShort = this.parseVodShortFromJson(book)
books.push(bookShort)
}
return books
}
async parseVodShortListFromDoc($) {
let vodElements = $("[class=\"container edit\"]").find("[class=\"col-auto\"]")
let books = []
for (const vodElement of vodElements) {
let bookShort = new BookShort()
bookShort.book_id = $(vodElement).find("a")[0].attribs.href.split("/comic/")[1]
bookShort.book_pic = $(vodElement).find("img")[0].attribs["data-src"]
bookShort.book_name = $($(vodElement).find("p")).text()
books.push(bookShort)
}
return books
}
async parseVodDetailFromDoc($, id) {
let bookDetail = new BookDetail()
bookDetail.book_pic = $("[class=\"comicParticulars-left-img loadingIcon\"]").find("img")[0].attribs["data-src"]
bookDetail.book_name = $('h6').text().trim()
bookDetail.book_director = $('span.comicParticulars-right-txt>a[href*="/author/"]')
.map((_, a) => $(a).text().trim())
.get()
.join('/')
bookDetail.book_content = $('p.intro').text().trim()
let data = JSON.parse(await this.fetch(this.siteUrl + `/comicdetail/${id}/chapters`, null, this.getHeader()))["results"]
let key = Crypto.enc.Utf8.parse('xxxmanga.woo.key');
let iv = Crypto.enc.Utf8.parse(data.substr(0, 16));
let src = Crypto.enc.Hex.parse(data.substr(16));
let dst = Crypto.AES.decrypt({ciphertext: src}, key, {iv: iv, padding: Crypto.pad.Pkcs7});
dst = Crypto.enc.Utf8.stringify(dst);
const groups = JSON.parse(dst).groups;
let urls = groups.default["chapters"]
.map((c) => {
return c.name + '$' + id + '|' + c.id;
})
.join('#');
bookDetail.volumes = '默認';
bookDetail.urls = urls;
bookDetail.book_id = id
return bookDetail
}
async parseVodShortListFromJson(obj) {
const books = [];
for (const book of obj) {
books.push(this.parseVodShortFromJson(book))
}
return books
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let page = pg || 1;
if (page === 0) page = 1;
let link = this.siteUrl + `/comics?theme=${extend.theme || ''}&region=${extend.region || ''}&status=${extend.status || ''}&ordering=${extend.ordering || '-datetime_updated'}`;
if (page > 1) {
link += '&offset=' + (page - 1) * 50 + '&limit=50';
}
let $ = await this.getHtml(link)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + `/comic/${id}`)
this.vodDetail = await this.parseVodDetailFromDoc($, id)
}
async setPlay(flag, id, flags) {
let info = id.split('|');
let $ = await this.getHtml(this.siteUrl + `/comic/${info[0]}/chapter/${info[1]}`);
const data = $('div.imageData')[0].attribs["contentkey"];
let key = Crypto.enc.Utf8.parse('xxxmanga.woo.key');
let iv = Crypto.enc.Utf8.parse(data.substr(0, 16));
let src = Crypto.enc.Hex.parse(data.substr(16));
let dst = Crypto.AES.decrypt({ciphertext: src}, key, {iv: iv, padding: Crypto.pad.Pkcs7});
dst = Crypto.enc.Utf8.stringify(dst);
const list = JSON.parse(dst);
let content = [];
for (let index = 0; index < list.length; index++) {
const element = list[index];
content[index] = element.url;
}
this.playUrl = {
"content": content,
}
}
async setSearch(wd, quick) {
let page = 1
const link = `${this.siteUrl}/api/kb/web/searcha/comics?offset=${page > 1 ? ((page - 1) * 12).toString() : ''}&platform=2&limit=12&q=${wd}&q_type=`;
let list = JSON.parse(await this.fetch(link, null, this.getHeader()))["results"]["list"]
this.vodList = await this.parseVodShortListFromJson(list)
}
}
let spider = new CopyManhuaSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,215 +0,0 @@
/*
* @File : dj0898_book_open.js.js
* @Author : jade
* @Date : 2023/12/22 17:00
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_} from '../lib/cat.js';
import {Spider} from "./spider.js";
import {BookShort} from "../lib/book.js";
class DJ0898Spider extends Spider {
constructor() {
super();
this.siteUrl = "http://m.dj0898.com";
}
getName() {
return "🎵┃世纪DJ音乐网┃🎵"
}
getAppName() {
return "世纪DJ音乐网"
}
getJSName() {
return "dj0898_book_open"
}
getType() {
return 10
}
async parseVodShortListFromDoc($) {
let books = []
const list = $("ul.djddv_djList > li");
for (const it of list) {
let bookShort = new BookShort();
const a = $(it).find("a")[1];
bookShort.book_id = a.attribs.href
bookShort.book_pic = $(it).find("img:first")[0].attribs.src;
const tt = $(it).find("strong:first")[0];
bookShort.book_name = tt.children[0].data
bookShort.book_remarks = "🎵" + $(it).find("font")[5].children[0].data || ""
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocByCategory($) {
const list = $("ul.djddv_djList > li");
let videos = _.map(list, (it) => {
const a = $(it).find("a")[1];
const img = $(it).find("img:first")[0];
const tt = $(it).find("strong:first")[0];
const remarks = $(it).find("font")[5];
return {
book_id: a.attribs.href,
book_name: tt.children[0].data,
book_pic: img.attribs["src"],
book_remarks: "🎵" + remarks.children[0].data || "",
};
});
const hasMore = $("ul.page_link > li > a:contains(\u00a0)").length > 0;
this.page = hasMore ? parseInt(this.page) + 1 : parseInt(this.page);
return videos
}
async parseVodShortListFromDocBySearch($) {
const list = $("ul.djddv_djList > li");
return _.map(list, (it) => {
const a = $(it).find("a")[1];
const img = $(it).find("img:first")[0];
const tt = $(it).find("strong:first")[0];
const remarks = $(it).find("font:first")[0];
return {
book_id: a.attribs.href,
book_name: tt.children[0].data,
book_pic: img.attribs["src"],
book_remarks: "🎵" + remarks.children[0].data || "",
};
})
}
async parseVodDetailFromDoc(id) {
const vod = {
book_id: id,
audio: 1,
type_name: '',
book_year: '',
book_area: '',
book_remarks: '',
book_actor: '',
book_director: '',
book_content: '',
};
const playlist = ["点击播放" + "$" + vod.book_id];
vod.volumes = "世纪DJ音乐网";
vod.urls = playlist.join("#");
return vod
}
async setClasses() {
this.classes = [{type_id: 1, type_name: "🎧串烧舞曲"}, {type_id: 2, type_name: "🎧外文舞曲"}, {
type_id: 3,
type_name: "🎧早场暖场"
}, {type_id: 4, type_name: "🎧中文舞曲"}, {type_id: 5, type_name: "🎧其他舞曲"}, {
type_id: 6,
type_name: "🎧国外电音"
}, {type_id: 8, type_name: "🎧慢歌连版"}, {type_id: 9, type_name: "🎧酒吧潮歌"}, {
type_id: 10,
type_name: "🎧中文串烧"
}, {type_id: 11, type_name: "🎧外文串烧"}, {type_id: 12, type_name: "🎧中外串烧"}, {
type_id: 13,
type_name: "🎧车载串烧"
}, {type_id: 14, type_name: "🎧越鼓串烧"}, {type_id: 40, type_name: "🎧3D/环绕"}, {
type_id: 45,
type_name: "🎧口水旋律"
}, {type_id: 46, type_name: "🎧精品收藏"}, {type_id: 47, type_name: "🎧开场舞曲"}, {
type_id: 48,
type_name: "🎧印度舞曲"
}, {type_id: 49, type_name: "🎧编排套曲"}, {type_id: 20, type_name: "🎧DuTch"}, {
type_id: 21,
type_name: "🎧Mash up"
}, {type_id: 22, type_name: "🎧ClubHouse"}, {type_id: 23, type_name: "🎧ElectroHouse"}, {
type_id: 24,
type_name: "🎧越南鼓Dj"
}, {type_id: 30, type_name: "🎧Funky"}, {type_id: 31, type_name: "🎧Reggae"}, {
type_id: 32,
type_name: "🎧Rnb"
}, {type_id: 33, type_name: "🎧Hip Hop"}, {type_id: 34, type_name: "🎧Dubstep"}, {
type_id: 8017,
type_name: "🎧Hardstyle"
}, {type_id: 8018, type_name: "🎧Hands Up"}];
}
async setFilterObj() {
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl + "/dance/lists/id/10/1")
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
const link = this.siteUrl + "/dance/lists/id/" + tid + "/" + pg;
let $ = await this.getHtml(link)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
this.vodDetail = await this.parseVodDetailFromDoc(id);
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(id)
const audio = $("body audio[src*=http]");
this.playUrl = audio[0].attribs.src
}
async setSearch(wd, quick) {
let $ = await this.getHtml(this.siteUrl + "/index.php/dance/so/key?key=" + wd + "&cid=0&p=1")
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new DJ0898Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,246 +0,0 @@
/*
* @File : doll.js
* @Author : jade
* @Date : 2024/1/4 14:15
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : doll
*/
import {Spider} from "./spider.js";
import {Crypto, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class Doll extends Spider {
constructor() {
super();
this.siteUrl = "https://hongkongdollvideo.com"
}
getImgHeader(){
let headers = this.getHeader()
headers["Proxy"] = true
return headers
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getImgHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getImgHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
async getHtml(url = this.siteUrl, proxy = false, headers = this.getHeader()) {
return super.getHtml(url, true, headers);
}
getName() {
return "🔞┃玩偶姐姐┃🔞"
}
getAppName() {
return "玩偶姐姐"
}
getJSName() {
return "doll"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"row\"]").find("[class=\"video-detail\"]")
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs["href"]
let videoInfoElements = $($(vodElement).find("[class=\"video-info\"]")).find("a")
vodShort.vod_name = videoInfoElements[0].attribs["title"]
vodShort.vod_remarks = $(videoInfoElements[1]).text()
let pic = $(vodElement).find("img")[0].attribs["data-src"]
// if (this.catOpenStatus) {
// vodShort.vod_pic = this.jsBase + Utils.base64Encode(pic)
// } else {
// vodShort.vod_pic = pic
// }
vodShort.vod_pic = pic
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($, key) {
let vodDetail = new VodDetail()
let vodElement = $("[class=\"container-fluid\"]")
vodDetail.vod_name = $($(vodElement).find("[class=\"page-title\"]")[0]).text()
vodDetail.vod_remarks = $(vodElement).find("[class=\"tag my-1 text-center\"]")[0].attribs["href"].replaceAll("/", "")
let pic = $(vodElement).find("video")[0].attribs["poster"]
// if (this.catOpenStatus) {
// vodDetail.vod_pic = this.jsBase + Utils.base64Encode(pic)
// } else {
// vodDetail.vod_pic = pic
// }
vodDetail.vod_pic = pic
let html = $.html()
let voteTag = Utils.getStrByRegex(/var voteTag="(.*?)";/g, html)
// let videoInfoStr = Utils.getStrByRegex(/<script type="application\/ld\+json">(.*?)<\/script>/g, html)
// let videoInfo = JSON.parse(videoInfoStr)
//
// try {
// let play_url_1 = await this.fetch(videoInfo["contentUrl"], null, this.getHeader())
// await this.jadeLog.debug(`播放链接为:${play_url_1}`)
// } catch (e) {
// await this.jadeLog.error(e)
// }
voteTag = Crypto.enc.Utf8.stringify(Crypto.enc.Base64.parse(voteTag))
let code = []
for (let i = 0; i < voteTag.length; i++) {
let k = i % key.length;
code.push(String.fromCharCode(voteTag.charCodeAt(i) ^ key.charCodeAt(k)))
}
let play_url_2 = decodeURIComponent(Crypto.enc.Utf8.stringify(Crypto.enc.Base64.parse(code.join(""))))
vodDetail.vod_play_from = "玩偶姐姐"
vodDetail.vod_play_url = "玩偶姐姐" + "$" + play_url_2
return vodDetail
}
async setClasses() {
let $ = await this.getHtml(this.siteUrl)
let navElements = $("[class=\"list-unstyled topnav-menu d-flex d-lg-block align-items-center justify-content-center flex-fill topnav-menu-left m-0\"]").find("li")
let index = 1
let class_id = index.toString()
this.classes = []
this.classes.push({"type_name": "首页", "type_id": "1"})
this.filterObj[class_id] = []
for (const navElement of navElements) {
let type_list = $(navElement).text().split("\n")
let valueElements = $(navElement).find("a")
let valueList = [{"n": "全部", "v": class_id}]
let type_id = index.toString()
for (const valueElement of valueElements) {
let title = $(valueElement).text().replaceAll("\n", "")
let href = valueElement.attribs["href"]
if (href !== undefined) {
valueList.push({"n": title, "v": href})
}
}
type_list = type_list.filter(element => element !== "");
this.filterObj[class_id].push({"key": type_id, "name": type_list[0], "value": valueList})
//下面这段是为了切割使用
// let new_value_list = []
// for (let i = 0; i < valueList.length; i++) {
// new_value_list.push(valueList[i])
// if (i % 8 === 0 && i !== 0) {
// this.filterObj[class_id].push({"key": type_id, "name": type_list[0], "value": new_value_list})
// new_value_list = []
// }
// }
// this.filterObj[class_id].push({"key": type_id, "name": type_list[0], "value": new_value_list})
}
let menuElements = $("[id=\"side-menu\"]").find("li")
for (const menuElement of menuElements) {
let type_id = $(menuElement).find("a")[0].attribs["href"]
if (type_id !== undefined && type_id.indexOf(this.siteUrl) > -1) {
let type_dic = {
"type_name": $(menuElement).text(), "type_id": type_id
}
this.classes.push(type_dic)
}
}
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
if (extend["1"] !== undefined) {
if (extend["1"] !== "1") {
tid = extend[1]
}
}
await this.jadeLog.info(`tid = ${tid}`)
let cateUrl = ""
if (tid.indexOf(this.siteUrl) > -1) {
cateUrl = tid + pg.toString() + ".html"
} else {
cateUrl = this.siteUrl
}
this.limit = 36
let $ = await this.getHtml(cateUrl)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(id)
let key = Utils.getStrByRegex(/video\/(\w+).html/, id)
this.vodDetail = await this.parseVodDetailFromDoc($, key)
}
async setPlay(flag, id, flags) {
this.playUrl = id
this.playHeader = {}
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + "search/" + encodeURIComponent(wd)
let $ = await this.getHtml(searchUrl)
this.vodList = await this.parseVodShortListFromDoc($)
}
async proxy(segments, headers) {
return super.proxy(segments, headers);
}
}
let spider = new Doll()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,636 +0,0 @@
/*
* @File : nivod.js
* @Author : jade
* @Date : 2023/12/19 14:23
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
import {_, Crypto} from "../lib/cat.js";
class DoubanSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://frodo.douban.com/api/v2'
this.apiKey = "0ac44ae016490db2204ce0a042db2916"
this.UserAgents = ["api-client/1 com.douban.frodo/7.22.0.beta9(231) Android/23 product/Mate 40 vendor/HUAWEI model/Mate 40 brand/HUAWEI rom/android network/wifi platform/AndroidPad", "api-client/1 com.douban.frodo/7.18.0(230) Android/22 product/MI 9 vendor/Xiaomi model/MI 9 brand/Android rom/miui6 network/wifi platform/mobile nd/1", "api-client/1 com.douban.frodo/7.1.0(205) Android/29 product/perseus vendor/Xiaomi model/Mi MIX 3 rom/miui6 network/wifi platform/mobile nd/1", "api-client/1 com.douban.frodo/7.3.0(207) Android/22 product/MI 9 vendor/Xiaomi model/MI 9 brand/Android rom/miui6 network/wifi platform/mobile nd/1"]
}
getHeader() {
return {
"Host": "frodo.douban.com",
"Connection": "Keep-Alive",
"Referer": "https://servicewechat.com/wx2f9b06c1de1ccfca/84/page-frame.html",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat"
}
}
getSearchHeader() {
let randomNumber = Math.floor(Math.random() * this.UserAgents.length); // 生成一个介于0到9之间的随机整数
return {
'User-Agent': this.UserAgents[randomNumber]
}
}
getName() {
return "🍥┃豆瓣┃🍥"
}
getAppName() {
return "豆瓣"
}
getJSName() {
return "douban"
}
getType() {
return 3
}
async setClasses() {
let classes = [{
"type_name": "热门电影", "type_id": "hot_gaia"
}, {
"type_name": "热播剧集", "type_id": "tv_hot"
}, {
"type_name": "热播综艺", "type_id": "show_hot"
}, {
"type_name": "电影筛选", "type_id": "movie"
}, {
"type_name": "电视筛选", "type_id": "tv"
}, {
"type_name": "电影榜单", "type_id": "rank_list_movie"
}, {
"type_name": "电视剧榜单", "type_id": "rank_list_tv"
}]
for (const class_dic of classes) {
this.classes.push({"type_name": class_dic["type_name"], "type_id": class_dic["type_id"]})
}
}
async setFilterObj() {
this.filterObj = {
"hot_gaia": [{
"key": "sort", "name": "排序", "value": [{
"n": "热度", "v": "recommend"
}, {
"n": "最新", "v": "time"
}, {
"n": "评分", "v": "rank"
}]
}, {
"key": "area", "name": "地区", "value": [{
"n": "全部", "v": "全部"
}, {
"n": "华语", "v": "华语"
}, {
"n": "欧美", "v": "欧美"
}, {
"n": "韩国", "v": "韩国"
}, {
"n": "日本", "v": "日本"
}]
}], "tv_hot": [{
"key": "type", "name": "分类", "value": [{
"n": "综合", "v": "tv_hot"
}, {
"n": "国产剧", "v": "tv_domestic"
}, {
"n": "欧美剧", "v": "tv_american"
}, {
"n": "日剧", "v": "tv_japanese"
}, {
"n": "韩剧", "v": "tv_korean"
}, {
"n": "动画", "v": "tv_animation"
}]
}], "show_hot": [{
"key": "type", "name": "分类", "value": [{
"n": "综合", "v": "show_hot"
}, {
"n": "国内", "v": "show_domestic"
}, {
"n": "国外", "v": "show_foreign"
}]
}], "movie": [{
"key": "类型", "name": "类型", "value": [{
"n": "全部类型", "v": ""
}, {
"n": "喜剧", "v": "喜剧"
}, {
"n": "爱情", "v": "爱情"
}, {
"n": "动作", "v": "动作"
}, {
"n": "科幻", "v": "科幻"
}, {
"n": "动画", "v": "动画"
}, {
"n": "悬疑", "v": "悬疑"
}, {
"n": "犯罪", "v": "犯罪"
}, {
"n": "惊悚", "v": "惊悚"
}, {
"n": "冒险", "v": "冒险"
}, {
"n": "音乐", "v": "音乐"
}, {
"n": "历史", "v": "历史"
}, {
"n": "奇幻", "v": "奇幻"
}, {
"n": "恐怖", "v": "恐怖"
}, {
"n": "战争", "v": "战争"
}, {
"n": "传记", "v": "传记"
}, {
"n": "歌舞", "v": "歌舞"
}, {
"n": "武侠", "v": "武侠"
}, {
"n": "情色", "v": "情色"
}, {
"n": "灾难", "v": "灾难"
}, {
"n": "西部", "v": "西部"
}, {
"n": "纪录片", "v": "纪录片"
}, {
"n": "短片", "v": "短片"
}]
}, {
"key": "地区", "name": "地区", "value": [{
"n": "全部地区", "v": ""
}, {
"n": "华语", "v": "华语"
}, {
"n": "欧美", "v": "欧美"
}, {
"n": "韩国", "v": "韩国"
}, {
"n": "日本", "v": "日本"
}, {
"n": "中国大陆", "v": "中国大陆"
}, {
"n": "美国", "v": "美国"
}, {
"n": "中国香港", "v": "中国香港"
}, {
"n": "中国台湾", "v": "中国台湾"
}, {
"n": "英国", "v": "英国"
}, {
"n": "法国", "v": "法国"
}, {
"n": "德国", "v": "德国"
}, {
"n": "意大利", "v": "意大利"
}, {
"n": "西班牙", "v": "西班牙"
}, {
"n": "印度", "v": "印度"
}, {
"n": "泰国", "v": "泰国"
}, {
"n": "俄罗斯", "v": "俄罗斯"
}, {
"n": "加拿大", "v": "加拿大"
}, {
"n": "澳大利亚", "v": "澳大利亚"
}, {
"n": "爱尔兰", "v": "爱尔兰"
}, {
"n": "瑞典", "v": "瑞典"
}, {
"n": "巴西", "v": "巴西"
}, {
"n": "丹麦", "v": "丹麦"
}]
}, {
"key": "sort", "name": "排序", "value": [{
"n": "近期热度", "v": "T"
}, {
"n": "首映时间", "v": "R"
}, {
"n": "高分优先", "v": "S"
}]
}, {
"key": "年代", "name": "年代", "value": [{
"n": "全部年代", "v": ""
}, {
"n": "2023", "v": "2023"
}, {
"n": "2022", "v": "2022"
}, {
"n": "2021", "v": "2021"
}, {
"n": "2020", "v": "2020"
}, {
"n": "2019", "v": "2019"
}, {
"n": "2010年代", "v": "2010年代"
}, {
"n": "2000年代", "v": "2000年代"
}, {
"n": "90年代", "v": "90年代"
}, {
"n": "80年代", "v": "80年代"
}, {
"n": "70年代", "v": "70年代"
}, {
"n": "60年代", "v": "60年代"
}, {
"n": "更早", "v": "更早"
}]
}], "tv": [{
"key": "类型", "name": "类型", "value": [{
"n": "不限", "v": ""
}, {
"n": "电视剧", "v": "电视剧"
}, {
"n": "综艺", "v": "综艺"
}]
}, {
"key": "电视剧形式", "name": "电视剧形式", "value": [{
"n": "不限", "v": ""
}, {
"n": "喜剧", "v": "喜剧"
}, {
"n": "爱情", "v": "爱情"
}, {
"n": "悬疑", "v": "悬疑"
}, {
"n": "动画", "v": "动画"
}, {
"n": "武侠", "v": "武侠"
}, {
"n": "古装", "v": "古装"
}, {
"n": "家庭", "v": "家庭"
}, {
"n": "犯罪", "v": "犯罪"
}, {
"n": "科幻", "v": "科幻"
}, {
"n": "恐怖", "v": "恐怖"
}, {
"n": "历史", "v": "历史"
}, {
"n": "战争", "v": "战争"
}, {
"n": "动作", "v": "动作"
}, {
"n": "冒险", "v": "冒险"
}, {
"n": "传记", "v": "传记"
}, {
"n": "剧情", "v": "剧情"
}, {
"n": "奇幻", "v": "奇幻"
}, {
"n": "惊悚", "v": "惊悚"
}, {
"n": "灾难", "v": "灾难"
}, {
"n": "歌舞", "v": "歌舞"
}, {
"n": "音乐", "v": "音乐"
}]
}, {
"key": "综艺形式", "name": "综艺形式", "value": [{
"n": "不限", "v": ""
}, {
"n": "真人秀", "v": "真人秀"
}, {
"n": "脱口秀", "v": "脱口秀"
}, {
"n": "音乐", "v": "音乐"
}, {
"n": "歌舞", "v": "歌舞"
}]
}, {
"key": "地区", "name": "地区", "value": [{
"n": "全部地区", "v": ""
}, {
"n": "华语", "v": "华语"
}, {
"n": "欧美", "v": "欧美"
}, {
"n": "国外", "v": "国外"
}, {
"n": "韩国", "v": "韩国"
}, {
"n": "日本", "v": "日本"
}, {
"n": "中国大陆", "v": "中国大陆"
}, {
"n": "中国香港", "v": "中国香港"
}, {
"n": "美国", "v": "美国"
}, {
"n": "英国", "v": "英国"
}, {
"n": "泰国", "v": "泰国"
}, {
"n": "中国台湾", "v": "中国台湾"
}, {
"n": "意大利", "v": "意大利"
}, {
"n": "法国", "v": "法国"
}, {
"n": "德国", "v": "德国"
}, {
"n": "西班牙", "v": "西班牙"
}, {
"n": "俄罗斯", "v": "俄罗斯"
}, {
"n": "瑞典", "v": "瑞典"
}, {
"n": "巴西", "v": "巴西"
}, {
"n": "丹麦", "v": "丹麦"
}, {
"n": "印度", "v": "印度"
}, {
"n": "加拿大", "v": "加拿大"
}, {
"n": "爱尔兰", "v": "爱尔兰"
}, {
"n": "澳大利亚", "v": "澳大利亚"
}]
}, {
"key": "sort", "name": "排序", "value": [{
"n": "近期热度", "v": "T"
}, {
"n": "首播时间", "v": "R"
}, {
"n": "高分优先", "v": "S"
}]
}, {
"key": "年代", "name": "年代", "value": [{
"n": "全部", "v": ""
}, {
"n": "2023", "v": "2023"
}, {
"n": "2022", "v": "2022"
}, {
"n": "2021", "v": "2021"
}, {
"n": "2020", "v": "2020"
}, {
"n": "2019", "v": "2019"
}, {
"n": "2010年代", "v": "2010年代"
}, {
"n": "2000年代", "v": "2000年代"
}, {
"n": "90年代", "v": "90年代"
}, {
"n": "80年代", "v": "80年代"
}, {
"n": "70年代", "v": "70年代"
}, {
"n": "60年代", "v": "60年代"
}, {
"n": "更早", "v": "更早"
}]
}, {
"key": "平台", "name": "平台", "value": [{
"n": "全部", "v": ""
}, {
"n": "腾讯视频", "v": "腾讯视频"
}, {
"n": "爱奇艺", "v": "爱奇艺"
}, {
"n": "优酷", "v": "优酷"
}, {
"n": "湖南卫视", "v": "湖南卫视"
}, {
"n": "Netflix", "v": "Netflix"
}, {
"n": "HBO", "v": "HBO"
}, {
"n": "BBC", "v": "BBC"
}, {
"n": "NHK", "v": "NHK"
}, {
"n": "CBS", "v": "CBS"
}, {
"n": "NBC", "v": "NBC"
}, {
"n": "tvN", "v": "tvN"
}]
}], "rank_list_movie": [{
"key": "榜单", "name": "榜单", "value": [{
"n": "实时热门电影", "v": "movie_real_time_hotest"
}, {
"n": "一周口碑电影榜", "v": "movie_weekly_best"
}, {
"n": "豆瓣电影Top250", "v": "movie_top250"
}]
}], "rank_list_tv": [{
"key": "榜单", "name": "榜单", "value": [{
"n": "实时热门电视", "v": "tv_real_time_hotest"
}, {
"n": "华语口碑剧集榜", "v": "tv_chinese_best_weekly"
}, {
"n": "全球口碑剧集榜", "v": "tv_global_best_weekly"
}, {
"n": "国内口碑综艺榜", "v": "show_chinese_best_weekly"
}, {
"n": "国外口碑综艺榜", "v": "show_global_best_weekly"
}]
}]
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const item of obj) {
let vod_short = new VodShort()
vod_short.vod_id = "msearch:" + item["id"]
if (item["title"] === undefined) {
vod_short.vod_name = item["target"]["title"]
} else {
vod_short.vod_name = item["title"]
}
if (item["pic"] === undefined) {
vod_short.vod_pic = item["target"]["cover_url"]
} else {
vod_short.vod_pic = item["pic"]["normal"]
}
if (item["rating"] === undefined) {
vod_short.vod_remarks = "评分:" + item["target"]["rating"]["value"].toString()
} else {
vod_short.vod_remarks = "评分:" + item["rating"]["value"].toString()
}
vod_list.push(vod_short);
}
return vod_list
}
get_tags(extend) {
let tag_list = []
for (const key of Object.keys(extend)) {
if (key !== "sort") {
tag_list.push(extend[key])
}
}
return tag_list.join(",")
}
sign(url, ts, method = 'GET') {
let _api_secret_key = "bf7dddc7c9cfe6f7"
let url_path = "%2F" + url.split("/").slice(3).join("%2F")
let raw_sign = [method.toLocaleUpperCase(), url_path, ts.toString()].join("&")
return Crypto.HmacSHA1(raw_sign, _api_secret_key).toString(Crypto.enc.Base64)
}
async setHomeVod() {
let url = this.siteUrl + "/subject_collection/subject_real_time_hotest/items"
let content = await this.fetch(url, {"apikey": this.apiKey}, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let items = content_json["subject_collection_items"]
this.homeVodList = await this.parseVodShortListFromJson(items)
}
}
async setCategory(tid, pg, filter, extend) {
let sort = extend["sort"] ?? "show_hot";
let tag_str = this.get_tags(extend)
this.count = 0
this.limit = 20;
this.total = 0;
let start = 0
if (parseInt(pg) > 1) {
start = (parseInt(pg) - 1) * this.limit
}
let cateUrl = ""
let params = {"start": start.toString(), "count": this.limit.toString()}
let itemKey = "items"
switch (tid) {
case "hot_gaia":
sort = extend["sort"] ?? "recommend"
let area = extend["area"] ?? "全部"
params["sort"] = sort
params["area"] = area
cateUrl = "/movie/hot_gaia"
break
case "tv_hot":
let type = extend["type"] ?? "tv_hot"
cateUrl = "/subject_collection/" + type + "/items"
itemKey = "subject_collection_items"
break
case "show_hot":
let showType = extend["type"] ?? "show_hot"
cateUrl = "/subject_collection/" + showType + "/items"
itemKey = "subject_collection_items";
break
case "movie":
params["sort"] = sort
params["tags"] = tag_str
cateUrl = "/movie/recommend"
break
case "tv":
params["sort"] = sort
params["tags"] = tag_str
cateUrl = "/tv/recommend"
break
case "rank_list_movie":
let rankMovieType = extend["榜单"] ?? "movie_real_time_hotest"
cateUrl = "/subject_collection/" + rankMovieType + "/items"
itemKey = "subject_collection_items"
break
case "rank_list_tv":
let rankTVType = extend["榜单"] ?? "tv_real_time_hotest"
cateUrl = "/subject_collection/" + rankTVType + "/items"
itemKey = "subject_collection_items"
break
default:
break
}
params["apikey"] = this.apiKey
let content = await this.fetch(this.siteUrl + cateUrl, params, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let items = content_json[itemKey]
this.vodList = await this.parseVodShortListFromJson(items)
}
}
async setSearch(wd, quick, pg) {
let _api_url = "https://frodo.douban.com/api/v2"
let _api_key = "0dad551ec0f84ed02907ff5c42e8ec70"
let url = _api_url + "/search/movie"
let date = new Date()
let ts = date.getFullYear().toString() + ('0' + (date.getMonth() + 1)).slice(-2).toString() + date.getDate().toString()
const limit = 20
let params = {
'_sig': this.sign(url, ts),
'_ts': ts,
'apiKey': _api_key,
'count': limit,
'os_rom': 'android',
'q': encodeURIComponent(wd),
'start': parseInt(pg)
}
let content = await this.fetch(url, params, this.getSearchHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
this.vodList = await this.parseVodShortListFromJson(content_json["items"])
const page = parseInt(pg);
let pageCount = page;
if (this.vodList.length === limit) {
pageCount = page + 1;
}
this.result.setPage(page, pageCount, limit, pageCount)
}
}
}
let spider = new DoubanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,75 +0,0 @@
/*
* @File : dubo.js
* @Author : jade
* @Date : 2024/4/16 18:46
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {TianTianSpider} from "./tiantian.js"
class DuboSpider extends TianTianSpider {
constructor() {
super();
this.siteUrl = "http://v.rbotv.cn"
this.cookie = ""
this.extendObj = {"extend": "类型", "area": "地区", "year": "年代"}
this.parseMap = {};
}
getName() {
return "🛶┃独播影视┃🛶"
}
getAppName() {
return "独播影视"
}
getJSName() {
return "dubo"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = false
}
}
let spider = new DuboSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,280 +0,0 @@
/*
* @File : dygangs.js
* @Author : jade
* @Date : 2024/2/21 15:06
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 电影港
*/
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {_, load} from "../lib/cat.js";
class MoviePortSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.dygangs.org"
}
getAppName() {
return "电影港"
}
getName() {
return "🏖️┃电影港┃🏖️"
}
getJSName() {
return "dygangs"
}
getType() {
return 3
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $($("[class=\"top-nav\"]")[0]).find("a")
for (const navElement of navElements) {
let type_id = navElement.attribs.href.replaceAll(this.siteUrl, "")
let type_name = $(navElement).text()
if (type_id !== "/") {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($, index) {
let element = $("[class=\"nav-down-2 clearfix\"]")[index]
let extend_list = []
if (element !== undefined) {
let name = "按类型"
let extend_dic = {"key": name, "name": name, "value": []}
extend_dic["name"] = name
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(element).find("a")) {
let type_name = $(ele).html()
let type_id = ele.attribs.href.split("/").slice(-2)[0]
extend_dic["value"].push({"n": type_name, "v": type_id})
}
extend_list.push(extend_dic)
}
return extend_list
}
async setFilterObj() {
let index = 0
for (const type_dic of this.classes.slice(1, 5)) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let url = this.siteUrl + `${type_id}`
let $ = await this.getHtml(url)
this.filterObj[type_id] = await this.getFilter($, index)
}
index = index + 1
}
}
parseVodShortFromElement($, element) {
let vodShort = new VodShort();
vodShort.vod_id = element.attribs.href
vodShort.vod_name = element.attribs.title
vodShort.vod_pic = $(element).find("img")[0].attribs["data-original"]
vodShort.vod_remarks = $($(element).find("i")[0]).text().replaceAll(" ", "").replaceAll("\n", "")
if (_.isEmpty(vodShort.vod_pic)){
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/dygang.jpg"
}
return vodShort
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"index-tj-l\"]").find("li")
for (const vodElement of vodElements) {
let vodShortElement = $(vodElement).find("a")[0]
let vodShort = this.parseVodShortFromElement($, vodShortElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $("[class=\"index-area clearfix\"]").find("li")
for (const vodElement of vodElements) {
let vodShortElement = $(vodElement).find("a")[0]
let vodShort = this.parseVodShortFromElement($, vodShortElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let vodDetailElement = $("[ class=\"ct mb clearfix\"]")
vodDetail.vod_pic = $(vodDetailElement).find("img")[0].attribs["src"]
vodDetail.vod_name = Utils.getStrByRegex(/◎片  名 (.*?)<br>/, $(vodDetailElement).html())
vodDetail.vod_area = Utils.getStrByRegex(/◎产  地 (.*?)<br>/, $(vodDetailElement).html())
vodDetail.vod_year = Utils.getStrByRegex(/◎年  代 (.*?)<br>/, $(vodDetailElement).html())
vodDetail.type_name = Utils.getStrByRegex(/◎类  别 (.*?)<br>/, $(vodDetailElement).html())
vodDetail.vod_remarks = Utils.getStrByRegex(/◎集  数 (.*?)<br>/, $(vodDetailElement).html())
let content = Utils.getStrByRegex(/   (.*?)<\/p>/s, $(vodDetailElement).html())
if (_.isEmpty(content)) {
content = Utils.getStrByRegex(/   (.*?)<\/p>/s, $(vodDetailElement).html())
}
let actor_list = []
for (const actor of content.split("\n")) {
actor_list.push(actor.replaceAll("    &nbsp;  ", "").replaceAll("<br>", "").replaceAll("     ", ""))
}
vodDetail.vod_actor = actor_list.join("/")
vodDetail.vod_director = Utils.getStrByRegex(/◎导  演 (.*?)<br>/, $(vodDetailElement).html())
vodDetail.vod_content = Utils.getStrByRegex(/  <\/p>(.*?)<br>/s, $(vodDetailElement).html()).replaceAll("<p>", "").replaceAll("\n", "")
if (_.isEmpty(vodDetail.vod_content)) {
vodDetail.vod_content = Utils.getStrByRegex(/  <br>(.*?)<\/p>/s, $(vodDetailElement).html()).replaceAll("<p>", "").replaceAll("\n", "")
}
let vod_play_from_list = []
let vod_play_list = []
let playFormatElements = $("[class=\"playfrom tab8 clearfix\"]")
let playUrlElements = $("[class=\"videourl clearfix\"]")
for (let i = 0; i < playFormatElements.length; i++) {
let playFormatElement = playFormatElements[i]
let format_name = $($(playFormatElement).find("li")).html()
vod_play_from_list.push(format_name.replaceAll("<i class=\"playerico ico-Azhan\"></i> ", ""))
let vodItems = []
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = playUrlElement.attribs.title
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
let playFormatElement = $($(vodDetailElement).find("span")[0]).find("span")
if (playFormatElement.length > 0) {
let format_name = $(playFormatElement).html()
vod_play_from_list.push(Utils.getStrByRegex(/【(.*?)】/, format_name.replaceAll("下载地址", "磁力链接")))
let vodItems = []
for (const playUrlElement of $($($(vodDetailElement).find("tbody")).find("tr")).find("a")) {
let episodeName = $(playUrlElement).html().replaceAll(".mp4", "")
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let url = this.siteUrl + tid
if (extend["按类型"] !== undefined && extend["按类型"] !== "0") {
url = url + `${extend["按类型"]}/`
}
if (parseInt(pg) > 1) {
url = url + `index_${pg}.html`
}
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/e/search/index.php"
let params = {"keyboard": wd, "submit": "搜 索", "show": "title,zhuyan", "tempid": "1"}
let resp = await this.post(url, params, this.getHeader())
let $ = load(resp)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setPlay(flag, id, flags) {
if (id.indexOf("http") > -1) {
let $ = await this.getHtml(id)
let url = Utils.getStrByRegex(/url: '(.*?)',/, $.html())
if (_.isEmpty(url)) {
let videoUrl = $($("[class=\"video\"]")[0]).find("iframe")[0].attribs["src"]
let html = await this.fetch(videoUrl, null, {"User-Agent": Utils.CHROME})
this.playUrl = Utils.getStrByRegex(/url: '(.*?)',/, html)
if (_.isEmpty(this.playUrl)){
let urlHost = Utils.getHost(videoUrl)
this.playUrl = urlHost + Utils.getStrByRegex(/var main = "(.*?)";/, html)
}
} else {
this.playUrl = url
}
} else {
this.playUrl = id
}
}
}
let spider = new MoviePortSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,214 +0,0 @@
/*
* @File : freeok.js
* @Author : jade
* @Date : 2024/1/19 10:26
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 电影天堂(已失效)
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class DyttSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.dy2018.com"
this.dyttReconnectTimes = 0
}
getName() {
return `👼┃电影天堂BT┃👼`
}
getAppName() {
return "电影天堂BT"
}
getJSName() {
return "dyttbt"
}
getType() {
return 3
}
// getHeader() {
// return {"User-Agent": "PostmanRuntime/7.36.1", "Host":"www.dy2018.com"};
// }
async getHtml(url = this.siteUrl, headers = this.getHeader()) {
try {
let buffer = await this.fetch(url, null, headers, false, false, 1)
let html = Utils.decode(buffer, "gb2312")
if (!_.isEmpty(html) && Utils.getStrByRegex(/<script src="(.*?)"><\/script>/, html) !== "/_guard/auto.js") {
return load(html)
} else {
if (this.dyttReconnectTimes < this.maxReconnectTimes) {
Utils.sleep(2)
this.dyttReconnectTimes = this.dyttReconnectTimes + 1
return await this.getHtml(url, headers)
} else {
await this.jadeLog.error(`html获取失败`, true)
}
}
} catch (e) {
await this.jadeLog.error(`获取html出错,出错原因为${e}`)
}
}
async setFilterObj() {
}
async setClasses() {
let $ = await this.getHtml()
let vodShortElements = $("[class=\"title_all\"]")
for (const vodShortElement of vodShortElements) {
let spanElement = $(vodShortElement).find("span")[0]
let aElement = $(vodShortElement).find("a")[0]
let type_name = $(spanElement).text()
let type_id = aElement.attribs["href"]
if (type_id.indexOf("https:") === -1 && type_id.indexOf("http:") === -1) {
type_id = this.siteUrl + type_id
}
this.classes.push(this.getTypeDic(type_name, type_id))
}
let containElements = $($("[id=\"menu\"]").find("[class=\"contain\"]")).find("a").slice(0, -3)
for (const contaElement of containElements) {
let type_name = $(contaElement).text()
let type_id = contaElement.attribs["href"]
if (type_id.indexOf("https:") === -1 && type_id.indexOf("http:") === -1) {
type_id = this.siteUrl + type_id
}
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodShortElements = $($("[class=\"co_content8\"]")[0]).find("tbody")
for (const vodShortElement of vodShortElements) {
let vodShort = new VodShort()
let vodElements = $(vodShortElement).find("tr")
vodShort.vod_name = Utils.getStrByRegex(/《(.*?)》/, $(vodElements[1]).text())
vodShort.vod_id = $(vodElements[1]).find("a").slice(-1)[0].attribs.href
vodShort.vod_remarks = "日期:" + Utils.getStrByRegex(/日期:(.*?) /, $(vodElements[2]).text()) + " 热度:" + Utils.getStrByRegex(/点击:(.*?) /, $(vodElements[2]).text())
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/dytt.jpg"
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodShortElements = $($("[class=\"co_area2\"]")[0]).find("li").slice(1)
for (const vodShortElement of vodShortElements) {
let vodShort = new VodShort()
let vodElement = $(vodShortElement).find("a")[0]
vodShort.vod_id = vodElement.attribs["href"]
vodShort.vod_name = Utils.getStrByRegex(/《(.*?)》/, vodElement.attribs["title"])
vodShort.vod_remarks = $($(vodShortElement).find("span")).text().replaceAll("", "")
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/dytt.jpg"
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
vodDetail.vod_name = Utils.getStrByRegex(/《(.*?)》/, Utils.getStrByRegex(/<title>(.*?)<\/title>/, $.html()))
let zoomElement = $("[id=\"Zoom\"]")
vodDetail.vod_pic = $(zoomElement).find("img")[0].attribs.src
let content = $(zoomElement).text()
vodDetail.vod_year = Utils.getStrByRegex(/年  代 (.*?)◎/, content)
vodDetail.type_name = Utils.getStrByRegex(/类  别 (.*?)◎/, content)
vodDetail.vod_area = Utils.getStrByRegex(/产  地 (.*?)◎/, content)
vodDetail.vod_director = Utils.getStrByRegex(/导  演 (.*?)◎/, content)
vodDetail.vod_content = Utils.getStrByRegex(/简  介 (.*?)◎/, content)
vodDetail.vod_actor = Utils.getStrByRegex(/主  演(.*?)◎/, content).replaceAll("      ", "*")
vodDetail.vod_remarks = Utils.getStrByRegex(/豆瓣评分 (.*?)\//, content)
vodDetail.vod_play_from = "磁力链接"
let playList = $(zoomElement).find("[class=\"player_list\"]").find("a")
let vodItems = []
for (const playEle of playList) {
vodItems.push($(playEle).text() + "$" + playEle.attribs.href);
}
vodDetail.vod_play_url = [vodItems.join("#")].join("$$$")
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let cateUrl = tid
if (tid.indexOf("index") > -1){
cateUrl = tid.split(".html")[0] + "_" + pg + ".html"
}
let $ = await this.getHtml(cateUrl)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
let spider = new DyttSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

View File

@ -1,96 +0,0 @@
/*
* @File : feifan.js
* @Author : jade
* @Date : 2024/02/06 14:58
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 非凡资源
*/
import {VodSpider} from "./vodSpider.js";
class FeiFanSpider extends VodSpider {
constructor() {
super();
this.siteUrl = "http://cj.ffzyapi.com"
this.remove18 = true
this.type_id_18 = 34
}
getAppName() {
return "非凡资源"
}
getName() {
return "🥗┃非凡资源┃🥗"
}
getJSName() {
return "feifan"
}
getType() {
return 3
}
async spiderInit(inReq) {
await super.spiderInit(inReq);
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
}
let spider = new FeiFanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,96 +0,0 @@
/*
* @File : feifan.js
* @Author : jade
* @Date : 2024/02/06 14:58
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 非凡资源
*/
import {VodSpider} from "./vodSpider.js";
class FeiFan18Spider extends VodSpider {
constructor() {
super();
this.siteUrl = "http://cj.ffzyapi.com"
this.remove18 = false
this.type_id_18 = 34
}
getAppName() {
return "非凡资源18+"
}
getName() {
return "🔞┃非凡资源18+┃🔞"
}
getJSName() {
return "feifan18"
}
getType() {
return 3
}
async spiderInit(inReq) {
await super.spiderInit(inReq);
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
}
let spider = new FeiFan18Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,333 +0,0 @@
/*
* @File : freeok.js
* @Author : jade
* @Date : 2024/1/19 10:26
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : OK资源网 已失效
*/
import {_} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {player} from "../lib/freeok_setttings.js";
const OCR_API = 'https://api.nn.ci/ocr/b64/text';//ocr在线识别接口
class OkSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.freeok.vip"
}
getName() {
return `🆗┃OK资源网┃🆗`
}
getAppName() {
return `OK资源网`
}
getJSName() {
return "freeok"
}
getType() {
return 3
}
async init(cfg) {
this.cookie = await this.load_cache()
await super.init(cfg);
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $($("[class=\"module\"]")).find("a").slice(0, 12)
for (const vodElement of vodElements) {
vod_list.push(this.parseVodShortFromElement($, vodElement))
}
return vod_list
}
parseVodShortFromElement($, element) {
let vodShort = new VodShort();
vodShort.vod_name = element.attribs["title"]
vodShort.vod_id = element.attribs["href"]
vodShort.vod_remarks = $($(element).find("[class=\"module-item-note\"]")).text()
vodShort.vod_pic = $(element).find("[class=\"lazy lazyload\"]")[0].attribs["data-original"]
return vodShort
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let itemElements = $($("[class=\"module-items module-poster-items-base \"]")).find("a")
for (const itemElement of itemElements) {
vod_list.push(this.parseVodShortFromElement($, itemElement))
}
return vod_list
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const result of obj["Data"]["result"]){
let vodShort = new VodShort()
vodShort.vod_id = result["vod_url"].replaceAll(this.siteUrl,"")
vodShort.vod_pic = result["vod_pic"]
vodShort.vod_name = result["vod_name"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByHot($) {
let vod_list = []
let itemElement = $($("[class=\"module-items module-card-items\"]"))[0]
let titleElements = $(itemElement).find("[class=\"module-card-item-title\"]").find("a")
let infoElements = $(itemElement).find("[class=\"module-card-item-info\"]")
let picElements = $(itemElement).find("[class=\"module-item-pic\"]").find("img")
for (let i = 0; i < titleElements.length; i++) {
let vodShort = new VodShort();
vodShort.vod_id = titleElements[i].attribs["href"]
vodShort.vod_name = $(titleElements[i]).text()
vodShort.vod_pic = picElements[i].attribs["data-original"]
vodShort.vod_remarks = $($(infoElements[i])).text().split("\n")[5]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let moudleElements = $("[class=\"module-info-tag-link\"]").find("a")
let mobilePlay = $("[class=\"module-mobile-play\"]").find("a")[0]
vodDetail.vod_name = mobilePlay.attribs["title"].replaceAll("立刻播放", "")
vodDetail.vod_content = $($("[class=\"module-info-introduction-content\"]")).text().replaceAll("\n", "").replaceAll(" ", "")
let type_list = []
for (const moudleElement of moudleElements.slice(2)) {
type_list.push($(moudleElement).text())
}
vodDetail.type_name = type_list.join("/")
vodDetail.vod_year = $(moudleElements[0]).text()
vodDetail.vod_area = $(moudleElements[1]).text()
let itemElements = $("[class=\"module-info-item\"]")
let itemText = ""
for (const itemElement of itemElements) {
itemText = itemText + $(itemElement).text().replaceAll("\n", "").replaceAll("", ":") + "\n"
}
vodDetail.vod_pic = $("[class=\"module-item-pic\"]").find("img")[0].attribs["data-original"]
vodDetail.vod_director = Utils.getStrByRegex(/导演:(.*?)\n/, itemText)
vodDetail.vod_actor = Utils.getStrByRegex(/主演:(.*?)\n/, itemText)
vodDetail.vod_year = Utils.getStrByRegex(/上映:(.*?)\n/, itemText)
vodDetail.vod_remarks = Utils.getStrByRegex(/备注:(.*?)\n/, itemText)
if (_.isEmpty(vodDetail.vod_remarks)) {
vodDetail.vod_remarks = Utils.getStrByRegex(/集数:(.*?)\n/, itemText)
}
let playElements = $($("[class=\"module-tab-items-box hisSwiper\"]")).find("span")
let play_from_list = []
let playUrlElements = $("[class=\"module-list sort-list tab-list his-tab-list\"]")
let play_url_list = []
for (let i = 0; i < playElements.length; i++) {
let text = $(playElements[i]).text()
if (text.indexOf("夸克") === -1) {
let playDetailElements = $(playUrlElements[i]).find("a")
let vodItems = []
for (const playDetailElement of playDetailElements) {
let play_name = playDetailElement.attribs["title"].replaceAll("播放", "").replaceAll(vodDetail.vod_name, "")
let play_url = playDetailElement.attribs["href"]
vodItems.push(`${play_name}$${play_url}`)
}
play_url_list.push(vodItems.join("#"))
play_from_list.push($(playElements[i]).text())
}
}
vodDetail.vod_play_from = play_from_list.join("$$$")
vodDetail.vod_play_url = play_url_list.join("$$$")
return vodDetail
}
async setClasses() {
let $ = await this.getHtml(this.siteUrl, this.getHeader())
let navElements = $($("[class=\"navbar-items swiper-wrapper\"]")).find("a")
let type_name = $(navElements.slice(0, 8).slice(-1)[0]).text().replaceAll("\n", "")
let type_id = navElements.slice(0, 8).slice(-1)[0].attribs["href"]
this.classes.push({"type_name": type_name, "type_id": type_id})
for (const navElement of navElements.slice(0, 8)) {
let type_name = $(navElement).text().replaceAll("\n", "")
if (type_name !== "首页" && type_name !== "热榜") {
let type_id = navElement.attribs["href"].split("/").slice(-1)[0].split(".")[0]
this.classes.push({"type_name": type_name, "type_id": type_id})
}
}
}
async getFilter($) {
let titleElements = $("[class=\"module-item-title\"]")
let boxElements = $("[class=\"module-item-box\"]")
let extend_list = []
let type_id_dic = {"类型": 1, "剧情": 4, "地区": 2, "语言": 5, "年份": 12, "排序": 3}
for (let i = 0; i < titleElements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": $(titleElements[i]).text(), "value": []}
let typeElements = $(boxElements[i]).find("a")
for (let j = 0; j < typeElements.length; j++) {
let type_name = $(typeElements[j]).text()
let type_id = decodeURIComponent(typeElements[j].attribs["href"].split("-")[type_id_dic[$(titleElements[i]).text()]]).replaceAll(".html", "")
extend_dic["value"].push({"n": type_name, "v": $(titleElements[i]).text() + "-" + type_id})
}
extend_list.push(extend_dic)
}
return extend_list;
}
async setFilterObj() {
for (const class_dic of this.classes) {
if (class_dic["type_name"] !== "最近更新" && class_dic["type_name"] !== "热榜") {
let cateUrl = this.siteUrl + `/vod-show/${class_dic["type_id"]}--------1---.html`
let $ = await this.getHtml(cateUrl, this.getHeader())
this.filterObj[class_dic["type_id"]] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl, this.getHeader())
this.homeVodList = await this.parseVodShortListFromDoc($)
}
getCateUrl(tid, pg, extend) {
let value_list = Object.values(extend)
let type_id_dic = {"类型": 1, "剧情": 3, "地区": 1, "语言": 4, "年份": 11, "排序": 2}
let urlParams = [tid.toString(), "", "","","", "", "", "", "", "", "",""]
urlParams[8] = pg.toString()
for (const value of value_list) {
if (value.split("-")[0] === "类型") {
urlParams[0] = value.split("-")[1].split("show/")[1].toString()
} else {
let type_index = type_id_dic[value.split("-")[0]]
urlParams[type_index] = value.split("-")[1]
}
}
return this.siteUrl + `/vod-show/` + urlParams.join("-") + ".html"
}
async setCategory(tid, pg, filter, extend) {
let cateUrl
if (tid.indexOf(".html") > -1) {
cateUrl = this.siteUrl + tid
let $ = await this.getHtml(cateUrl, this.getHeader());
this.vodList = await this.parseVodShortListFromDocByHot($)
} else {
cateUrl = this.getCateUrl(tid, pg, extend)
let $ = await this.getHtml(cateUrl, this.getHeader());
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
}
async setSearch(wd, quick) {
let url = `http://123.207.150.253/zxapi/public/?service=App.F.Fetch&req_p=${wd}&type=okys`
let content = await this.fetch(url,null,this.getHeader())
this.vodList = await this.parseVodShortListFromJson(JSON.parse(content))
}
async refreshCookie() {
let passUrl = this.siteUrl + "/index.php/verify/index.html?"
let passHtml = await this.fetch(passUrl,null,this.getHeader(),false,true)
let response2 = await this.post(OCR_API,passHtml["content"],this.getHeader())
this.cookie = Utils.getStrByRegex(/(.*?);/,passHtml["cookie"])
let verifyUrl = this.siteUrl + "/index.php/ajax/verify_check?type=search&verify=5286"
let headers = this.getHeader()
headers["cookie"] = this.cookie
let response = await this.post(verifyUrl,null,headers)
await this.write_cache()
}
async load_cache() {
try {
return await local.get("freeok_cookie", "cookie")
} catch (e) {
return ""
}
}
async write_cache() {
await local.set("freeok_cookie", "cookie", JSON.stringify(this.cookie))
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id, this.getHeader())
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(this.siteUrl + id, this.getHeader())
const js = JSON.parse($('script:contains(player_)').html().replace('var player_aaaa=', ''));
let url = this.siteUrl + "/okplayer/"
let params = {
"url": decodeURIComponent(js.url), "next": decodeURIComponent(js.url_next), "title": js.vod_data.vod_name
}
let playHtml = await this.fetch(url, params, this.getHeader());
let view_port_id = Utils.getStrByRegex(/<meta name="viewport"(.*?)>/, playHtml).split("id=\"")[1].replaceAll("now_", "")
let player_id = Utils.getStrByRegex(/meta charset="UTF-8" id="(.*?)">/, playHtml).replaceAll("now_", "")
let player_url = Utils.getStrByRegex(/"url": "(.*?)",/, playHtml)
this.playUrl = player(player_url, view_port_id, player_id)
}
}
let spider = new OkSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

View File

@ -1,228 +0,0 @@
/*
* @File : gitcafe.js
* @Author : jade
* @Date : 2024/1/18 9:56
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 阿里纸条
*/
import {_, load} from "../lib/cat.js";
import {Spider} from "./spider.js";
import {detailContent, initAli, playContent} from "../lib/ali.js";
import * as Utils from "../lib/utils.js";
import {VodDetail, VodShort} from "../lib/vod.js";
class GitCafeSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://ali.gitcafe.ink"
}
getName() {
return "🦊┃阿里纸条┃🦊"
}
getAppName() {
return "阿里纸条"
}
getJSName() {
return "gitcafe"
}
getType() {
return 3
}
async getApiUrl() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let paper_js_url = Utils.getStrByRegex(/<script src='(.*?)'><\/script>/, html)
let paper_js_content = await this.fetch(paper_js_url, null, this.getHeader())
return {
"api": "https:" + Utils.getStrByRegex(/ return '(.*?)' \+ /, paper_js_content) + new Date().getTime(),
"search_api": Utils.getStrByRegex(/const SEARCH_API = '(.*?)';/, paper_js_content)
}
}
}
async getContentJson() {
let url_json = await this.getApiUrl()
let content = await this.fetch(url_json["api"], null, this.getHeader())
this.search_api = url_json["search_api"]
if (!_.isEmpty(content)) {
return JSON.parse(content)
}
}
async spiderInit() {
this.content_json = await this.getContentJson()
this.token_dic = await this.load_cache()
}
async init(cfg) {
await this.spiderInit()
await super.init(cfg);
await initAli(this.cfgObj["token"]);
}
async parseClassFromJson(obj) {
let data_list = Object.keys(obj["data"]).slice(0, 19)
for (const data_key of data_list) {
this.classes.push({"type_name": obj["data"][data_key]["name"], "type_id": data_key})
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
let class_id_list = this.getClassIdList()
for (const data_obj of obj) {
let vodShort = new VodShort()
if (class_id_list.includes(data_obj["cat"])) {
vodShort.vod_id = JSON.stringify(data_obj)
vodShort.vod_name = data_obj["title"]
vodShort.vod_remarks = data_obj["date"]
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailfromJson(obj) {
let classNamesList = this.getClassNameList()
let classIdList = this.getClassIdList()
let vodDetail = new VodDetail()
vodDetail.vod_name = obj["title"]
vodDetail.vod_remarks = obj["creatime"] ?? obj["date"]
vodDetail.type_name = classNamesList[classIdList.indexOf(obj["cat"])]
vodDetail.vod_content = obj["des"]
let ali_url = "https://www.aliyundrive.com/s/" + obj["alikey"]
let aliVodDetail = await detailContent([ali_url])
vodDetail.vod_play_url = aliVodDetail.vod_play_url
vodDetail.vod_play_from = aliVodDetail.vod_play_from
return vodDetail
}
async setClasses() {
await this.parseClassFromJson(this.content_json)
}
async setHomeVod() {
this.homeVodList = await this.parseVodShortListFromJson(this.content_json["info"]["new"])
}
async setDetail(id) {
let content_json = JSON.parse(id)
this.vodDetail = await this.parseVodDetailfromJson(content_json)
}
async setCategory(tid, pg, filter, extend) {
this.vodList = await this.parseVodShortListFromJson(this.content_json["data"][tid]["catdata"])
}
async setSearch(wd, quick) {
await this.refreshToken();
let params = {
"action": "search", "from": "web", "token": this.token_dic["token"], "keyword": wd
}
let content = await this.post(this.search_api, params, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
this.vodList = await this.parseVodShortListFromJson(content_json["data"])
}
}
async refreshToken() {
let this_time = new Date().getTime()
if (_.isEmpty(this.token_dic["token"])) {
await this.get_token()
await this.jadeLog.debug("Token为空,刷新Token")
} else if (this_time - parseInt(this.token_dic["date"]) > 24 * 60 * 60 * 1000) {
await this.jadeLog.debug(`Token到期,上次获取Token时间为:${this_time},当前时间为:${parseInt(this.token_dic["date"])},刷新Token`)
await this.get_token()
} else {
await this.jadeLog.debug(`Token仍然有效,无需刷新`, true)
}
}
async get_token() {
try {
let params = {
"action": "get_token", "from": "web",
}
let content = await this.post(this.search_api, params, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let this_time = new Date().getTime()
this.token_dic["token"] = content_json["data"]
this.token_dic["date"] = this_time.toString()
await this.write_cache()
}
} catch (e) {
await this.jadeLog.error("获取Token失败,失败原因为:" + e)
}
}
async write_cache() {
await local.set("gitcafe_token", "token", JSON.stringify(this.token_dic))
}
async load_cache() {
try {
let str = await local.get("gitcafe_token", "token")
return JSON.parse(str)
} catch (e) {
return {"token": "", "date": ""}
}
}
async play(flag, id, flags) {
return await playContent(flag, id, flags);
}
}
let spider = new GitCafeSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,156 +0,0 @@
/*
* @File : haiwaikan.js
* @Author : jade
* @Date : 2024/04/02 9:15
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 海外看
*/
import {VodSpider} from "./vodSpider.js";
class HaiWaiKanSpider extends VodSpider {
constructor() {
super();
this.siteUrl = "https://haiwaikan.com"
this.remove18 = true
this.type_id_18 = 0
}
async spiderInit(inReq) {
await super.spiderInit(inReq);
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
getAppName() {
return "海外看"
}
getName() {
return "☕┃海外看┃☕墙"
}
getJSName() {
return "haiwaikan"
}
getType() {
return 3
}
async setClasses() {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod/from", {"ac": "list"}, this.getHeader())
let content_json = JSON.parse(content)
for (const class_dic of content_json["class"]) {
if (class_dic["type_id"] < 26 ) {
this.classes.push(this.getTypeDic(class_dic["type_name"], class_dic["type_id"].toString()))
}
}
this.content_json = content_json
}
async getFilter(type_id,obj) {
let extend_list = []
let extend_dic = {"key": "1", "name": "全部类别", "value": [{"n":"全部类别","v":type_id.toString()}]}
for (const type_dic of obj["class"]){
let a_type_id = type_dic["type_id"]
let max_type_id = 0
let min_type_id = 0
if (type_id === 20){
max_type_id = 50
min_type_id = 27
}
if (type_id === 21){
max_type_id = 128
min_type_id = 100
}
if (type_id === 22){
max_type_id = 143
min_type_id = 134
}
if (type_id === 23){
max_type_id = 135
min_type_id = 127
}
if (a_type_id < max_type_id && a_type_id > min_type_id){
extend_dic["value"].push({"n":type_dic["type_name"],"v":a_type_id.toString()})
}
}
if (extend_dic["value"].length > 1){
extend_list.push(extend_dic)
return extend_list
}else{
return null
}
}
async setFilterObj() {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod/from", {"ac": "list"}, this.getHeader())
let content_json = JSON.parse(content)
for (const type_dic of this.classes){
let type_id = type_dic["type_id"]
if (type_id !== "最近更新"){
let extend_list = await this.getFilter(parseInt(type_id),content_json)
if (extend_list !== null){
this.filterObj[type_id] = extend_list
}
}
}
}
}
let spider = new HaiWaiKanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,625 +0,0 @@
/*
* @File : hanxiucao.js
* @Author : jade
* @Date : 2024/04/13 19:38
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, Crypto} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import {Spider} from "./spider.js";
import * as Utils from "../lib/utils.js";
function He(e, {key: t, iv: s} = {}) {
let VITE_APP_AES_KEY = "B77A9FF7F323B5404902102257503C2F"
let VITE_APP_AES_IV = "B77A9FF7F323B5404902102257503C2F"
var o = Crypto.enc.Utf8.parse(e)
, A = Crypto.AES.encrypt(o, Crypto.enc.Utf8.parse(t || VITE_APP_AES_KEY), {
iv: Crypto.enc.Utf8.parse(s || VITE_APP_AES_IV),
mode: Crypto.mode.CBC,
padding: Crypto.pad.Pkcs7
});
return Crypto.enc.Base64.stringify(A.ciphertext)
}
function Kt() {
const e = new Date;
return He(parseInt(e.getTime() / 1e3) + e.getTimezoneOffset() * 60 + -1)
}
function bt(e) {
const wA = "46cc793c53dc451b"
let t = Crypto.enc.Utf8.parse(wA)
, s = Crypto.AES.decrypt(e, t, {
mode: Crypto.mode.ECB,
padding: Crypto.pad.Pkcs7
});
return Crypto.enc.Utf8.stringify(s).toString()
}
class HanXiuCaoSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.qianyuewenhua.xyz"
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "imgBt", this.getHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'imgBt/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
await this.spiderInit(null)
}
getAppName() {
return "含羞草"
}
getName() {
return "🔞┃含羞草┃🔞"
}
getJSName() {
return "hanxiucao"
}
getType() {
return 3
}
getParams(params) {
return {"endata": He(JSON.stringify(params)), "ents": Kt()}
}
async setClasses() {
let params = this.getParams({"channel": "pc"})
let response = await this.post(this.siteUrl + "/panel/list", params, this.getHeader(), "")
let resJson = JSON.parse(response)
for (const data of resJson["data"]["list"]) {
let type_id = data["panelId"]
let type_name = data["panelName"]
if (type_name !== "首页") {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter(Layouts) {
let extend_list = []
for (const data of Layouts) {
let layoutObj = JSON.parse(data["layoutContent"])
for (const layout of layoutObj["sortKeys"]) {
let extend_dic = {}
if (layout["label"] !== "综合排序") {
extend_dic = {"key": "sorts", "name": layout["label"].toString(), value: []}
extend_dic["value"].push({"n": "升序", "v": layout["value"].toString() + "-" + "升序"})
extend_dic["value"].push({"n": "降序", "v": layout["value"].toString() + "-" + "降序"})
} else {
extend_dic = {"key": "sorts", "name": "排序", value: []}
extend_dic["value"].push({"n": layout["label"].toString(), "v": layout["value"].toString()})
}
extend_list.push(extend_dic)
}
}
return extend_list
}
async getNvYouFilter(Layouts) {
let extend_list = []
let params = {
"uids": [],
"page": 1,
"length": 20
}
for (let i = 0; i < Layouts.length; i++) {
let data = Layouts[i]
let layoutObj = JSON.parse(data["layoutContent"])
params["uids"] = layoutObj["list"]
let resJson = JSON.parse(await this.post(this.siteUrl + "/user/getUpList", this.getParams(params), this.getHeader(), ""))
let extend_dic = {"key": `tags`, "name": data["layoutName"], value: []}
for (const layout of resJson["data"]["list"]) {
extend_dic["value"].push({"n": layout["user_nicename"], "v": JSON.stringify(layout)})
}
extend_list.push(extend_dic)
}
let sort_list = [
{
"key": "sorts",
"name": "发布时间",
"value": [
{
"n": "升序",
"v": "1-升序"
},
{
"n": "降序",
"v": "1-降序"
}
]
},
{
"key": "sorts",
"name": "点赞数量",
"value": [
{
"n": "升序",
"v": "5-升序"
},
{
"n": "降序",
"v": "5-降序"
}
]
},
{
"key": "sorts",
"name": "收藏数量",
"value": [
{
"n": "升序",
"v": "6-升序"
},
{
"n": "降序",
"v": "6-降序"
}
]
}
]
return [...extend_list, ...sort_list]
}
async getZhuanTiFilter(Layouts) {
let extend_list = []
let params = {
"page": 1,
"length": 36,
"subjectIds": []
}
for (let i = 0; i < Layouts.length; i++) {
let data = Layouts[i]
let layoutObj = JSON.parse(data["layoutContent"])
params["subjectIds"] = layoutObj["list"]
let resJson = JSON.parse(await this.post(this.siteUrl + "/subject/list", this.getParams(params), this.getHeader(), ""))
let extend_dic = {"key": `tags`, "name": data["layoutName"], value: []}
for (const layout of resJson["data"]["list"]) {
extend_dic["value"].push({"n": layout["name"], "v": JSON.stringify(layout)})
}
extend_list.push(extend_dic)
}
let sort_dic = {
"key": "sorts",
"name": "排序",
"value": [
{
"n": "推荐",
"v": "8"
},
{
"n": "最新",
"v": "1"
},
{
"n": "最热",
"v": "2"
}
]
}
extend_list.push(sort_dic)
return extend_list
}
async getChuanMeiFilter(Layouts) {
let extend_list = []
let extend_dic = {"key": `tags`, "name": "传媒", value: []}
for (let i = 0; i < Layouts.length; i++) {
let data = Layouts[i]
extend_dic["value"].push({"n": data["layoutName"], "v": data["layoutContent"]})
}
extend_list.push(extend_dic)
for (const layout of JSON.parse(Layouts[0]["layoutContent"])["moreOrderType"]) {
extend_dic = {"key": "sorts", "name": layout["label"].toString(), value: []}
extend_dic["value"].push({"n": "升序", "v": layout["value"].toString() + "-" + "升序"})
extend_dic["value"].push({"n": "降序", "v": layout["value"].toString() + "-" + "降序"})
extend_list.push(extend_dic)
}
extend_list.push(extend_dic)
return extend_list
}
async getHeJiFilter(Layouts) {
let extend_list = []
let params = {
"page": 1,
"length": 24,
"gatherType": 1,
"gatherIds": []
}
let extend_dic = {"key": `tags`, "name": "合集", value: []}
let resJson = JSON.parse(await this.post(this.siteUrl + "/gather/getList", this.getParams(params), this.getHeader(), ""))
for (const data of resJson["data"]["list"]) {
extend_dic["value"].push({"n": data["name"], "v": data["gatherId"].toString()})
}
extend_list.push(extend_dic)
return extend_list
}
async setFilterObj() {
for (let i = 0; i < this.classes.length; i++) {
let type_dic = this.classes[i]
let type_id = type_dic["type_id"]
let type_name = type_dic["type_name"]
let filterList = []
if (type_id !== "最近更新") {
type_id = parseInt(type_id)
let params = this.getParams({"panelId": type_id})
let response = await this.post(this.siteUrl + "/panel/get", params, this.getHeader(), "")
let resJson = JSON.parse(response)
let layoutList = resJson["data"]["info"]["Layouts"]
let layOutObj = JSON.parse(resJson["data"]["info"]["Layouts"][0]["layoutContent"])
if (type_id > 174 && type_id < 181) {
let layOutObj = JSON.parse(resJson["data"]["info"]["Layouts"][0]["layoutContent"])
type_id = type_id + "$" + JSON.stringify(layOutObj)
filterList = await this.getFilter(layoutList)
} else {
switch (type_id) {
case 172:
filterList = await this.getHeJiFilter(layoutList)
type_id = type_id + "$" + filterList[0]["value"][0]["v"]
break
case 173:
filterList = await this.getChuanMeiFilter(layoutList)
type_id = type_id + "$" + JSON.stringify(layOutObj)
break
case 182:
filterList = await this.getNvYouFilter(layoutList)
type_id = type_id + "$" + filterList[0]["value"][0]["v"]
break
case 209:
filterList = await this.getZhuanTiFilter(layoutList)
type_id = type_id + "$" + filterList[0]["value"][0]["v"]
break
default:
break
}
}
this.classes[i] = this.getTypeDic(type_name, type_id)
this.filterObj[type_id] = filterList
}
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const data of obj) {
let vodShort = new VodShort()
vodShort.vod_id = data["id"]
vodShort.vod_name = data["name"]
vodShort.vod_pic = this.jsBase + Utils.base64Encode(data["coverImgUrl"])
if (data["hot"] === undefined) {
vodShort.vod_remarks = "观看:" + (data["seeCount"] / 10000).toFixed(1).toString() + "W"
} else {
vodShort.vod_remarks = "热度:" + (data["hot"] / 1000).toFixed(1).toString() + "K"
}
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromGatherJson(obj) {
let vod_list = []
for (const data of obj) {
let vodShort = new VodShort()
vodShort.vod_id = data["gatherId"]
vodShort.vod_name = data["name"]
vodShort.vod_pic = this.jsBase + Utils.base64Encode(data["coverImgUrl"])
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc(detailObj) {
let vodDetail = new VodDetail()
vodDetail.vod_name = detailObj["name"]
vodDetail.vod_year = detailObj["addTime"]
vodDetail.vod_pic = this.jsBase + Utils.base64Encode(detailObj["coverImgUrl"])
vodDetail.type_name = detailObj["typeName"]
vodDetail.vod_content = detailObj["tags"]
let vodItems = []
let params = {
"videoId": detailObj["id"]
}
let resJson = JSON.parse(await this.post(this.siteUrl + "/videos/getPreUrl", this.getParams(params), this.getHeader(), ""))
let playList = resJson["data"]["url"].split("?")
let playUrl = playList[0] + "?sign" + playList[1].split("&sign").slice(-1)[0]
vodItems.push(vodDetail.vod_name + "$" + playUrl)
let playObj = {"线路1": vodItems.join("#")}
vodDetail.vod_play_url = _.values(playObj).join('$$$');
vodDetail.vod_play_from = _.keys(playObj).join('$$$');
return vodDetail
}
async getHomeVod(params) {
let params_str = this.getParams(params)
let response = await this.post(this.siteUrl + "/videos/getList", params_str, this.getHeader(), "")
return await this.parseVodShortListFromJson(JSON.parse(response)["data"]["list"])
}
async setHomeVod() {
let vod_list1 = await this.getHomeVod({
"page": 1,
"length": 16,
"offset": 0,
"typeIds": [],
"orderType": 1,
"payType": [3, 4]
})
let vod_list2 = await this.getHomeVod({
"page": 1,
"length": 16,
"offset": 0,
"typeIds": [],
"orderType": 3,
"payType": [
1
]
})
let vod_list3 = await this.getHomeVod({
"page": 1,
"length": 32,
"offset": 0,
"typeIds": [],
"orderType": 1,
"payType": [
3
]
})
this.homeVodList = [...vod_list1, ...vod_list2, ...vod_list3];
}
getSortParams(params, extend) {
let orderTypeStr = extend["sorts"] ?? ""
if (!_.isEmpty(orderTypeStr)) {
let orderType = orderTypeStr.split("-")[0]
params["orderType"] = parseInt(orderType)
let orderModeStr = orderTypeStr.split("-")[1]
let orderMode = 0
if (orderModeStr === "升序") {
orderMode = "1"
} else {
orderMode = "0"
}
params["orderMode"] = parseInt(orderMode)
}
return params
}
getTopParams(type_id, layOutObj, pg, extend) {
let defaultOderType
if (type_id === 180) {
defaultOderType = "1"
} else {
defaultOderType = "7"
}
let orderMode = "1"
let orderType
let orderTypeStr = extend["sorts"] ?? defaultOderType
let isOrderModel = false
if (orderTypeStr.indexOf("-") > -1) {
orderType = orderTypeStr.split("-")[0]
let orderModeStr = orderTypeStr.split("-")[1]
if (orderModeStr === "升序") {
orderMode = "1"
} else {
orderMode = "0"
}
isOrderModel = true
} else {
orderType = defaultOderType
}
let params = {
"orderType": parseInt(orderType), //或者7
"tags": [],
"length": 11,
"page": parseInt(pg),
"typeIds": layOutObj["classs"],
"payType": layOutObj["payType"],
}
if (isOrderModel) {
params["orderMode"] = parseInt(orderMode)
}
return params
}
getChuanMeiParams(layOutObj, pg, extend) {
let obj
if (!_.isEmpty(extend["tags"])) {
obj = JSON.parse(extend["tags"])
} else {
obj = layOutObj
}
let params = {
"page": parseInt(pg),
"length": 32,
"offset": 32 * parseInt(pg - 1),
"tag": obj["videoLables"].join(","),
"typeIds": obj["classs"],
"orderType": obj["orderType"],
"payType": obj["payType"]
}
params = this.getSortParams(params, extend)
return params
}
getNvYouParams(layoutObj, pg, extend) {
let obj
if (!_.isEmpty(extend["tags"])) {
obj = JSON.parse(extend["tags"])
} else {
obj = layoutObj
}
let params = {"videoSort": 1, "touid": obj["id"], "page": parseInt(pg), "length": 12, "orderType": 1}
params = this.getSortParams(params, extend)
return params
}
getZhuantiParams(layoutObj, pg, extend) {
let obj
if (!_.isEmpty(extend["tags"])) {
obj = JSON.parse(extend["tags"])
} else {
obj = layoutObj
}
let orderType = extend["sorts"] ?? "8"
return {
"page": parseInt(pg),
"length": 12,
"offset": 12 * (parseInt(pg) - 1),
"orderType": parseInt(orderType),
"subjectId": obj["id"]
}
}
async setCategory(tid, pg, filter, extend) {
let tid_list = tid.split("$")
let type_id = parseInt(tid_list[0])
let layOutObj = JSON.parse(tid_list[1])
let params = {}
let url = "/videos/getList"
if (type_id > 174 && type_id < 181) {
params = this.getTopParams(type_id, layOutObj, pg, extend)
} else {
switch (type_id) {
case 173:
params = this.getChuanMeiParams(layOutObj, pg, extend)
break
case 182:
params = this.getNvYouParams(layOutObj, pg, extend)
url = "/user/getSpaceVideo"
break
case 209:
params = this.getZhuantiParams(layOutObj, pg, extend)
break
case 172:
let gatherId = extend["tags"] ?? layOutObj
params = {
"gatherId": parseInt(gatherId)
}
url = "/gather/getDetail"
break
default:
break
}
}
let resJson = JSON.parse(await this.post(this.siteUrl + url, this.getParams(params), this.getHeader(), ""))
if (type_id === 172) {
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["info"]["videos"])
} else {
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["list"])
}
}
async setDetail(id) {
let params = {
"videoId": parseInt(id),
"videoSort": 1
}
let resJson = JSON.parse(await this.post(this.siteUrl + "/videos/getInfo", this.getParams(params), this.getHeader(), ""))
this.vodDetail = await this.parseVodDetailFromDoc(resJson["data"]["info"])
}
async proxy(segments, headers) {
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'imgBt') {
let response = await req(url, {buffer: 0});
return JSON.stringify({
code: 200,
buffer: 2,
content: bt(response.content).replaceAll("data:image/jpeg;base64,", "").replaceAll("data:image/jpg;base64,", "").replaceAll("data:image/png;base64", ""),
headers: headers,
});
}
}
async setSearch(wd, quick, pg) {
let params = {
"page": parseInt(pg),
"length": 12,
"type": 1,
"key": wd
}
let resJson = JSON.parse(await this.post(this.siteUrl + "/base/globalSearch", this.getParams(params), this.getHeader(), ""))
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["infos"])
this.result.setPage(parseInt(pg), resJson["data"]["count"] / 12, 12, resJson["data"]["count"])
}
}
let spider = new HanXiuCaoSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider, bt}

View File

@ -1,273 +0,0 @@
/*
* @File : haoxi.js
* @Author : jade
* @Date : 2024/2/7 14:24
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 好戏追剧 已失效
*/
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class HaoXiSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://haoxi.vip"
}
getAppName() {
return `好戏追剧`
}
getName() {
return `🌿┃好戏追剧┃🌿`
}
getJSName() {
return "haoxi"
}
getType() {
return 3
}
parseVodShortFromElement($, element) {
let vodShort = new VodShort();
vodShort.vod_id = $(element).find("a")[0].attribs.href
vodShort.vod_name = $(element).find("a")[0].attribs.title
if (vodShort.vod_name === undefined) {
vodShort.vod_name = $($($(element).find("[class=\"thumb-txt cor4 hide\"]")).find("a")).html()
}
vodShort.vod_pic = $(element).find("img")[0].attribs["data-src"]
vodShort.vod_remarks = $($(element).find("[class=\"public-list-prb hide ft2\"]")).html()
return vodShort
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"flex bottom4\"]").find("[class=\"public-list-box public-pic-a [swiper]\"]")
for (const vodElement of vodElements) {
let vodShort = this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $("[class=\"public-list-box public-pic-b [swiper]\"]")
for (const vodElement of vodElements) {
let vodShort = this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"public-list-box search-box flex rel\"]")
for (const vodElement of vodElements) {
let vodShort = this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetailElement = $("[class=\"vod-detail style-detail rel cor1 hader0\"]")
let vodDetail = new VodDetail();
vodDetail.vod_pic = $(vodDetailElement).find("img")[0].attribs.src
vodDetail.vod_name = $($(vodDetailElement).find("[class=\"slide-info-title hide\"]")).html()
let elements = $(vodDetailElement).find("[class=\"slide-info hide\"]")
vodDetail.vod_year = $($($(elements[0]).find("[class=\"slide-info-remarks\"]")[0]).find("a")[0]).html()
vodDetail.vod_area = $($($(elements[0]).find("[class=\"slide-info-remarks\"]")[1]).find("a")[0]).html()
vodDetail.type_name = $($($(elements[0]).find("[class=\"slide-info-remarks\"]")[2]).find("a")[0]).html()
vodDetail.vod_remarks = $(elements[1]).text().replaceAll("备注 :", "")
vodDetail.vod_director = $(elements[2]).text().replaceAll("导演 :", "")
vodDetail.vod_actor = $(elements[3]).text().replaceAll("演员 :", "")
vodDetail.vod_content = $($("[class=\"text cor3\"]")).text()
let playElements = $("[class=\"box-width cor5\"]")
let playFormatElements = playElements.find("[class=\"swiper-slide\"]")
let playUrlElements = playElements.find("[class=\"anthology-list-box none\"]")
let vod_play_from_list = []
let vod_play_list = []
for (let i = 0; i < playFormatElements.length; i++) {
let playFormatElement = playFormatElements[i]
let format_name = playFormatElement.children[1].data
format_name = format_name.replaceAll(" ", "")
vod_play_from_list.push(format_name)
let vodItems = []
if (format_name === "http下载") {
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
if (episodeName !== "复制地址") {
vodItems.push(episodeName + "$" + episodeUrl)
}
}
} else {
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $("[class=\"head flex between no-null header_nav0\"]").find("li")
for (const navElement of navElements) {
let type_name = $($(navElement).find("a")).text()
let type_id = Utils.getStrByRegex(/\/vodtype\/(.*?)\//, $(navElement).find("a")[0].attribs.href)
if (Utils.isNumeric(type_id)) {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($) {
let elements = $("[class=\"nav-swiper rel\"]")
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": "", "value": []}
let name = $($($(elements[i]).find("[class=\"filter-text bj cor5\"]")[0]).find("span")).html()
if (name !== "已选" && name !== "频道") {
extend_dic["name"] = name
for (const ele of $(elements[i]).find("li")) {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
extend_list.push(extend_dic)
}
}
let sortElments = $("[class=\"site-tabs b-b br\"]")
let extend_dic = {"key": (elements.length + 1).toString(), "name": "排序", "value": []}
extend_dic["value"].push({"n": "全部", "v": "/"})
for (const ele of $(sortElments).find("a")) {
let type_id_list = ele.attribs.href.split("-")
extend_dic["value"].push({"n": $(ele).text(), "v": type_id_list[2]})
}
extend_list.push(extend_dic)
return extend_list
}
async setFilterObj() {
for (const class_dic of this.classes) {
let type_id = class_dic["type_id"]
if (Utils.isNumeric(type_id)) {
let url = this.siteUrl + `/vodshow/${type_id}-----------`
let $ = await this.getHtml(url)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
get_extend_sort_dic(tid) {
return {
"3": 3, "4": 1, "5": 11, "6": 4, "9": 5, "10": 2,
}
}
async setCategory(tid, pg, filter, extend) {
// "1-大陆-hits-Netflix-英语-A----正片--2023/version/4K/"
let urlParams = [tid.toString(), "", "", "", "", "", "", "", pg.toString(), "", "", ""]
let extend_dic = this.get_extend_sort_dic(parseInt(tid))
for (const key of Object.keys(extend_dic)) {
if (extend[key] === "0") {
urlParams[extend_dic[key]] = ""
} else {
if (extend[key] !== "全部") {
urlParams[extend_dic[key]] = extend[key]
}
}
}
let reqUrl = this.siteUrl + '/vodshow/' + urlParams.join("-");
if (extend[7] !== undefined && extend[7] !== "全部") {
reqUrl = reqUrl + `/version/${extend[7]}/`
}
await this.jadeLog.debug(`分类URL:${reqUrl}`)
let $ = await this.getHtml(reqUrl)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setSearch(wd, quick) {
let $ = await this.getHtml(this.siteUrl + `/vodsearch/-------------/?wd=${wd}`)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
async setPlay(flag, id, flags) {
if (flag !== "http下载") {
let $ = await this.getHtml(this.siteUrl + id)
let playConfig = JSON.parse(Utils.getStrByRegex(/var player_aaaa=(.*?)<\/script>/, $.html()))
this.playUrl = playConfig['url']
} else {
this.playUrl = id
}
}
}
let spider = new HaoXiSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,153 +0,0 @@
/*
* @File : hscangku.js
* @Author : jade
* @Date : 2024/01/03 19:19
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
class HsCangkuSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://hsck12.shop/"
}
getName() {
return "🔞┃黄色仓库┃🔞"
}
getAppName() {
return "黄色仓库"
}
getJSName() {
return "hscangku"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"stui-vodlist clearfix\"]").find("li")
for (const vod_element of vodElements) {
let vodShort = new VodShort()
let vodElement = $(vod_element).find("a")[0]
vodShort.vod_id = vodElement.attribs["href"]
vodShort.vod_name = vodElement.attribs["title"]
vodShort.vod_pic = vodElement.attribs["data-original"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let element = $($("[class=\"stui-pannel__head clearfix\"]")[1]).find("h3")
let stui_pannel_bd_element = $("div.stui-pannel-bd > div")
let video_element = stui_pannel_bd_element.find("video")[0]
vodDetail.vod_name = element.text()
vodDetail.vod_pic = video_element.attribs["poster"]
vodDetail.vod_play_from = "黄色仓库"
vodDetail.vod_play_url = $(video_element).find("source")[0].attribs["src"]
return vodDetail
}
async setClasses() {
this.classes = [
{
"type_name": "国产视频",
"type_id": "?type=gc"
},
{
"type_name": "国产新片",
"type_id": "?type=ycgc"
},
{
"type_name": "无码中文字幕",
"type_id": "?type=wz"
},
{
"type_name": "有码中文字幕",
"type_id": "?type=yz"
},
{
"type_name": "日本无码",
"type_id": "?type=rw"
}
]
}
async setCategory(tid, pg, filter, extend) {
let url = this.siteUrl + tid + "&p=" + pg.toString()
let html = await this.fetch(url, null,this.getHeader())
this.limit = 40;
if (html !== null) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
this.total = parseInt($("[class=\"active\"]").find("span").text())
}
}
async setDetail(id) {
let url = this.siteUrl + id
let html = await this.fetch(url,null,this.getHeader())
if (html !== null) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setPlay(flag, id, flags) {
this.playUrl = id
this.playHeader = {}
}
}
let spider = new HsCangkuSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
};
}
export {spider}

View File

@ -1,709 +0,0 @@
/*
* @File : huya.js
* @Author : jade
* @Date : 2024/3/7 9:13
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class HuyaSpider extends Spider {
constructor() {
super();
this.isJustLive = false
this.dataFrom = ""
this.customArea = ""
this.huYaPlayForamtObj = {"AL": "蓝光8M", "TX": "蓝光4M", "HW": "超清", "HS": "流畅"}
this.livePlayForamtObj = {"HD": "蓝光8M", "LD": "蓝光4M", "SD": "超清", "OD": "流畅"}
}
getName() {
return "🐯┃虎牙直播┃🐯"
}
getAppName() {
return "虎牙直播"
}
getJSName() {
return "huya"
}
getType() {
return 3
}
async spiderInit() {
if (this.cfgObj.hasOwnProperty('custom')) {
this.customArea = this.cfgObj.custom;
}
if (this.cfgObj.hasOwnProperty('from')) {
this.dataFrom = this.cfgObj.from;
}
if (this.dataFrom !== 'justlive') {
this.siteUrl = 'https://www.huya.com';
} else {
this.siteUrl = 'http://live.yj1211.work';
this.isJustLive = true;
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit()
}
getHeader() {
let header = super.getHeader();
header["User-Agent"] = Utils.MOBILEUA
return header
}
async setClasses() {
this.classes = [{
"type_id": "1", "type_name": "网游"
}, {"type_id": "2", "type_name": "单机"}, {"type_id": "3", "type_name": "手游"}, {
"type_id": "8", "type_name": "娱乐"
}]
}
async setFilterObj() {
this.filterObj = {
"1": [{
"key": "cateId",
"name": "分类",
"init": "1",
"value": [{"n": "英雄联盟", "v": "1"}, {"n": "CS2", "v": "862"}, {
"n": "穿越火线", "v": "4"
}, {"n": "lol云顶之弈", "v": "5485"}, {"n": "无畏契约", "v": "5937"}, {
"n": "CFHD", "v": "6079"
}, {"n": "逆战", "v": "135"}, {"n": "炉石传说", "v": "393"}, {"n": "DOTA2", "v": "7"}, {
"n": "地下城与勇士", "v": "2"
}, {"n": "魔兽世界", "v": "8"}, {"n": "坦克世界", "v": "802"}, {"n": "DOTA1", "v": "6"}, {
"n": "梦三国", "v": "489"
}, {"n": "魔兽争霸3", "v": "4615"}, {"n": "问道", "v": "107"}, {
"n": "命运方舟", "v": "3058"
}, {"n": "QQ飞车", "v": "9"}, {"n": "星际争霸", "v": "5"}, {
"n": "网游竞技", "v": "100023"
}, {"n": "射击综合游戏", "v": "100141"}, {"n": "暴雪专区", "v": "100043"}, {
"n": "彩虹岛Online", "v": "683"
}, {"n": "剑灵", "v": "897"}, {"n": "军事游戏", "v": "100133"}, {
"n": "冒险岛", "v": "2243"
}, {"n": "暗黑破坏神", "v": "1123"}, {"n": "诛仙3", "v": "1646"}, {
"n": "热血江湖", "v": "387"
}, {"n": "英魂之刃", "v": "1830"}, {"n": "武林外传一世琴缘", "v": "1661"}, {
"n": "起凡:群雄逐鹿", "v": "1612"
}, {"n": "神武4电脑版", "v": "3227"}, {"n": "龙之谷", "v": "15"}, {
"n": "炉石战棋", "v": "5751"
}, {"n": "御龙在天", "v": "675"}, {"n": "逆水寒", "v": "2952"}, {
"n": "千年3", "v": "878"
}, {"n": "永恒之塔", "v": "446"}, {"n": "体育游戏", "v": "100135"}, {
"n": "寻仙", "v": "734"
}, {"n": "战舰世界", "v": "1947"}, {"n": "QQ三国", "v": "1090"}, {
"n": "流放之路", "v": "427"
}, {"n": "反恐精英Online", "v": "1918"}, {"n": "反恐行动online", "v": "861"}, {
"n": "征途", "v": "2715"
}, {"n": "战争雷霆", "v": "624"}, {"n": "丝路传说2", "v": "1026"}, {
"n": "星际战甲", "v": "627"
}, {"n": "NBA2KOL系列", "v": "3959"}, {"n": "九阴真经", "v": "1009"}, {
"n": "跑跑卡丁车", "v": "162"
}, {"n": "诛仙世界", "v": "7749"}, {"n": "QQ华夏", "v": "1878"}, {
"n": "天涯明月刀", "v": "1219"
}, {"n": "大话西游:归来", "v": "8239"}, {"n": "荒野行动PC版", "v": "3185"}, {
"n": "新剑侠情缘", "v": "586"
}, {"n": "剑网3", "v": "900"}, {"n": "生死狙击2", "v": "6091"}, {
"n": "全球使命", "v": "939"
}, {"n": "梦想世界3", "v": "486"}, {"n": "枪神纪", "v": "496"}, {
"n": "新天龙八部", "v": "5671"
}, {"n": "铁甲雄兵", "v": "2765"}, {"n": "神泣", "v": "2531"}, {
"n": "斗战神", "v": "591"
}, {"n": "造梦西游OL", "v": "6815"}, {"n": "天堂", "v": "1966"}, {
"n": "大话西游2", "v": "2975"
}, {"n": "使命召唤:战区", "v": "5911"}, {"n": "希望OL", "v": "1161"}, {
"n": "极光世界 弑神传", "v": "514"
}, {"n": "守望先锋归来", "v": "2174"}, {"n": "QQ自由幻想", "v": "1862"}, {
"n": "命运2", "v": "2942"
}, {"n": "奇迹世界2", "v": "766"}, {"n": "坦克大战", "v": "4359"}, {
"n": "生死狙击", "v": "2471"
}, {"n": "天翼决", "v": "779"}, {"n": "QQ幻想", "v": "2419"}, {
"n": "新飞飞(FlyFF)", "v": "1582"
}, {"n": "刀剑英雄", "v": "915"}, {"n": "FIFA Online系列", "v": "100079"}, {
"n": "全球使命3", "v": "2953"
}, {"n": "完美端游系列", "v": "3034"}, {"n": "战意", "v": "2599"}, {
"n": "泡泡堂", "v": "440"
}, {"n": "赛尔号", "v": "2755"}, {"n": "大唐无双零", "v": "1584"}, {
"n": "QQ炫舞", "v": "2440"
}, {"n": "007传奇", "v": "1135"}, {"n": "天下", "v": "1597"}, {
"n": "天谕", "v": "1899"
}, {"n": "新倩女幽魂", "v": "1579"}, {"n": "传世无双", "v": "984"}, {
"n": "剑侠世界", "v": "903"
}, {"n": "Warhaven", "v": "9053"}, {"n": "诺亚传说", "v": "190"}, {
"n": "新挑战", "v": "583"
}, {"n": "超激斗梦境", "v": "5691"}, {"n": "QQ音速", "v": "1085"}, {"n": "征途2", "v": "677"}, {
"n": "征程", "v": "678"
}, {"n": "蜀门", "v": "4711"}, {"n": "完美世界:诸神之战", "v": "7217"}, {
"n": "战之刃:幸存者", "v": "8627"
}, {"n": "黎明之光", "v": "41"}, {"n": "天命西游", "v": "1086"}, {
"n": "炫舞时代", "v": "3353"
}, {"n": "荣誉空间", "v": "225"}, {"n": "卡拉彼丘", "v": "9073"}, {
"n": "成吉思汗怀旧版", "v": "640"
}, {"n": "英雄年代3", "v": "1232"}, {"n": "天书奇谈", "v": "2225"}, {
"n": "劲舞团", "v": "2420"
}, {"n": "远征Online梦想版", "v": "142"}, {"n": "奇迹:传奇", "v": "3917"}, {
"n": "封印者", "v": "2294"
}, {"n": "上古世纪", "v": "1046"}, {"n": "梦幻诛仙2", "v": "488"}, {
"n": "TERA Online", "v": "1072"
}, {"n": "倚天Ⅱ", "v": "959"}, {"n": "街头篮球", "v": "206"}, {
"n": "永恒轮回:无限", "v": "7847"
}, {"n": "火线精英", "v": "2550"}, {"n": "忍者村大战2", "v": "2369"}, {
"n": "领地人生", "v": "2282"
}, {"n": "仙侠世界", "v": "995"}, {"n": "洛奇英雄传", "v": "432"}, {
"n": "KARDS", "v": "8261"
}, {"n": "无限法则", "v": "3189"}, {"n": "全面战争:竞技场", "v": "5901"}, {
"n": "自由篮球", "v": "243"
}, {"n": "FC Online4", "v": "3683"}, {"n": "战地之王", "v": "618"}, {
"n": "古剑奇谭OL", "v": "1892"
}, {"n": "QQ仙侠传", "v": "2291"}, {"n": "300英雄", "v": "1132"}]
}], "2": [{
"key": "cateId",
"name": "分类",
"init": "2793",
"value": [{"n": "天天吃鸡", "v": "2793"}, {"n": "永劫无间", "v": "6219"}, {
"n": "主机游戏", "v": "100032"
}, {"n": "猛兽派对", "v": "6165"}, {"n": "互动点播", "v": "5907"}, {
"n": "我的世界", "v": "1732"
}, {"n": "方舟", "v": "1997"}, {"n": "单机热游", "v": "100002"}, {
"n": "怀旧游戏", "v": "100125"
}, {"n": "逃离塔科夫", "v": "3493"}, {"n": "俄罗斯钓鱼4", "v": "5495"}, {
"n": "部落:上升", "v": "1318"
}, {"n": "Dark and Darker", "v": "7905"}, {"n": "The Front", "v": "9497"}, {
"n": "Apex英雄", "v": "5011"
}, {"n": "生化危机4重制版", "v": "8013"}, {"n": "DayZ独立版", "v": "1125"}, {
"n": "星空", "v": "7857"
}, {"n": "互动剧游", "v": "6919"}, {"n": "艾尔登法环", "v": "5801"}, {
"n": "恐惧之间", "v": "6679"
}, {"n": "SCUM", "v": "4245"}, {"n": "Dread Hunger", "v": "7601"}, {
"n": "塞尔达传说:王国之泪", "v": "7883"
}, {"n": "欧洲卡车模拟", "v": "475"}, {"n": "洛克王国", "v": "2864"}, {
"n": "卧龙:苍天陨落", "v": "7859"
}, {"n": "无人深空", "v": "2566"}, {"n": "帝国神话", "v": "6821"}, {
"n": "饥荒", "v": "74"
}, {"n": "森林之子", "v": "7943"}, {"n": "星球大战系列", "v": "554"}, {
"n": "极限竞速:地平线", "v": "2634"
}, {"n": "最终幻想16", "v": "7869"}, {"n": "Among Us", "v": "6163"}, {
"n": "怪物猎人:崛起", "v": "6479"
}, {"n": "怪物猎人物语", "v": "7101"}, {"n": "骑马与砍杀系列", "v": "4783"}, {
"n": "荒野大镖客2", "v": "4319"
}, {"n": "太荒初境", "v": "7685"}, {"n": "罗布乐思", "v": "5771"}, {
"n": "只狼:影逝二度", "v": "4505"
}, {"n": "双人成行", "v": "6737"}, {"n": "重生边缘", "v": "6201"}, {
"n": "海贼王 寻秘世界", "v": "5097"
}, {"n": "战神:诸神黄昏", "v": "7771"}, {"n": "恐鬼症", "v": "6205"}, {
"n": "鬼谷八荒", "v": "6571"
}, {"n": "霍格沃茨之遗", "v": "7881"}, {"n": "全面战争", "v": "3521"}, {
"n": "仁王2", "v": "5795"
}, {"n": "奥拉星", "v": "2846"}, {"n": "甜蜜之家", "v": "6739"}, {
"n": "仙剑奇侠传七", "v": "6509"
}, {"n": "消逝的光芒2", "v": "7581"}, {"n": "渡神记", "v": "6231"}, {
"n": "归家异途", "v": "2949"
}, {"n": "博德之门3", "v": "6147"}, {"n": "看门狗:军团", "v": "6155"}, {
"n": "使命召唤系列", "v": "100137"
}, {"n": "育碧游戏", "v": "100139"}, {"n": "帝国时代4", "v": "4835"}, {
"n": "英灵神殿", "v": "6609"
}, {"n": "蛮荒志异:起源", "v": "9709"}, {"n": "岛", "v": "3019"}, {
"n": "沙盒与副本", "v": "9151"
}, {"n": "扫雷", "v": "2349"}, {"n": "街机游戏", "v": "5999"}, {
"n": "幽灵线:东京", "v": "7669"
}, {"n": "怪物猎人世界", "v": "3519"}, {"n": "盗贼之海", "v": "3641"}, {
"n": "纸人", "v": "5257"
}, {"n": "黑色像素人", "v": "28"}, {"n": "对马岛之魂", "v": "6039"}, {
"n": "瑞奇与叮当", "v": "2455"
}, {"n": "港诡实录", "v": "5853"}, {"n": "剑士", "v": "1467"}, {
"n": "魔法门之英雄无敌系列", "v": "2096"
}, {"n": "星露谷物语", "v": "2443"}, {"n": "仙剑奇侠传四", "v": "1659"}, {
"n": "伤害世界", "v": "2337"
}, {"n": "禁闭求生", "v": "6065"}, {"n": "真三国无双", "v": "1599"}, {
"n": "恐怖黎明", "v": "3435"
}, {"n": "其他单机", "v": "3069"}, {"n": "幽灵行动:荒野", "v": "2794"}, {
"n": "边缘", "v": "151"
}, {"n": "阿凡达", "v": "106"}, {"n": "全面战争:三国", "v": "3004"}, {
"n": "黎明之星", "v": "40"
}, {"n": "翼星求生", "v": "7463"}, {"n": "黎明传说", "v": "39"}, {
"n": "恶魔之魂", "v": "6151"
}, {"n": "艾兰岛", "v": "3855"}, {"n": "龙与地下城秘影历代记HD", "v": "17"}, {
"n": "龙与地下城:匕首谷", "v": "18"
}, {"n": "沙石镇时光", "v": "7687"}, {"n": "三国志曹操传", "v": "2592"}, {
"n": "FIFA足球", "v": "1888"
}, {"n": "最终幻想7重制版", "v": "5809"}, {"n": "四海兄弟", "v": "5995"}, {
"n": "最终幻想:起源", "v": "7653"
}, {"n": "摔跤城大乱斗", "v": "7773"}, {"n": "音乐游戏", "v": "2761"}, {
"n": "精灵与萤火意志", "v": "5895"
}, {"n": "桥梁建造师", "v": "3275"}, {"n": "哈迪斯", "v": "6153"}, {
"n": "小缇娜的奇幻之地", "v": "7647"
}, {"n": "宝可梦:剑盾", "v": "5715"}, {"n": "边境", "v": "4779"}, {
"n": "人类一败涂地", "v": "3289"
}, {"n": "糖豆人:终极淘汰赛", "v": "6083"}, {"n": "精灵宝可梦Let's Go", "v": "4375"}, {
"n": "战锤40K暗潮", "v": "3016"
}, {"n": "石油骚动", "v": "2585"}, {"n": "紫塞秋风", "v": "6045"}, {
"n": "阿尔比恩", "v": "8115"
}, {"n": "猎人:荒野的召唤", "v": "2906"}, {"n": "FIFA 23", "v": "7789"}, {
"n": "都市:天际线", "v": "2201"
}, {"n": "乐高大电影:游戏版", "v": "1439"}, {"n": "全面战争:阿提拉", "v": "2383"}, {
"n": "斩妖行", "v": "6105"
}, {"n": "马里奥赛车8", "v": "5947"}, {"n": "复仇者联盟", "v": "6121"}, {"n": "霓虹深渊", "v": "5743"}]
}], "3": [{
"key": "cateId",
"name": "分类",
"init": "2336",
"value": [{"n": "王者荣耀", "v": "2336"}, {"n": "和平精英", "v": "3203"}, {
"n": "英雄联盟手游", "v": "6203"
}, {"n": "CF手游", "v": "2413"}, {"n": "金铲铲之战", "v": "7185"}, {
"n": "三国杀", "v": "1669"
}, {"n": "原神", "v": "5489"}, {"n": "棋牌桌游", "v": "100036"}, {
"n": "综合手游", "v": "100029"
}, {"n": "劲乐幻想", "v": "7691"}, {"n": "新游广场", "v": "100052"}, {
"n": "崩坏:星穹铁道", "v": "7349"
}, {"n": "火影忍者手游", "v": "2429"}, {"n": "第五人格", "v": "3115"}, {
"n": "问道手游", "v": "2477"
}, {"n": "暗区突围", "v": "7209"}, {"n": "QQ飞车手游", "v": "2928"}, {
"n": "球球大作战", "v": "2411"
}, {"n": "明日之后", "v": "3483"}, {"n": "皇室战争", "v": "2439"}, {
"n": "COD手游", "v": "4769"
}, {"n": "手游休闲", "v": "100004"}, {"n": "二次元手游", "v": "100091"}, {
"n": "摸了个鱼", "v": "9283"
}, {"n": "MMORPG", "v": "100273"}, {"n": "动作游戏", "v": "100197"}, {
"n": "战争冲突", "v": "7449"
}, {"n": "王者模拟战", "v": "5699"}, {"n": "逆水寒手游", "v": "7725"}, {
"n": "幻塔", "v": "6437"
}, {"n": "欢乐斗地主", "v": "1749"}, {"n": "神武4手游", "v": "3135"}, {
"n": "阴阳师", "v": "2598"
}, {"n": "DNF手游", "v": "4921"}, {"n": "欢乐麻将", "v": "1751"}, {
"n": "英雄联盟电竞经理", "v": "7177"
}, {"n": "狼人杀手游", "v": "100049"}, {"n": "新天龙八部手游", "v": "6945"}, {
"n": "中国象棋", "v": "1671"
}, {"n": "天天象棋", "v": "4997"}, {"n": "传奇世界3D", "v": "3961"}, {
"n": "御龙在天手游", "v": "2568"
}, {"n": "高能英雄", "v": "8359"}, {"n": "天龙八部手游", "v": "2852"}, {
"n": "三国志战略版", "v": "5619"
}, {"n": "忍者必须死3", "v": "4041"}, {"n": "SKY光遇", "v": "3719"}, {
"n": "虎牙领主争霸", "v": "7529"
}, {"n": "云上城之歌", "v": "5977"}, {"n": "晶核", "v": "7279"}, {
"n": "仙境传说RO", "v": "2675"
}, {"n": "天天狼人", "v": "2774"}, {"n": "JJ棋牌", "v": "3841"}, {
"n": "奇迹MU觉醒", "v": "3116"
}, {"n": "指尖四川麻将", "v": "7215"}, {"n": "部落冲突", "v": "1797"}, {
"n": "新剑侠情缘手游", "v": "6259"
}, {"n": "萌宠远征", "v": "9385"}, {"n": "暗黑破坏神:不朽", "v": "6385"}, {
"n": "英雄杀", "v": "2688"
}, {"n": "热血江湖手游", "v": "2817"}, {"n": "蛋仔派对", "v": "6909"}, {
"n": "完美世界手游", "v": "4237"
}, {"n": "巅峰战舰", "v": "2502"}, {"n": "狼人杀", "v": "2785"}, {
"n": "斗罗大陆:魂师对决", "v": "6745"
}, {"n": "武侠乂手游", "v": "4929"}, {"n": "诛仙手游", "v": "2647"}, {
"n": "斗破苍穹手游", "v": "4337"
}, {"n": "迷你世界", "v": "2683"}, {"n": "风云", "v": "3061"}, {
"n": "妄想山海", "v": "6007"
}, {"n": "曙光英雄", "v": "6169"}, {"n": "三国战纪2", "v": "6049"}, {
"n": "梦幻新诛仙", "v": "5975"
}, {"n": "黎明觉醒:生机", "v": "6131"}, {"n": "远征", "v": "7837"}, {
"n": "航海王:燃烧意志", "v": "3943"
}, {"n": "火炬之光:无限", "v": "6399"}, {"n": "巅峰极速", "v": "6979"}, {
"n": "圣境之塔", "v": "7055"
}, {"n": "魔力宝贝", "v": "2891"}, {"n": "香肠派对", "v": "3639"}, {
"n": "创造与魔法", "v": "2931"
}, {"n": "JJ斗地主", "v": "6271"}, {"n": "永恒纪元:戒", "v": "2646"}, {
"n": "天涯明月刀手游", "v": "5115"
}, {"n": "狼人杀官方", "v": "3679"}, {"n": "混沌起源", "v": "5985"}, {
"n": "多多自走棋", "v": "5133"
}, {"n": "梦幻诛仙手游", "v": "2672"}, {"n": "鸿图之下", "v": "6027"}, {
"n": "新笑傲江湖", "v": "5669"
}, {"n": "凡人修仙传:人界篇", "v": "8297"}, {"n": "多乐棋牌", "v": "6209"}, {
"n": "口袋觉醒", "v": "5953"
}, {"n": "跑跑卡丁车手游", "v": "2620"}, {"n": "奶块", "v": "2775"}, {
"n": "月圆之夜", "v": "4339"
}, {"n": "率土之滨", "v": "2691"}, {"n": "征途2手游", "v": "2811"}, {
"n": "英魂之刃口袋版", "v": "2760"
}, {"n": "精灵盛典:黎明", "v": "6123"}, {"n": "方舟手游", "v": "4035"}, {
"n": "掼蛋", "v": "6225"
}, {"n": "绝世仙王", "v": "6619"}, {"n": "流星群侠传", "v": "3927"}, {
"n": "寻仙手游", "v": "2979"
}, {"n": "一梦江湖", "v": "3082"}, {"n": "Lost Light萤火突击国际服", "v": "6859"}, {
"n": "弹幕云游戏", "v": "7001"
}, {"n": "猎魂觉醒", "v": "3071"}, {"n": "冒险岛:枫之传说", "v": "8005"}, {
"n": "征途手游", "v": "2556"
}, {"n": "海岛奇兵", "v": "2624"}, {"n": "倩女幽魂手游", "v": "2503"}, {
"n": "超凡先锋", "v": "6507"
}, {"n": "龙之谷2手游", "v": "2736"}, {"n": "崩坏3", "v": "2639"}, {
"n": "猫和老鼠", "v": "2758"
}, {"n": "七人传奇:光与暗之交战", "v": "8125"}, {"n": "JJ麻将", "v": "9487"}, {
"n": "拉轰西游", "v": "9543"
}, {"n": "三国战纪", "v": "6047"}, {"n": "自由幻想手游", "v": "4015"}, {
"n": "秦时明月世界", "v": "5279"
}, {"n": "新斗罗大陆", "v": "6657"}, {"n": "新神魔大陆", "v": "5939"}, {
"n": "逃跑吧!少年", "v": "4137"
}, {"n": "太古神王2", "v": "6649"}, {"n": "剑侠世界3", "v": "7183"}, {
"n": "天天吃鸡手机版", "v": "4341"
}, {"n": "时空猎人3", "v": "6411"}, {"n": "合金弹头:觉醒", "v": "6931"}, {
"n": "明日方舟", "v": "4925"
}, {"n": "原始征途", "v": "7713"}, {"n": "奇迹:最强者", "v": "3215"}, {
"n": "天天酷跑", "v": "1715"
}, {"n": "FC 足球世界", "v": "3873"}, {"n": "万国觉醒", "v": "6159"}, {
"n": "机动都市阿尔法", "v": "5411"
}, {"n": "航海王热血航线", "v": "6181"}, {"n": "幻世九歌", "v": "7199"}, {
"n": "植物大战僵尸", "v": "485"
}, {"n": "无悔华夏", "v": "7063"}, {"n": "时空猎人", "v": "1742"}, {
"n": "荒野乱斗", "v": "4613"
}, {"n": "拳皇98终极之战OL", "v": "2687"}, {"n": "蛇蛇争霸", "v": "2680"}, {
"n": "王牌竞速", "v": "6463"
}, {"n": "重返帝国", "v": "6955"}, {"n": "吞噬星空:黎明", "v": "6651"}, {
"n": "口袋妖怪", "v": "2541"
}, {"n": "QQ炫舞手游", "v": "2991"}, {"n": "一拳超人:最强之男", "v": "4629"}, {
"n": "荣耀新三国", "v": "6943"
}, {"n": "少年三国志2", "v": "6125"}, {"n": "我的起源", "v": "5365"}, {
"n": "决战平安京", "v": "3064"
}, {"n": "剑灵2", "v": "7223"}, {"n": "开心消消乐", "v": "1712"}, {
"n": "小小蚁国", "v": "7803"
}, {"n": "最强NBA", "v": "2988"}, {"n": "剑侠情缘手游", "v": "2621"}, {
"n": "长安幻想", "v": "6727"
}, {"n": "我叫MT4", "v": "4087"}, {"n": "全明星街球派对", "v": "8401"}, {
"n": "大话西游手游", "v": "2626"
}, {"n": "荣耀大天使", "v": "6477"}, {"n": "镇魂街:天生为王", "v": "6557"}, {
"n": "摩尔庄园", "v": "5981"
}, {"n": "游戏王:决斗链接", "v": "4451"}, {"n": "剑侠世界2手游", "v": "3150"}, {
"n": "青云诀2", "v": "6009"
}, {"n": "战地无疆", "v": "7909"}, {"n": "一念逍遥", "v": "6419"}, {
"n": "永劫无间手游", "v": "7579"
}, {"n": "尘白禁区", "v": "7297"}, {"n": "元梦之星", "v": "9521"}, {
"n": "不良人3", "v": "5891"
}, {"n": "剑灵:革命", "v": "4545"}, {"n": "魔力宝贝:旅人", "v": "7573"}, {
"n": "米加小镇", "v": "7269"
}, {"n": "龙武手游", "v": "5219"}, {"n": "斗罗大陆2绝世唐门", "v": "6581"}, {
"n": "西行纪燃魂", "v": "8303"
}, {"n": "坦克世界闪击战", "v": "4977"}, {"n": "军棋", "v": "2561"}, {
"n": "饥荒:新家", "v": "6491"
}, {"n": "拳皇命运", "v": "3379"}, {"n": "实况足球", "v": "3741"}, {
"n": "战舰世界闪击战", "v": "4101"
}, {"n": "时空召唤", "v": "2551"}, {"n": "王牌战争:文明重启", "v": "5479"}, {
"n": "雀魂麻将", "v": "7107"
}, {"n": "欢乐升级", "v": "3925"}, {"n": "绿色征途", "v": "4227"}, {
"n": "弹弹堂手游", "v": "2857"
}, {"n": "太极熊猫3猎龙", "v": "2778"}, {"n": "哈利波特:魔法觉醒", "v": "5835"}, {
"n": "天地劫:幽城再临", "v": "5987"
}, {"n": "热血街篮", "v": "5859"}, {"n": "神雕侠侣手游", "v": "1781"}, {
"n": "山海镜花", "v": "5089"
}, {"n": "三国志战棋版", "v": "7937"}, {"n": "神雕侠侣2", "v": "4209"}, {
"n": "仙魔决", "v": "1674"
}, {"n": "王者荣耀星之破晓", "v": "7927"}, {"n": "我在江湖之神魔道", "v": "7699"}, {
"n": "梦幻模拟战", "v": "3481"
}, {"n": "单机手游", "v": "2777"}, {"n": "斗罗大陆-斗神再临", "v": "6631"}, {
"n": "未来之役", "v": "6831"
}, {"n": "风云岛行动", "v": "4695"}, {"n": "新游推荐", "v": "3160"}, {
"n": "火影忍者OL", "v": "3901"
}, {"n": "九灵神域", "v": "7719"}, {"n": "武动乾坤", "v": "3829"}, {
"n": "秦时明月2", "v": "1784"
}, {"n": "文明与征服", "v": "7071"}, {"n": "战双:帕弥什", "v": "4133"}, {
"n": "大航海时代:海上霸主", "v": "6929"
}, {"n": "剑网1归来", "v": "7361"}, {"n": "绝区零", "v": "7711"}, {
"n": "黑色沙漠手游", "v": "7287"
}, {"n": "虎牙吃鸡", "v": "7465"}, {"n": "一剑斩仙", "v": "6843"}, {
"n": "传奇天下", "v": "6927"
}, {"n": "斗斗堂", "v": "7133"}, {"n": "斗罗大陆", "v": "6119"}, {
"n": "天谕手游", "v": "5925"
}, {"n": "坎公骑冠剑", "v": "6641"}, {"n": "最终幻想觉醒", "v": "2721"}, {
"n": "神将三国", "v": "6621"
}, {"n": "灌篮高手正版授权手游", "v": "5399"}, {"n": "剑与家园", "v": "2838"}, {
"n": "极无双2", "v": "7825"
}, {"n": "光明大陆", "v": "2832"}, {"n": "荒野行动", "v": "3084"}, {
"n": "战斗法则", "v": "9513"
}, {"n": "疯狂原始人", "v": "4619"}, {"n": "逆战手游", "v": "7575"}, {
"n": "石器时代:觉醒", "v": "9159"
}]
}], "8": [{
"key": "cateId",
"name": "分类",
"init": "1663",
"value": [{"n": "星秀", "v": "1663"}, {"n": "户外", "v": "2165"}, {
"n": "一起看", "v": "2135"
}, {"n": "二次元", "v": "2633"}, {"n": "虚拟偶像", "v": "6055"}, {"n": "旅游", "v": "6791"}, {
"n": "放映厅", "v": "6245"
}, {"n": "娱乐天地", "v": "100022"}, {"n": "交友", "v": "4079"}, {
"n": "组队", "v": "5367"
}, {"n": "吃喝玩乐", "v": "100044"}, {"n": "原创", "v": "6861"}, {
"n": "虎牙文化", "v": "4089"
}, {"n": "体育", "v": "2356"}, {"n": "虎牙地方", "v": "5123"}, {"n": "颜值", "v": "2168"}, {
"n": "科技", "v": "2408"
}, {"n": "音乐", "v": "3793"}, {"n": "趣分享", "v": "5883"}, {"n": "一起买", "v": "7759"}, {
"n": "派对", "v": "7785"
}]
}],
};
if (this.customArea.length > 0) {
const filterCfg = this.customArea.split('#');
this.classes.unshift({"type_id": "custom", "type_name": "自选"});
const filterList = _.map(filterCfg, (it) => {
const filterKv = it.split(',');
return {
n: filterKv[1], v: filterKv[0],
};
});
const defKey = filterList[0];
this.filterObj["custom"] = [{"key": "cateId", "name": "分类", "init": defKey.v, "value": filterList}];
}
if (this.isJustLive) {
// key-value映射修改
const filterKeys = Object.keys(this.filterObj);
for (const filterKey of filterKeys) {
const filterItem = this.filterObj[filterKey];
for (const typeItem of filterItem) {
typeItem.value = _.map(typeItem.value, (it) => {
// 修改默认值
if (it.v === typeItem.init) {
typeItem.init = it.n;
}
return {
n: it.n, v: it.n,
};
});
}
}
}
this.classes.unshift({"type_id": "home", "type_name": "首页"});
}
async setHome(filter) {
await this.setClasses()
await this.setFilterObj()
}
async parseVodShortListFromJson(obj) {
let vod_list = []
if (this.isJustLive) {
for (const it of obj["data"]) {
let vodShort = new VodShort()
vodShort.vod_id = it["roomId"]
vodShort.vod_name = it["ownerName"] + it["roomName"]
vodShort.vod_pic = it["roomPic"]
vodShort.vod_remarks = it["categoryName"]
vod_list.push(vodShort)
}
} else {
for (const it of obj.data.datas) {
let vodShort = new VodShort()
vodShort.vod_id = it["profileRoom"]
vodShort.vod_name = it["nick"] + it["introduction"]
vodShort.vod_pic = it["screenshot"]
vodShort.vod_remarks = it["gameFullName"]
vod_list.push(vodShort)
}
}
return vod_list
}
getPlayUrlData(streamInfo, ratio) {
const hlsUrl = streamInfo["sHlsUrl"] + '/' + streamInfo["sStreamName"] + '.' + streamInfo["sHlsUrlSuffix"];
const srcAntiCode = unescape(streamInfo["sHlsAntiCode"]);
let codeList = srcAntiCode.split('&');
codeList = codeList.filter(code => code !== '');
let cryptoInfo = {};
for (const code of codeList) {
const [k, v] = code.split('=');
cryptoInfo[k] = v;
}
const fm = Utils.unquote(cryptoInfo["fm"]);
const fmDecoded = Utils.base64Decode(fm);
const hashPrefix = fmDecoded.split('_')[0];
const ctype = cryptoInfo["ctype"] || '';
const txyp = cryptoInfo["txyp"] || '';
const fs = cryptoInfo.fs || '';
const t = cryptoInfo.t || '';
const u = 1463993859134;
const curTime = Date.now();
const seqid = Math.floor(curTime + u);
const wsTime = (Math.floor(curTime / 1e3) + 3600).toString(16);
const v0 = seqid + '|' + ctype + '|' + t;
const v1 = Utils.md5Encode(v0);
const v2 = hashPrefix + '_' + u + '_' + streamInfo["sStreamName"] + '_' + v1 + '_' + wsTime;
const hash = Utils.md5Encode(v2);
// ratio = ""
const purl = `${hlsUrl}?wsSecret=${hash}&wsTime=${wsTime}&seqid=${seqid}&ctype=${ctype}&ver=1&txyp=${txyp}&fs=${fs}&ratio=${ratio}&u=${u}&t=${t}&sv=2107230339`;
return {
cdnType: streamInfo["sCdnType"], playUrl: purl,
};
}
async parseVodDetailfromJson(liveInfo, streamInfoList, bitInfoList) {
let vodDetail = new VodDetail()
vodDetail.vod_name = liveInfo["introduction"] ?? liveInfo["sIntroduction"]
vodDetail.vod_pic = liveInfo["screenshot"] ?? liveInfo["sScreenshot"]
vodDetail.vod_remarks = liveInfo["gameFullName"] ?? liveInfo["sGameFullName"]
vodDetail.type_name = liveInfo["gameFullName"] ?? liveInfo["sGameFullName"]
vodDetail.vod_director = liveInfo["nick"] ?? liveInfo["sNick"]
vodDetail.vod_content = liveInfo["activityCount"] ?? liveInfo["lActivityCount"]
vodDetail.vod_content = vodDetail.vod_content + '人在线'
let vod_play_from_list = []
let vod_play_list = []
for (const streamInfo of streamInfoList) {
let vodItems = []
for (const bitinfo of bitInfoList) {
let format_name = this.huYaPlayForamtObj[streamInfo["sCdnType"]]
if (format_name === bitinfo["sDisplayName"]) {
const urlData = this.getPlayUrlData(streamInfo, bitinfo["iBitRate"]);
vod_play_from_list.push(format_name)
vodItems.push("虎牙直播" + '$' + urlData["playUrl"])
vod_play_list.push(vodItems.join("#"))
break
}
}
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async parseVodDetailFromDoc(vodData, playData) {
let vodDetail = new VodDetail()
vodDetail.vod_name = vodData["data"]["roomName"]
vodDetail.vod_director = vodData["data"]["ownerName"]
vodDetail.vod_pic = vodData["data"]["roomPic"]
vodDetail.vod_remarks = vodData["data"]["categoryName"]
vodDetail.vod_content = vodData["data"]["online"] + "人在线"
let vod_play_from_list = []
let vod_play_list = []
for (const key of Object.keys(this.livePlayForamtObj)) {
let vodItems = []
if (playData.data.hasOwnProperty(key)) {
vod_play_from_list.push(this.livePlayForamtObj[key])
vodItems.push("JustLive" + '$' + playData["data"][key])
vod_play_list.push(vodItems.join("#"))
}
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async parseVodShortListFromDocBySearch(data) {
let vod_list = [];
for (const vod of data.response['3']["docs"]) {
let vodShort = new VodShort()
vodShort.vod_id = vod["room_id"]
vodShort.vod_name = vod["game_nick"] + vod["game_introduction"]
vodShort.vod_pic = vod["game_screenshot"]
vodShort.vod_remarks = vod["game_name"]
vod_list.push(vodShort)
}
return vod_list
}
async setCategory(tid, pg, filter, extend) {
if (pg <= 0 || typeof pg == 'undefined') pg = 1;
let url = '';
let data = {}
if (this.isJustLive) {
if (tid === 'home') {
url = this.siteUrl + '/api/live/getRecommendByPlatform?platform=huya&size=20&page=' + pg;
} else {
url = this.siteUrl + '/api/live/getRecommendByPlatformArea?platform=huya&size=20&area=' + extend.cateId + '&page=' + pg;
}
data = JSON.parse(await this.fetch(url, null, this.getHeader()));
} else {
if (tid === 'home') {
url = this.siteUrl + '/cache.php?m=LiveList&do=getLiveListByPage&tagAll=1&page=' + pg;
} else {
url = this.siteUrl + '/cache.php?m=LiveList&do=getLiveListByPage&gameId=' + extend["cateId"] + '&tagAll=0&page=' + pg;
}
data = JSON.parse(await this.fetch(url, null, this.getHeader()));
}
this.vodList = await this.parseVodShortListFromJson(data)
}
async setDetail(id) {
let liveInfo = null;
let streamInfoList = null;
if (this.isJustLive) {
await this.jadeLog.debug("JustLive", true)
const vodInfo = await this.fetch(this.siteUrl + `/api/live/getRoomInfo?platform=huya&roomId=${id}`, null, this.getHeader())
const playInfo = await this.fetch(this.siteUrl + `/api/live/getRealUrl?platform=huya&roomId=${id}`, null, this.getHeader())
const vodData = JSON.parse(vodInfo);
const playData = JSON.parse(playInfo)
this.vodDetail = await this.parseVodDetailFromDoc(vodData, playData)
} else {
await this.jadeLog.debug("虎牙直播", true)
const resp = await this.fetch('https://mp.huya.com/cache.php?m=Live&do=profileRoom&roomid=' + id, null, this.getHeader());
const data = JSON.parse(resp);
liveInfo = data.data["liveData"];
let bitInfo = JSON.parse(liveInfo["bitRateInfo"])
streamInfoList = data.data.stream["baseSteamInfoList"];
this.vodDetail = await this.parseVodDetailfromJson(liveInfo, streamInfoList, bitInfo)
}
/**
*
* await this.jadeLog.debug("虎牙直播",true)
* const headers = {
* 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': Utils.MOBILEUA,
* };
* let content = await this.fetch('https://m.huya.com/' + id, null, headers);
* let liveData = JSON.parse(Utils.getStrByRegex(/<script> window.HNF_GLOBAL_INIT = (.*?)<\/script>/, content))
* const vodData = liveData["roomInfo"];
* liveInfo = vodData["tLiveInfo"];
* streamInfoList = vodData["tLiveInfo"]["tLiveStreamInfo"]["vStreamInfo"]["value"]
* let bitInfoList = vodData["tLiveInfo"]["tLiveStreamInfo"]["vBitRateInfo"]["value"]
* this.vodDetail = await this.parseVodDetailfromJson(liveInfo, streamInfoList, bitInfoList)
* */
}
async setSearch(wd, quick) {
const resp = await this.fetch('https://search.cdn.huya.com/?m=Search&do=getSearchContent&q=' + wd + '&uid=0&v=4&typ=-5&livestate=0&rows=40&start=0', null, this.getHeader());
const data = JSON.parse(resp);
this.vodList = await this.parseVodShortListFromDocBySearch(data)
}
}
let spider = new HuyaSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,319 +0,0 @@
/*
* @File : ikanbot.js
* @Author : jade
* @Date : 2024/1/15 10:32
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {Spider} from "./spider.js";
import {load, _} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
function _0xf746(_0xbb40c4, _0x1cb776) {
const _0x45e084 = _0x45e0();
return _0xf746 = function (_0xf74696, _0x4d32af) {
_0xf74696 = _0xf74696 - 0x1a8;
let _0xcbfa28 = _0x45e084[_0xf74696];
return _0xcbfa28;
}, _0xf746(_0xbb40c4, _0x1cb776);
}
function _0x45e0() {
const _0x58b10c = ['1580630GngmmA', '117uvwflw', 'join', 'current_id', '565448Apkhig', '23092JwmytW', '707152yowhOv', 'getElementById', '855936CGaczt', 'length', '2966831GCGpvn', '611266nfcTEf', 'value', 'substring'];
_0x45e0 = function () {
return _0x58b10c;
};
return _0x45e0();
}
(function (_0x27923d, _0x43d7fc) {
const _0x439396 = _0xf746, _0x30f164 = _0x27923d();
while (!![]) {
try {
const _0xa560eb = -parseInt(_0x439396(0x1b4)) / 0x1 + parseInt(_0x439396(0x1ad)) / 0x2 + -parseInt(_0x439396(0x1b1)) / 0x3 * (-parseInt(_0x439396(0x1b5)) / 0x4) + -parseInt(_0x439396(0x1b0)) / 0x5 + parseInt(_0x439396(0x1aa)) / 0x6 + parseInt(_0x439396(0x1ac)) / 0x7 + parseInt(_0x439396(0x1a8)) / 0x8;
if (_0xa560eb === _0x43d7fc) break; else _0x30f164['push'](_0x30f164['shift']());
} catch (_0x3ae316) {
_0x30f164['push'](_0x30f164['shift']());
}
}
}(_0x45e0, 0x4a3d9));
function get_tks(play_id, e_token) {
const _0xf07220 = _0xf746;
let _0x35162d = play_id, _0xf25678 = e_token;
if (!_0x35162d || !_0xf25678) return;
let _0x3882a3 = _0x35162d['length'], _0x52a097 = _0x35162d[_0xf07220(0x1af)](_0x3882a3 - 0x4, _0x3882a3),
_0x2d9d1b = [];
for (let _0x570711 = 0x0; _0x570711 < _0x52a097[_0xf07220(0x1ab)]; _0x570711++) {
let _0x23e537 = parseInt(_0x52a097[_0x570711]), _0x48b93d = _0x23e537 % 0x3 + 0x1;
_0x2d9d1b[_0x570711] = _0xf25678[_0xf07220(0x1af)](_0x48b93d, _0x48b93d + 0x8), _0xf25678 = _0xf25678[_0xf07220(0x1af)](_0x48b93d + 0x8, _0xf25678[_0xf07220(0x1ab)]);
}
return _0x2d9d1b[_0xf07220(0x1b2)]('');
}
class IKanBotSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://v.ikanbot.com"
}
getName() {
return "🤖┃爱看机器人┃🤖"
}
getAppName() {
return "爱看机器人"
}
getJSName() {
return "ikanbot"
}
getType() {
return 3
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
async parseVodShortListFromDoc($) {
let vod_list = [];
let VodShortElements = $($("[class=\"row list-wp\"]")).find("a")
for (const vodShortElement of VodShortElements) {
let vodShort = new VodShort()
let reElement = $(vodShortElement).find("img")[0]
vodShort.vod_id = vodShortElement.attribs["href"]
vodShort.vod_pic = this.jsBase + Utils.base64Encode(reElement.attribs["data-src"])
vodShort.vod_name = reElement.attribs["alt"]
vod_list.push(vodShort)
}
return vod_list
}
getChildren(detail, index) {
try {
return detail[index].children[0].data;
} catch (e) {
return ""
}
}
async parseVodDetailFromDoc($) {
const detail = $('div.detail > .meta');
let vodDetail = new VodDetail();
vodDetail.vod_pic = this.jsBase + Utils.base64Encode($('div.item-root > img')[0].attribs['data-src'])
vodDetail.vod_name = this.getChildren(detail, 0)
vodDetail.vod_year = this.getChildren(detail, 1)
vodDetail.vod_area = this.getChildren(detail, 3);
vodDetail.vod_actor = this.getChildren(detail, 4);
let id = Utils.getStrByRegex(/<input type="hidden" id="current_id" value="(.*?)"/, $.html())
let token = Utils.getStrByRegex(/<input type="hidden" id="e_token" value="(.*?)"/, $.html())
let mtype = Utils.getStrByRegex(/<input type="hidden" id="mtype" value="(.*?)"/, $.html())
let params = {
"videoId": id, "mtype": mtype, "token": get_tks(id, token),
}
let content = await this.fetch(this.siteUrl + '/api/getResN', params, this.getHeader())
const list = JSON.parse(content)["data"]["list"];
let playlist = {};
let index = 0
let form_list = []
for (const l of list) {
const flagData = JSON.parse(l["resData"]);
for (const f of flagData) {
index = index + 1
const from = f.flag;
const urls = f.url;
if (!from || !urls) continue;
if (playlist[from]) continue;
form_list.push(`线路${index}`)
playlist[from] = urls;
}
}
vodDetail.vod_play_from = form_list.join('$$$');
vodDetail.vod_play_url = _.values(playlist).join('$$$');
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
const items = $('div.media > div.media-left > a');
for (const item of items) {
let vodShort = new VodShort();
const img = $(item).find('img:first')[0];
vodShort.vod_id = item.attribs.href
vodShort.vod_name = img.attribs.alt
vodShort.vod_pic = this.jsBase + Utils.base64Encode(img.attribs['data-src'])
vod_list.push(vodShort)
}
return vod_list
}
async setClasses() {
let html = await this.fetch(this.siteUrl + "/category", null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
let classElements = $($($("[class=\"row visible-xs-block visible-sm-block\"]")).find("li")).find("a")
for (const classElement of classElements) {
this.classes.push({"type_name": $(classElement).text(), "type_id": classElement.attribs["href"]})
}
}
}
async setFilterObj() {
for (const class_dic of this.classes.slice(1, 9)) {
let type_id = class_dic["type_id"]
if (type_id.indexOf("category") === -1 || type_id.indexOf(",") > -1) {
let type_url = type_id.split(",").slice(-1)[0]
let html = await this.fetch(this.siteUrl + type_url, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
let containerElement = $("[class=\"row visible-xs-block visible-sm-block\"]")
let filterElements = containerElement.find("[class=\"nav nav-pills\"]").find("a")
let value_list = []
if (type_id.indexOf(",") > -1) {
value_list.push({"n": "全部", "v": type_id.split(",")[0]})
}
let extend_dic = {
"key": type_id, "name": $(containerElement.find("h5")).text(), "value": value_list
}
for (const filterElement of filterElements) {
value_list.push({"n": $(filterElement).text(), "v": filterElement.attribs["href"]})
}
if (value_list.length > 0) {
this.filterObj[type_id] = [extend_dic]
}
}
}
}
}
async setHomeVod() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
async setCategory(tid, pg, filter, extend) {
let categoryUrl = (this.siteUrl + (extend[tid] || tid.split(",")[0]))
let update_page = false
if (categoryUrl.indexOf("html") > -1) {
categoryUrl = categoryUrl.replace('.html', pg > 1 ? `-p-${pg}.html` : '.html');
} else {
categoryUrl = categoryUrl + `?p=${pg}`
update_page = true
}
await this.jadeLog.debug(`分类URL:${categoryUrl}`)
let html = await this.fetch(categoryUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
let pageDoc = $('div.page-more > a:contains(下一页)')
if (update_page) {
this.page = parseInt(pageDoc[0].attribs["href"].split("p=")[1])
}
const hasMore = pageDoc.length > 0;
this.limit = 24
this.count = hasMore ? parseInt(pg) + 1 : parseInt(pg);
this.total = this.limit * this.count
}
}
async setDetail(id) {
let html = await this.fetch(this.siteUrl + id, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html);
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setSearch(wd, quick) {
const html = await this.fetch(this.siteUrl + '/search?q=' + wd, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
async setPlay(flag, id, flags) {
this.playUrl = id
}
}
let spider = new IKanBotSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

View File

@ -1,317 +0,0 @@
/*
* @File : jable.js
* @Author : jade
* @Date : 2024/3/4 9:44
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class JableTVSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://jable.tv"
this.cookie = ""
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getImgHeaders());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getImgHeaders());
}
}
getImgHeaders(){
return {
"User-Agent": "PostmanRuntime/7.37.3",
"Postman-Token": "c2602692-1a05-4bb0-93cd-270afad97e87",
"Host": "assets-cdn.jable.tv",
"Proxy": true
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
getAppName() {
return "Jable"
}
getName() {
return "🔞┃Jable┃🔞"
}
getJSName() {
return "jable"
}
getType() {
return 3
}
getHeader() {
// let header = super.getHeader()
let header = {}
header["User-Agent"] = "PostmanRuntime/7.36.3"
header["Host"] = "jable.tv"
header["Postman-Token"] = "33290483-3c8d-413f-a160-0d3aea9e6f95"
return header
}
async getHtml(url = this.siteUrl, proxy = false, headers = this.getHeader()) {
return super.getHtml(url, true, headers);
}
async setClasses() {
let $ = await this.getHtml(this.siteUrl)
let navElements = $("[class=\"title-box\"]")
let defaultTypeIdElements = $("div.row")
for (const navElement of $(defaultTypeIdElements[0]).find("a")) {
let type_name = $(navElement).text()
let type_id = navElement.attribs.href
if (type_id.indexOf(this.siteUrl) > -1) {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
navElements = navElements.slice(1, 9)
defaultTypeIdElements = defaultTypeIdElements.slice(1, 9)
for (let i = 0; i < navElements.length; i++) {
let typeId = $(defaultTypeIdElements[i]).find("a")[0].attribs["href"]
this.classes.push(this.getTypeDic("标签", typeId));
break
}
}
async getSortFilter($) {
let sortElements = $("[class=\"sorting-nav\"]").find("a")
let extend_dic = {"name": "排序", "key": "sort", "value": []}
for (const sortElement of sortElements) {
let typeId = sortElement.attribs["data-parameters"].split("sort_by:")[1]
let typeName = $(sortElement).text()
extend_dic["value"].push({"n": typeName, "v": typeId})
}
return extend_dic
}
async getFilter($, index, type_id, type_name) {
let extend_list = []
if (index < 4) {
let extend_dic = {"name": type_name, "key": "type", "value": []}
let type_seletc_list = ["div.img-box > a", "[class=\"horizontal-img-box ml-3 mb-3\"] > a", "", "sort"]
let type_id_select_list = ["div.absolute-center > h4", "div.detail"]
let default$ = await this.getHtml(type_id)
for (const element of default$(type_seletc_list[index])) {
let typeId = element.attribs["href"]
let typeName = $($(element).find(type_id_select_list[index])).text().replaceAll("\t", "").replaceAll("\n", '').replaceAll(" ", "");
extend_dic["value"].push({"n": typeName, "v": typeId})
}
if (extend_dic.value.length > 0) {
extend_list.push(extend_dic)
//排序
let sortDetail$ = await this.getHtml(extend_dic["value"][0]["v"])
let sort_extend_dic = await this.getSortFilter(sortDetail$)
if (sort_extend_dic.value.length > 0) {
extend_list.push(sort_extend_dic)
}
} else {
//排序
let sort_extend_dic = await this.getSortFilter(default$)
if (sort_extend_dic.value.length > 0) {
extend_list.push(sort_extend_dic)
}
}
} else {
let defaultTypeIdElements = $("div.row").slice(1, 9)
let navElements = $("[class=\"title-box\"]").slice(1, 9)
for (let i = 0; i < navElements.length; i++) {
let extend_dic = {"name": $($(navElements[i]).find("h2")).text(), "key": "type", "value": []}
for (const filterElement of $(defaultTypeIdElements[i]).find("a")) {
let filter_type_id = filterElement.attribs.href
if (filter_type_id.indexOf(this.siteUrl) > -1) {
extend_dic["value"].push({"n": $(filterElement).text(), "v": filter_type_id})
}
}
extend_list.push(extend_dic)
}
let sortDetail$ = await this.getHtml(type_id)
let sort_extend_dic = await this.getSortFilter(sortDetail$)
if (sort_extend_dic.value.length > 0) {
extend_list.push(sort_extend_dic)
}
}
return extend_list
}
async setFilterObj() {
let $ = await this.getHtml(this.siteUrl)
let classes = this.classes.slice(1)
for (let i = 0; i < classes.length; i++) {
let type_name = classes[i].type_name
let type_id = classes[i].type_id
// if (type_id.indexOf("models") > 1) {
// type_id = `https://jable.tv/models/?mode=async&function=get_block&block_id=list_models_models_list&sort_by=total_videos&_=${new Date().getTime()}`
// }
let extend_list = await this.getFilter($, i, type_id, type_name)
if (extend_list.length > 1 && i < 4) {
type_id = extend_list[0]["value"][0]["v"]
this.classes[i + 1] = this.getTypeDic(type_name, type_id)
}
this.filterObj[type_id] = extend_list
}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("div.video-img-box")
for (const element of vodElements) {
let vodShort = new VodShort()
let vod_pic = $(element).find("img").attr("data-src")
if (vod_pic !== undefined) {
vodShort.vod_pic = vod_pic
// if (this.catOpenStatus) {
// vodShort.vod_pic = this.jsBase + Utils.base64Encode(vod_pic)
// } else {
// vodShort.vod_pic = vod_pic
// }
let url = $(element).find("a").attr("href");
vodShort.vod_id = url.split("/")[4];
vodShort.vod_name = url.split("/")[4];
let remarks_list = $($(element).find("[class=\"sub-title\"]")).text().split("\n")
if (remarks_list.length > 1) {
vodShort.vod_remarks = remarks_list[1].replaceAll(" ", "").replaceAll("\t", "")
} else {
vodShort.vod_remarks = "精选"
}
if (!_.isEmpty(vodShort.vod_pic) && vodShort.vod_remarks !== "[限時優惠]只需1元即可無限下載") {
vod_list.push(vodShort);
}
}
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let leftElement = $("[class=\"header-left\"]")
vodDetail.vod_name = $($(leftElement).find("h4")).text();
let vod_pic = Utils.getStrByRegex(/<video poster="(.*?)" id=/, $.html())
vodDetail.vod_pic = vod_pic
// if (this.catOpenStatus) {
// vodDetail.vod_pic = this.jsBase + Utils.base64Encode(vod_pic)
// } else {
// vodDetail.vod_pic = vod_pic
// }
vodDetail.vod_year = $($("[class=\"inactive-color\"]")).text()
let episodeName = $($("[class=\"header-right d-none d-md-block\"] > h6")).text().replaceAll("\n", "").replaceAll("●", "")
let vodItems = []
let episodeUrl = Utils.getStrByRegex(/var hlsUrl = '(.*?)';/, $.html())
vodItems.push(episodeName + "$" + episodeUrl)
let vod_play_list = []
vod_play_list.push(vodItems.join("#"))
let vod_play_from_list = ["Jable"]
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + "/videos/" + id + "/")
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let extend_type = extend["type"] ?? tid
let sort_by = extend["sort"] ?? "video_viewed"
this.limit = 24
let cateUrl;
this.total = 0
this.count = 0
if (tid.indexOf("latest-updates") > 1) {
cateUrl = `https://jable.tv/latest-updates/?mode=async&function=get_block&block_id=list_videos_latest_videos_list&sort_by=post_date&from=${pg}&_=1709730132217`
} else {
cateUrl = extend_type + `/${pg}/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=${sort_by}&_=${new Date().getTime()}`
}
let $ = await this.getHtml(cateUrl);
this.vodList = await this.parseVodShortListFromDoc($)
let page = $($("[class=\"page-item\"]").slice(-1)[0]).text()
if (page.indexOf("最後") > -1) {
} else {
if (parseInt(page) === this.page || _.isEmpty(page)) {
await this.jadeLog.debug("分类页面到底了")
this.total = this.page
this.count = this.page
}
}
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + `/search/${wd}/`
let $ = await this.getHtml(searchUrl)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
}
let spider = new JableTVSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,295 +0,0 @@
/*
* @File : jiafeimao.js
* @Author : jade
* @Date : 2024/1/24 9:15
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 加菲猫 (已失效)
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class JiaFeiMaoSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://jfmys.app"
}
getAppName() {
return "加菲猫"
}
getName() {
return `🐈┃加菲猫┃🐈`
}
getJSName() {
return "jiafeimao"
}
getType() {
return 3
}
getPic(url){
if (url.indexOf("http:") > -1 || url.indexOf("https:") > -1){
return url
}else{
return this.siteUrl + url
}
}
parseVodShortFromElement($, element) {
let vodShort = new VodShort()
vodShort.vod_id = Utils.getStrByRegex(/id\/(.*?)\//,$(element).find("a")[0].attribs.href)
vodShort.vod_name = $(element).find("a")[0].attribs.title
vodShort.vod_pic = this.getPic($(element).find("img")[0].attribs["data-src"])
vodShort.vod_remarks = $($(element).find("[class=\"v-tips\"]")).html()
return vodShort
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $(".icon > .container").find("[class=\"imain clearfix\"]").find("li")
for (const vodElement of vodElements) {
let vodShort = this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $("[class=\"tv-list clearfix\"]").find("li")
for (const vodElement of vodElements) {
let vodShort = this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
vodDetail.vod_name = $($("[class=\"iptit\"]").find("h3")).html().split(" ")[0]
vodDetail.vod_content = $($("[class=\"idetail container\"]").find("[class=\"infor_intro\"]")).text()
let vodPlayElements = $("[class=\"fjcon\"]")
let vod_play_from_list = []
let vod_play_list = []
let playFormatElemets = $($(vodPlayElements).find("[class=\"fjtop clearfix\"]")).find("a")
let playUrlElements = $(vodPlayElements).find("[class=\"xjn_ul play-list\"]")
for (let i = 0; i < playFormatElemets.length; i++) {
let playFormatElement = playFormatElemets[i]
vod_play_from_list.push("线路" +( i+1).toString())
let vodItems = []
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
parseVodDetail(vod_data) {
let vodDetail = new VodDetail()
vodDetail.vod_name = vod_data["vod_name"]
vodDetail.vod_pic = this.getPic(vod_data["vod_pic"])
vodDetail.vod_remarks = vod_data["vod_remarks"]
vodDetail.vod_area = vod_data["vod_area"]
vodDetail.vod_year = vod_data["vod_year"]
vodDetail.vod_actor = vod_data["vod_actor"]
vodDetail.vod_director = vod_data["vod_director"]
vodDetail.vod_content = vod_data["vod_content"].replaceAll("<p>","").replaceAll("</p>","")
let vod_play_from = []
for (let i = 0; i < vod_data["vod_play_from"].split("$$$").length; i++) {
vod_play_from.push("线路"+(i+1).toString())
}
vodDetail.vod_play_from = vod_play_from.join("$$$")
vodDetail.vod_play_url = vod_data["vod_play_url"]
vodDetail.type_name = vod_data["type_name"]
return vodDetail
}
async parseVodDetailfromJson(obj) {
let vodDetail;
let vod_data_list = obj["list"]
if (vod_data_list.length > 0) {
let vod_data = vod_data_list[0]
vodDetail = this.parseVodDetail(vod_data)
}
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"tv-bd search-list\"]").find("[class=\"item clearfix\"]")
for (const vodElement of vodElements){
let vodShort = new VodShort()
vodShort.vod_id = Utils.getStrByRegex(/id\/(.*?).html/, $($(vodElement).find("[class=\"s_tit\"]")).find("a")[0].attribs.href)
vodShort.vod_name = $($($(vodElement).find("[class=\"s_tit\"]")).find("a")).text()
vodShort.vod_pic = this.getPic($(vodElement).find("img")[0].attribs.src)
vodShort.vod_remarks = $($(vodElement).find("[class=\"s_score\"]")).text()
vod_list.push(vodShort)
}
return vod_list
}
async setClasses() {
let $ = await this.getHtml()
let content = $($("[class=\"container\"]").find("script")).html()
let navContent = Utils.getStrByRegex(/document.write\('(.*?);/, content)
for (const navElement of $(navContent).find("a")) {
let type_id = navElement.attribs["href"]
let type_name = $(navElement).text()
if (type_id !== "/" && type_name !== "专题" && type_name !== "站长模板") {
this.classes.push(this.getTypeDic(type_name, Utils.getStrByRegex(/id\/(.*?).html/, type_id)))
}
}
}
async getFilter($) {
let elements = $($("[class=\"container\"]").find("[class=\"select_list clearfix\"]")).find("li")
let extend_list = []
let key_value_dic = {
"分类": /id\/(.*?).html/,
"地区": /area\/(.*?)\//,
"年份": /year\/(.*?).html/,
"字母": /letter\/(.*?).html/,
"排序": /by\/(.*?)\//,
}
for (let i = 0; i < elements.length; i++) {
let element = elements[i]
let name = $($($(element).find("[class=\"v-tit\"]"))).text().replaceAll("", "")
if (name !== "频道") {
let extend_dic = {"key": (i + 1).toString(), "name": name, "value": []}
for (const ele of $(element).find("a")) {
let type_id = Utils.getStrByRegex(key_value_dic[name], ele.attribs.href)
if (_.isEmpty(type_id)) {
type_id = "/"
}
extend_dic["value"].push({"n": $(ele).text(), "v": decodeURIComponent(type_id)})
}
extend_list.push(extend_dic)
}
}
let sortElments = $("[class=\"v-hd clearfix\"]")
let extend_dic = {"key": (elements.length + 1).toString(), "name": "排序", "value": []}
extend_dic["value"].push({"n": "全部", "v": "/"})
for (const ele of $(sortElments).find("a")) {
let type_id = Utils.getStrByRegex(key_value_dic["排序"], ele.attribs.href)
if (_.isEmpty(type_id)) {
type_id = "/"
}
extend_dic["value"].push({"n": $(ele).text(), "v": type_id})
}
extend_list.push(extend_dic)
return extend_list
}
async setFilterObj() {
for (const class_dic of this.classes) {
let type_id = class_dic["type_id"]
if (type_id !== "最近更新") {
let $ = await this.getHtml(this.siteUrl + `/index.php/vod/show/id/${type_id}.html`)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
getExtend(extend, key, value) {
if (extend[key] !== undefined && extend[key] !== "/") {
return value + "/" + extend[key] + "/"
} else {
return ""
}
}
async setCategory(tid, pg, filter, extend) {
let area = this.getExtend(extend, "3", "area")
let sort = this.getExtend(extend, "6", "by")
let id = this.getExtend(extend, "2", "id")
let letter = this.getExtend(extend, "5", "letter")
let year = this.getExtend(extend, "4", "year")
if (_.isEmpty(id)) {
id = "id/" + tid + "/"
}
let url = this.siteUrl + `/index.php/vod/show/${area}${sort}${id}${letter}${year}page/${pg}.html`
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod", {
"ac": "detail", "ids": id
}, this.getHeader())
this.vodDetail = await this.parseVodDetailfromJson(JSON.parse(content))
}
async setSearch(wd, quick) {
let $ = await this.getHtml(this.siteUrl + "/index.php/vod/search.html?wd="+wd)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new JiaFeiMaoSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,482 +0,0 @@
/*
* @File : jianpian.js
* @Author : jade
* @Date : 2024/1/15 10:32
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 完成荐片所有功能添加弹幕
*/
import {Spider} from "./spider.js";
import {_, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class JianPianSpider extends Spider {
constructor() {
super();
this.siteUrl = "http://api2.rinhome.com"
// this.siteUrl = "https://ownjpykxttjzuhy.jiesiwa.com"
}
getName() {
return "🌼┃荐片┃🌼"
}
getAppName() {
return "荐片"
}
getJSName() {
return "jianpian"
}
getType() {
return 3
}
getHeader() {
return {
"User-Agent": "jianpian-android/360",
"JPAUTH": "y261ow7kF2dtzlxh1GS9EB8nbTxNmaK/QQIAjctlKiEv",
"Referer": "www.jianpianapp.com"
}
}
async spiderInit(inReq=null) {
if (inReq !== null){
this.jsBase = await js2Proxy(inReq,"img",this.getHeader());
}else{
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
await this.spiderInit(null)
}
async parseVodShortListFromJson(data_list) {
let vod_list = [];
for (const data of data_list) {
let vodShort = new VodShort();
vodShort.vod_id = data["id"]
if (data["path"] !== undefined) {
vodShort.vod_pic = this.jsBase + Utils.base64Encode(data["path"])
} else {
vodShort.vod_pic = this.jsBase + Utils.base64Encode(data["thumbnail"])
}
vodShort.vod_name = data["title"]
if (data["mask"] !== undefined){
vodShort.vod_remarks = data["mask"]
}else{
vodShort.vod_remarks = data["playlist"]["title"]
}
vod_list.push(vodShort)
}
return vod_list
}
objToList(list, key, split_value = "*") {
let value_list = []
for (const dic of list) {
value_list.push(dic[key])
}
return value_list.join(split_value)
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail();
vodDetail.vod_id = obj["id"]
vodDetail.vod_year = obj["year"]["title"]
if (!this.catOpenStatus) {
vodDetail.vod_pic = obj["thumbnail"] + "@Referer=www.jianpianapp.com@User-Agent=jianpian-version353@JPAUTH=y261ow7kF2dtzlxh1GS9EB8nbTxNmaK/QQIAjctlKiEv"
} else {
vodDetail.vod_pic = this.jsBase + Utils.base64Encode(obj["thumbnail"])
}
vodDetail.type_name = obj["category"][0]["title"]
vodDetail.vod_name = obj["title"]
vodDetail.vod_content = obj["description"]
vodDetail.vod_area = obj["area"]["title"]
vodDetail.vod_director = this.objToList(obj["directors"], "name")
vodDetail.vod_actor = this.objToList(obj["actors"], "name")
vodDetail.vod_remarks = "评分:" + obj["score"]
let playKeyList = [{"btbo_downlist": "btbo"}, {"xunlei_downlist": "迅雷"}, {"m3u8_downlist": "m3u8"}, {"new_ftp_list": "new_ftp"}, {"new_m3u8_list": "new_m3u8"}]
let playlist = {}
let urlList = []
for (const dic of playKeyList) {
let key = Object.keys(dic)[0]
let value = Object.values(dic)[0]
if (obj[key].length > 0) {
let url_str_list = []
for (const dic of obj[key]) {
url_str_list.push(dic["title"] + "$" + dic["url"])
}
if (urlList.indexOf(url_str_list.join("#")) === -1) {
urlList.push(url_str_list.join("#"))
playlist[value] = url_str_list.join("#")
} else {
await this.jadeLog.warning(`key为:${key},播放链接重复,无需保存`)
}
}
}
vodDetail.vod_play_url = _.values(playlist).join('$$$');
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
return vodDetail
}
async setClasses() {
let type_name_list = ["全部", "电影", "电视剧", "动漫", "综艺"]
let type_id_list = ["0", "1", "2", "3", "4"]
for (let i = 0; i < type_name_list.length; i++) {
let type_name = type_name_list[i]
let type_id = type_id_list[i]
this.classes.push({"type_name": type_name, "type_id": type_id})
}
}
async setFilterObj() {
this.filterObj = {
"0": [{
"key": "area", "name": "地區", "value": [{
"n": "全部", "v": "0"
}, {
"n": "国产", "v": "1"
}, {
"n": "中国香港", "v": "3"
}, {
"n": "中国台湾", "v": "6"
}, {
"n": "美国", "v": "5"
}, {
"n": "韩国", "v": "18"
}, {
"n": "日本", "v": "2"
}]
}, {
"key": "year", "name": "年份", "value": [{
"n": "全部", "v": "0"
}, {
"n": "2024", "v": "119"
}, {
"n": "2023", "v": "153"
}, {
"n": "2022", "v": "101"
}, {
"n": "2021", "v": "118"
}, {
"n": "2020", "v": "16"
}, {
"n": "2019", "v": "7"
}, {
"n": "2018", "v": "2"
}, {
"n": "2017", "v": "3"
}, {
"n": "2016", "v": "22"
}]
}, {
"key": "by", "name": "排序", "value": [{
"n": "热门", "v": "hot"
}, {
"n": "更新", "v": "updata"
}, {
"n": "评分", "v": "rating"
}]
}], "1": [{
"key": "area", "name": "地區", "value": [{
"n": "全部", "v": "0"
}, {
"n": "国产", "v": "1"
}, {
"n": "中国香港", "v": "3"
}, {
"n": "中国台湾", "v": "6"
}, {
"n": "美国", "v": "5"
}, {
"n": "韩国", "v": "18"
}, {
"n": "日本", "v": "2"
}]
}, {
"key": "year", "name": "年份", "value": [{
"n": "全部", "v": "0"
}, {
"n": "2024", "v": "119"
}, {
"n": "2023", "v": "153"
}, {
"n": "2022", "v": "101"
}, {
"n": "2021", "v": "118"
}, {
"n": "2020", "v": "16"
}, {
"n": "2019", "v": "7"
}, {
"n": "2018", "v": "2"
}, {
"n": "2017", "v": "3"
}, {
"n": "2016", "v": "22"
}]
}, {
"key": "by", "name": "排序", "value": [{
"n": "热门", "v": "hot"
}, {
"n": "更新", "v": "updata"
}, {
"n": "评分", "v": "rating"
}]
}], "2": [{
"key": "area", "name": "地區", "value": [{
"n": "全部", "v": "0"
}, {
"n": "国产", "v": "1"
}, {
"n": "中国香港", "v": "3"
}, {
"n": "中国台湾", "v": "6"
}, {
"n": "美国", "v": "5"
}, {
"n": "韩国", "v": "18"
}, {
"n": "日本", "v": "2"
}]
}, {
"key": "year", "name": "年份", "value": [{
"n": "全部", "v": "0"
}, {
"n": "2024", "v": "119"
}, {
"n": "2023", "v": "153"
}, {
"n": "2022", "v": "101"
}, {
"n": "2021", "v": "118"
}, {
"n": "2020", "v": "16"
}, {
"n": "2019", "v": "7"
}, {
"n": "2018", "v": "2"
}, {
"n": "2017", "v": "3"
}, {
"n": "2016", "v": "22"
}]
}, {
"key": "by", "name": "排序", "value": [{
"n": "热门", "v": "hot"
}, {
"n": "更新", "v": "updata"
}, {
"n": "评分", "v": "rating"
}]
}], "3": [{
"key": "area", "name": "地區", "value": [{
"n": "全部", "v": "0"
}, {
"n": "国产", "v": "1"
}, {
"n": "中国香港", "v": "3"
}, {
"n": "中国台湾", "v": "6"
}, {
"n": "美国", "v": "5"
}, {
"n": "韩国", "v": "18"
}, {
"n": "日本", "v": "2"
}]
}, {
"key": "year", "name": "年份", "value": [{
"n": "全部", "v": "0"
}, {
"n": "2024", "v": "119"
}, {
"n": "2023", "v": "153"
}, {
"n": "2022", "v": "101"
}, {
"n": "2021", "v": "118"
}, {
"n": "2020", "v": "16"
}, {
"n": "2019", "v": "7"
}, {
"n": "2018", "v": "2"
}, {
"n": "2017", "v": "3"
}, {
"n": "2016", "v": "22"
}]
}, {
"key": "by", "name": "排序", "value": [{
"n": "热门", "v": "hot"
}, {
"n": "更新", "v": "updata"
}, {
"n": "评分", "v": "rating"
}]
}], "4": [{
"key": "area", "name": "地區", "value": [{
"n": "全部", "v": "0"
}, {
"n": "国产", "v": "1"
}, {
"n": "中国香港", "v": "3"
}, {
"n": "中国台湾", "v": "6"
}, {
"n": "美国", "v": "5"
}, {
"n": "韩国", "v": "18"
}, {
"n": "日本", "v": "2"
}]
}, {
"key": "year", "name": "年份", "value": [{
"n": "全部", "v": "0"
}, {
"n": "2024", "v": "119"
}, {
"n": "2023", "v": "153"
}, {
"n": "2022", "v": "101"
}, {
"n": "2021", "v": "118"
}, {
"n": "2020", "v": "16"
}, {
"n": "2019", "v": "7"
}, {
"n": "2018", "v": "2"
}, {
"n": "2017", "v": "3"
}, {
"n": "2016", "v": "22"
}]
}, {
"key": "by", "name": "排序", "value": [{
"n": "热门", "v": "hot"
}, {
"n": "更新", "v": "updata"
}, {
"n": "评分", "v": "rating"
}]
}]
}
}
async setHomeVod() {
let content = await this.fetch(this.siteUrl + "/api/tag/hand?code=unknown601193cf375db73d&channel=wandoujia", null, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let data_list = content_json["data"][0]["video"]
this.homeVodList = await this.parseVodShortListFromJson(data_list)
}
}
async setCategory(tid, pg, filter, extend) {
let cateId = extend["cateId"] ?? tid
let area = extend["area"] ?? "0";
let year = extend["year"] ?? "0";
let by = extend["by"] ?? "hot";
this.limit = 24
let categoryUrl = this.siteUrl + `/api/crumb/list?area=${area}&category_id=${cateId}&page=${pg}&type=0&limit=24&sort=${by}&year=${year}`
await this.jadeLog.debug(`分类URL:${categoryUrl}`)
let content = await this.fetch(categoryUrl, null, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let data = content_json["data"]
this.vodList = await this.parseVodShortListFromJson(data)
}
}
async setDetail(id) {
let url = this.siteUrl + "/api/node/detail?channel=wandoujia&token=&id=" + id;
let content = await this.fetch(url, null, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content);
let data_list = content_json["data"]
this.vodDetail = await this.parseVodDetailfromJson(data_list)
}
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/api/video/search?page=1" + "&key=" + wd;
const content = await this.fetch(url, null, this.getHeader());
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let data_list = content_json["data"]
this.vodList = await this.parseVodShortListFromJson(data_list)
}
}
async setPlay(flag, id, flags) {
await this.jadeLog.debug(`播放链接为:${id}`)
this.playUrl = id
}
}
let spider = new JianPianSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

View File

@ -1,282 +0,0 @@
/*
* @File : jiujiuliu.js
* @Author : jade
* @Date : 2024/1/4 14:15
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 996影视
*/
import {Spider} from "./spider.js";
import {_, Crypto, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class JiuJiuLiuSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.ojig519d8se.icu"
}
getName() {
return "🔞┃九九六影视┃🔞"
}
getAppName() {
return "九九六影视"
}
getJSName() {
return "jiujiuliu"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"stui-vodlist clearfix\"]").find("li")
for (const vodElement of vodElements) {
let resource = $(vodElement).find("[class=\"stui-vodlist__thumb lazyload\"]")[0]
let vodShort = new VodShort()
vodShort.vod_id = resource.attribs["href"]
vodShort.vod_name = resource.attribs["title"]
vodShort.vod_pic = resource.attribs["data-original"]
vodShort.vod_remarks = $($(resource).find("[class=\"pic-text text-right\"]")[0]).text()
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"stui-pannel_bd\"]").find("li")
for (const vodElement of vodElements) {
let resource = $($(vodElement).find("[class=\"thumb\"]")[0]).find("a")[0]
let vodShort = new VodShort()
vodShort.vod_id = resource.attribs["href"]
vodShort.vod_name = resource.attribs["title"]
vodShort.vod_pic = resource.attribs["data-original"]
vodShort.vod_remarks = Utils.getStrByRegex(/类型:(.*?)地区/, $($(vodElement).find("[class=\"hidden-mi\"]")[0]).text())
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let vodElement = $("[class=\"col-pd clearfix\"]")[1]
let vodShortElement = $(vodElement).find("[class=\"stui-content__thumb\"]")[0]
let vodItems = []
for (const playElement of $("[class=\"stui-content__playlist clearfix\"]").find("a")) {
let episodeUrl = this.siteUrl + playElement.attribs["href"];
let episodeName = $(playElement).text();
vodItems.push(episodeName + "$" + episodeUrl);
}
vodDetail.vod_name = $(vodShortElement).find("[class=\"stui-vodlist__thumb picture v-thumb\"]")[0].attribs["title"]
vodDetail.vod_pic = $(vodShortElement).find("img")[0].attribs["data-original"]
vodDetail.vod_remarks = $($(vodShortElement).find("[class=\"pic-text text-right\"]")[0]).text()
let data_str = $($(vodElement).find("[class=\"data\"]")).text().replaceAll(" ", " ")
vodDetail.type_name = Utils.getStrByRegex(/类型:(.*?) /, data_str)
vodDetail.vod_area = Utils.getStrByRegex(/地区:(.*?) /, data_str)
vodDetail.vod_year = Utils.getStrByRegex(/年份:(.*?) /, data_str)
vodDetail.vod_actor = Utils.getStrByRegex(/主演:(.*?) /, data_str)
vodDetail.vod_director = Utils.getStrByRegex(/导演:(.*?) /, data_str)
vodDetail.vod_content = $($("[class=\"stui-pannel_bd\"]").find("[class=\"col-pd\"]")).text()
vodDetail.vod_play_from = ["996"].join("$$$")
vodDetail.vod_play_url = [vodItems.join("#")].join("$$$")
return vodDetail
}
async setClasses() {
let html = await this.fetch(this.siteUrl, null, this.getHeader(),false,false,0,true)
if (html !== null) {
let $ = load(html)
let menuElements = $("[class=\"stui-header__menu type-slide\"]").find("a")
for (const menuElement of menuElements) {
let type_dic = {
"type_name": $(menuElement).text(),
"type_id": "/show/id/" + menuElement.attribs["href"].split("/").slice(-1)[0].split(".")[0]
}
if ($(menuElement).text() !== "首页") {
this.classes.push(type_dic)
}
}
}
let x = 0
}
async getFilter($) {
let hdElements = $("[class=\"stui-pannel_hd\"]")
let extend_list = []
let index = 0
for (let i = 0; i < 2; i++) {
let cateElemet = hdElements[i]
let typeElements = $(cateElemet).find("ul")
if (i === 0) {
for (const typeElement of typeElements) {
let extend_dic = {
"key": (index + 1).toString(), "name": $($(typeElement).find("li")[0]).text(), "value": []
}
for (const ele of $(typeElement).find("li").slice(1)) {
if (!_.isEmpty($(ele).text())) {
if (index === 0) {
extend_dic["value"].push({
"n": $(ele).text(),
"v": $(ele).find("a")[0].attribs["href"].split("/").slice(-1)[0].split(".")[0]
})
} else {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
}
}
extend_list.push(extend_dic)
index = index + 1
}
} else {
let extend_dic = {
"key": (index + 1).toString(), "name": $($(cateElemet).find("li")[0]).text(), "value": []
}
extend_dic["value"].push({"n": "全部", "v": "time"})
for (const ele of $(cateElemet).find("li").slice(1)) {
if (!_.isEmpty($(ele).text())) {
extend_dic["value"].push({
"n": $(ele).text(), "v": $(ele).find("a")[0].attribs["href"].split("/")[3]
})
}
}
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "/" && type_id !== "最近更新") {
let url = this.siteUrl + type_id + ".html"
let html = await this.fetch(url, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
}
async setHomeVod() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
getParams(params, value) {
let x = value ?? "全部"
if (x === "全部" || x === undefined) {
return ""
} else {
return params + value
}
}
async setCategory(tid, pg, filter, extend) {
let typeName = this.getParams("/id/", extend["1"])
if (_.isEmpty(typeName)) {
typeName = "/id/" + tid.split("/").slice(-1)[0]
}
let plot = this.getParams("/class/", extend["2"])
let area = this.getParams("/area/", extend["3"])
let year = this.getParams("/year/", extend["4"])
let language = this.getParams("/lang/ ", extend["5"])
let letter = this.getParams("/letter/ ", extend["6"])
let time = this.getParams("/by/", extend["7"])
let cateUrl = this.siteUrl + `/show${area}${time}${plot}${typeName}${language}${letter}${year}/page/${pg.toString()}.html`
await this.jadeLog.info(`类别URL为:${cateUrl}`)
this.limit = 36
let html = await this.fetch(cateUrl, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id
let html = await this.fetch(detailUrl, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + `/search.html?wd=${wd}`
let html = await this.fetch(searchUrl, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
let x = 0
}
async setPlay(flag, id, flags) {
let html = await this.fetch(id, null, this.getHeader())
if (html !== null) {
let matcher = Utils.getStrByRegex(/player_aaaa=(.*?)<\/script>/, html)
let player = JSON.parse(matcher);
try {
this.playUrl = decodeURIComponent(Crypto.enc.Utf8.stringify(Crypto.enc.Base64.parse(player["url"])))
this.header = this.getHeader()
} catch (e) {
this.playUrl = player["url"]
}
}
}
}
let spider = new JiuJiuLiuSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,308 +0,0 @@
/*
* @File : kankan70.js
* @Author : jade
* @Date : 2023/12/29 15:33
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import * as Utils from "../lib/utils.js";
import {_, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
function get_qp_name44(qp_type) {
if (qp_type === 'zd') return '最大';
if (qp_type === 'yj') return '永久';
if (qp_type === 'hn') return '牛牛';
if (qp_type === 'gs') return '光波';
if (qp_type === 'sn') return '新朗';
if (qp_type === 'wl') return '涡轮';
if (qp_type === 'lz') return '良子';
if (qp_type === 'fs') return 'F速';
if (qp_type === 'ff') return '飞飞';
if (qp_type === 'bd') return '百度';
if (qp_type === 'uk') return '酷U';
if (qp_type === 'wj') return '无天';
if (qp_type === 'bj') return '八戒';
if (qp_type === 'tk') return '天空';
if (qp_type === 'ss') return '速速';
if (qp_type === 'kb') return '酷播';
if (qp_type === 'sd') return '闪电';
if (qp_type === 'xk') return '看看';
if (qp_type === 'tp') return '淘淘';
if (qp_type === 'jy') return '精英';
return qp_type;
}
class Kankan70Spider extends Spider {
constructor() {
super();
this.siteUrl = "http://cqdb6.com";
}
getName() {
return "📺┃70看看┃📺"
}
getAppName() {
return "70看看"
}
getJSName() {
return "kankan70"
}
getType() {
return 3
}
paraseUrlObject(js_str) {
let content_list = js_str.split(";")
let urlObject = {}
let js_name = ""
let play_id = 0
let pldy_id = 0
let js_key = ""
for (let i = 0; i < content_list.length; i++) {
let content = content_list[i]
if (content.indexOf("var lianzaijs") > -1) {
js_name = content.split("=")[0].split(" ")[1]
js_key = js_name.split("_")[1]
} else if (content.indexOf("pl_id=") > -1) {
play_id = content.split("=")[1]
urlObject[js_name] = {"play_id": play_id, "list": [], "pl_dy": pldy_id}
} else if (content.indexOf("var pl_dy") > -1) {
pldy_id = content.split("=")[1]
}
if (content.indexOf(`playarr_${js_key}[`) > -1) {
let play_url = content.split("=\"")[1].split(",")[0]
urlObject[js_name]["list"].push(play_url)
}
}
let play_url_list = [], play_format_list = [];
for (const key of Object.keys(urlObject)) {
if (key.indexOf("_") > -1) {
let play_format_name = get_qp_name44(key.split("_")[1])
play_format_list.push(play_format_name)
let vodItems = []
let index = 0
for (const play_url of urlObject[key]["list"]) {
index = index + 1
vodItems.push("第" + index.toString() + "集" + "$" + play_url)
}
play_url_list.push(vodItems.join("#"))
}
}
return {"play_format": play_format_list.join("$$$"), "play_url": play_url_list.join("$$$")}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vod_elements = $("a.li-hv")
for (const vod_element of vod_elements) {
let vodShort = new VodShort()
vodShort.vod_id = "/" + vod_element.attribs["href"]
vodShort.vod_name = vod_element.attribs["title"]
vodShort.vod_pic = $(vod_element).find("img")[0].attribs["data-original"]
let remarkEle = $(vod_element).find("p.bz")[0]
if (remarkEle.length > 0) {
vodShort.vod_remarks = remarkEle.children[0].data
}
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let infoElement = $("[class=info]")
let dtElement = $(infoElement).find("dt.name")[0]
vodDetail.vod_name = dtElement.children[0].data
vodDetail.vod_remarks = dtElement.children[1].children[0].data
let ddString = $(infoElement).find("dd").text()
vodDetail.vod_area = Utils.getStrByRegex(/地区:(.*?) /, ddString)
vodDetail.vod_year = Utils.getStrByRegex(/年代:(.*?)\n/, ddString)
vodDetail.type_name = Utils.getStrByRegex(/类型:(.*?)\n/, ddString)
vodDetail.vod_content = $(infoElement).find("[class=des2]").text().replaceAll("\n", "").replaceAll("剧情:", "")
vodDetail.vod_pic = $("img.lazy")[0].attribs["data-original"]
return vodDetail
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const vod_object of obj) {
let vodShort = new VodShort()
vodShort.vod_id = vod_object["url"]
vodShort.vod_pic = vod_object["thumb"]
vodShort.vod_remarks = vod_object["time"]
vodShort.vod_name = vod_object["title"]
vod_list.push(vodShort)
}
return vod_list
}
async setClasses() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
let elements = $("[class=index-list-l]")
for (const element of elements) {
let typeElement = $($(element).find("[class=\"h1 clearfix\"]")[0]).find("a")
let type_id = typeElement[0].attribs["href"]
let type_name = $(typeElement[1]).text()
if (!_.isEmpty(type_name)) {
this.classes.push({"type_id": type_id, "type_name": type_name})
}
}
}
}
async getFilter(type_id) {
let url = this.siteUrl + type_id
let html = await this.fetch(url, null, this.getHeader())
let extend_list = []
if (!_.isEmpty(html)) {
let $ = load(html)
let elements = $("[class=\"sy scon clearfix\"]").find("dl")
let i = 0
for (const element of elements) {
let type_name = $($(element).find("dt")).text().replace("按", "").replace("", "")
let extend_dic = {
"key": (i + 1).toString(), "name": type_name, "value": []
}
let type_elements = $(element).find("a")
let index = 0
if (type_name === "剧情") {
index = 3
} else if (type_name === "年代") {
index = 2
} else if (type_name === "地区") {
index = 4
}
for (const type_element of type_elements) {
let type_id_list = type_element.attribs["href"].split("/")
extend_dic["value"].push({"n": $(type_element).text(), "v": type_id_list[index]})
}
extend_list.push(extend_dic)
i = i + 1
}
}
return extend_list
}
async setFilterObj() {
for (const class_dic of this.classes) {
let type_id = class_dic["type_id"]
if (type_id !== "最近更新") {
this.filterObj[type_id] = await this.getFilter(type_id)
}
}
}
async setHomeVod() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
async setCategory(tid, pg, filter, extend) {
let url = this.siteUrl + tid
let html = await this.fetch(url, null, this.getHeader())
if (!_.isEmpty(html)) {
let class_name = tid.split("/")[1]
let id = tid.split("/")[2]
let api_str = Utils.getStrByRegex(/var _yu_gda_s="(.*?)";/, html)
let params = {
"action": class_name,
"page": parseInt(pg),
"year": extend["2"] ?? "0",
"area": extend["3"] ?? "all",
"class": extend["1"] ?? "0",
"dect": "",
"id": id
}
let cate_html = await this.fetch(api_str, params, this.getHeader())
if (cate_html !== null) {
let $ = load(cate_html)
this.vodList = await this.parseVodShortListFromDoc($)
}
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id
let html = await this.fetch(detailUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
let mather = /<script type="text\/javascript" src="http:\/\/test.gqyy8.com:8077\/ne2(.*?)"><\/script>/g.exec(html)
let js_url = "http://test.gqyy8.com:8077/ne2" + mather[1]
let js_str = await this.fetch(js_url, null, this.getHeader())
if (!_.isEmpty(js_str)) {
let playObject = this.paraseUrlObject(js_str)
this.vodDetail.vod_play_url = playObject["play_url"]
this.vodDetail.vod_play_from = playObject["play_format"]
}
}
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/search.php"
let html = await this.fetch(url, null, this.getHeader())
if (!_.isEmpty(html)) {
let params = {
"top": 10, "q": wd,
}
let api_url = Utils.getStrByRegex(/var my_search='(.*?)';/, html)
let content = await this.fetch(api_url, params, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content.replaceAll("",""))
this.vodList = await this.parseVodShortListFromJson(content_json)
}
}
}
}
let spider = new Kankan70Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,444 +0,0 @@
/*
* @File : kuaikan.js
* @Author : jade
* @Date : 2024/3/19 11:12
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {jinja2, _, dayjs, Crypto} from "../lib/cat.js";
import {Spider} from "./spider.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
const charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789';
function randStr(len, withNum) {
let _str = '';
let containsNum = withNum === undefined ? true : withNum;
for (let i = 0; i < len; i++) {
let idx = _.random(0, containsNum ? charStr.length - 1 : charStr.length - 11);
_str += charStr[idx];
}
return _str;
}
function randDevice() {
return {
brand: 'Huawei',
model: 'HUAWEI Mate 20',
release: '10',
buildId: randStr(3, false).toUpperCase() + _.random(11, 99) + randStr(1, false).toUpperCase(),
};
}
function formatPlayUrl(src, name) {
return name
.trim()
.replaceAll(src, '')
.replace(/<|>|《|》/g, '')
.replace(/\$|#/g, ' ')
.trim();
}
function jsonParse(input, json) {
try {
let url = json.url ?? '';
if (url.startsWith('//')) {
url = 'https:' + url;
}
if (!url.startsWith('http')) {
return {};
}
let headers = json['headers'] || {};
let ua = (json['user-agent'] || '').trim();
if (ua.length > 0) {
headers['User-Agent'] = ua;
}
let referer = (json['referer'] || '').trim();
if (referer.length > 0) {
headers['Referer'] = referer;
}
_.keys(headers).forEach((hk) => {
if (!headers[hk]) delete headers[hk];
});
return {
header: headers, url: url,
};
} catch (error) {
}
return {};
}
class KuaiKanSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://api1.baibaipei.com:8899';
this.device = {}
this.parse = []
}
getName() {
return "🛥︎┃快看视频┃🛥︎"
}
getAppName() {
return "快看视频"
}
getJSName() {
return "kuaikan"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
await this.setDevice();
}
async request(reqUrl, postData, agentSp, get) {
let ts = dayjs().valueOf().toString();
let rand = randStr(32);
let sign = Crypto.enc.Hex.stringify(Crypto.MD5('H58d2%gLbeingX*%D4Y8!C!!@G_' + ts + '_' + rand))
.toString()
.toLowerCase();
let headers = {
'user-agent': agentSp || this.device.ua,
};
if (reqUrl.includes('baibaipei')) {
headers['device-id'] = this.device.id;
headers['sign'] = sign;
headers['time'] = ts;
headers['md5'] = rand;
headers['version'] = '2.1.5';
headers['system-model'] = this.device.model;
headers['system-brand'] = this.device.brand;
headers['system-version'] = this.device.release;
headers["host"] = "api1.baibaipei.com:8899"
}
if (!get) {
headers['Content-Type'] = 'application/x-www-form-urlencoded';
}
let res = await req(reqUrl, {
method: get ? 'get' : 'post', headers: headers, data: postData || {}, postType: 'form'
});
await this.jadeLog.debug(`URL:${reqUrl},headers:${JSON.stringify(headers)},data:${[JSON.stringify(postData)]}`)
let content = res.content;
try {
let key = Crypto.enc.Utf8.parse('IjhHsCB2B5^#%0Ag');
let iv = Crypto.enc.Utf8.parse('y8_m.3rauW/>j,}.');
let src = Crypto.enc.Base64.parse(content);
let dst = Crypto.AES.decrypt({ciphertext: src}, key, {iv: iv, padding: Crypto.pad.Pkcs7});
dst = Crypto.enc.Utf8.stringify(dst);
await this.jadeLog.debug(`response:${dst}`)
return JSON.parse(dst);
} catch (e) {
return JSON.parse(content)
}
}
async setDevice() {
let deviceKey = 'device';
let deviceInfo = await local.get(this.siteKey, deviceKey);
if (deviceInfo.length > 0) {
try {
this.device = JSON.parse(deviceInfo);
} catch (error) {
}
}
if (_.isEmpty(this.device)) {
this.device = randDevice();
this.device.id = randStr(13).toLowerCase();
this.device.ua = 'okhttp/3.14.9';
await local.set(this.siteKey, deviceKey, JSON.stringify(this.device));
}
}
async setClasses() {
await this.setDevice()
let response = await this.request(this.siteUrl + '/api.php/Index/getTopVideoCategory');
for (const type of response.data) {
let typeName = type["nav_name"];
if (typeName === '推荐') continue;
let typeId = type["nav_type_id"].toString();
this.classes.push({
type_id: typeId, type_name: typeName,
});
}
}
async getFilter(filterData) {
await this.jadeLog.debug(JSON.stringify(filterData))
let filterAll = []
for (let key of Object.keys(filterData)) {
let itemValues = filterData[key];
if (key === 'plot') key = 'class';
let typeExtendName = '';
switch (key) {
case 'class':
typeExtendName = '类型';
break;
case 'area':
typeExtendName = '地区';
break;
case 'lang':
typeExtendName = '语言';
break;
case 'year':
typeExtendName = '年代';
break;
case 'sort':
typeExtendName = '排序';
break;
}
if (typeExtendName.length === 0) continue;
let newTypeExtend = {
key: key, name: typeExtendName,
};
let newTypeExtendKV = [];
for (let j = 0; j < itemValues.length; j++) {
const name = itemValues[j];
let value = key === 'sort' ? j + '' : name === '全部' ? '0' : name;
newTypeExtendKV.push({n: name, v: value});
}
newTypeExtend['init'] = key === 'sort' ? '1' : newTypeExtendKV[0]['v'];
newTypeExtend.value = newTypeExtendKV;
filterAll.push(newTypeExtend);
}
return filterAll
}
async setFilterObj() {
for (const typeDic of this.classes) {
let typeId = typeDic["type_id"]
if (typeId !== "最近更新") {
let filterData = await this.request(this.siteUrl + '/api.php/Video/getFilterType', {type: typeId})
this.filterObj[typeId] = await this.getFilter(filterData["data"])
}
}
}
async parseVodShortListFromJSONByHome(obj) {
let vod_list = []
for (const data of obj["video"]) {
let video_vod_list = await this.parseVodShortListFromJson(data["list"])
vod_list.push(...video_vod_list)
}
return vod_list
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const data of obj) {
let vodShort = new VodShort()
vodShort.vod_id = data["vod_id"]
vodShort.vod_name = data["vod_name"]
vodShort.vod_pic = data["vod_pic"]
vodShort.vod_remarks = data["vod_remarks"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail()
vodDetail.load_dic(JSON.stringify(obj))
vodDetail.vod_content = obj["vod_content"].trim()
vodDetail.type_name = obj["vod_class"]
let playlist = {};
for (const item of obj["vod_play"]) {
let from = item["playerForm"];
if (from === 'jp' && this.catOpenStatus) continue;
if (from === 'xg' && this.catOpenStatus) continue;
let urls = [];
for (const u of item.url) {
urls.push(formatPlayUrl(vodDetail.vod_name, u.title) + '$' + u.play_url);
}
if (!playlist.hasOwnProperty(from) && urls.length > 0) {
playlist[from] = urls;
}
}
this.parse = obj.parse || [];
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
let urls = _.values(playlist);
let vod_play_url = [];
for (const urlist of urls) {
vod_play_url.push(urlist.join('#'));
}
vodDetail.vod_play_url = vod_play_url.join('$$$');
return vodDetail
}
async setHomeVod() {
let data = await this.request(this.siteUrl + "/api.php/Index/getHomePage", {"p": "1", "type": "1"})
this.homeVodList = await this.parseVodShortListFromJSONByHome(data.data)
}
async setCategory(tid, pg, filter, extend) {
if (pg === 0) pg = 1;
let reqUrl = this.siteUrl + '/api.php/Video/getFilterVideoList';
let formData = JSON.parse(jinja2(`{
"type": "{{tid}}",
"p": "{{pg}}",
"area": "{{ext.area|default(0)}}",
"year": "{{ext.year|default(0)}}",
"sort": "{{ext.sort|default(0)}}",
"class": "{{ext.class|default(0)}}"}`, {ext: extend, tid: tid, pg: pg}));
console.log(formData);
let data = await this.request(reqUrl, formData);
this.vodList = await this.parseVodShortListFromJson(data["data"]["data"])
}
async setDetail(id) {
let data = await this.request(this.siteUrl + '/api.php/Video/getVideoInfo', {video_id: id})
this.vodDetail = await this.parseVodDetailfromJson(data["data"]["video"])
}
async setPlay(flag, id, flags) {
this.result.jx = 0
try {
if (id.indexOf('youku') >= 0 || id.indexOf('iqiyi') >= 0 || id.indexOf('v.qq.com') >= 0 || id.indexOf('pptv') >= 0 || id.indexOf('le.com') >= 0 || id.indexOf('1905.com') >= 0 || id.indexOf('mgtv') >= 0)
{
if (this.parse.length > 0) {
for (let index = 0; index < this.parse.length; index++) {
try {
const p = this.parse[index];
let res = await req(p + id, {
headers: {'user-agent': 'okhttp/4.1.0'},
});
await this.jadeLog.debug(`解析连接结果为:${JSON.stringify(res)}`)
let result = jsonParse(id, JSON.parse(res.content)["data"]);
if (result.url){
this.playUrl = result.url // 这里可以直接返回弹幕,无法进行快进操作
this.danmuUrl = await this.danmuSpider.getVideoUrl(id,0)
this.result.jx = 1
}
} catch (error) {
}
}
}
} else if (id.indexOf('jqq-') >= 0) {
let jqqHeaders = await this.request(this.siteUrl + '/jqqheader.json', null, null, true);
let ids = id.split('-');
let jxJqq = await req('https://api.juquanquanapp.com/app/drama/detail?dramaId=' + ids[1] + '&episodeSid=' + ids[2] + '&quality=LD', {headers: jqqHeaders});
let jqqInfo = JSON.parse(jxJqq.content);
if (jqqInfo.data["playInfo"]["url"]) {
this.playUrl = jqqInfo.data["playInfo"]["url"]
}
} else if (id.startsWith("ftp")) {
this.playUrl = id
} else {
let res = await this.request(this.siteUrl + '/video.php', {url: id});
let result = jsonParse(id, res.data);
if (result.url) {
if (result.url.indexOf("filename=1.mp4") > -1) {
this.playUrl = result.url
} else {
this.playUrl = await js2Proxy(true, this.siteType, this.siteKey, 'lzm3u8/' + Utils.base64Encode(result.url), {});
}
}
}
} catch (e) {
await this.jadeLog.error(e)
}
}
async setSearch(wd, quick) {
let data = await this.request(this.siteUrl + '/api.php/Search/getSearch', {key: wd, type_id: 0, p: 1})
this.vodList = await this.parseVodShortListFromJson(data["data"]["data"])
}
async proxy(segments, headers) {
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'lzm3u8') {
await this.jadeLog.debug(`使用代理播放,播放连接为:${url}`)
const resp = await req(url, {});
let hls = resp.content;
const jsBase = await js2Proxy(false, this.siteType, this.siteKey, 'lzm3u8/', {});
const baseUrl = url.substr(0, url.lastIndexOf('/') + 1);
await this.jadeLog.debug(hls.length)
hls = hls.replace(/#EXT-X-DISCONTINUITY\r*\n*#EXTINF:6.433333,[\s\S]*?#EXT-X-DISCONTINUITY/, '');
await this.jadeLog.debug(hls.length)
hls = hls.replace(/(#EXT-X-KEY\S+URI=")(\S+)("\S+)/g, function (match, p1, p2, p3) {
let up = (!p2.startsWith('http') ? baseUrl : '') + p2;
return p1 + up + p3;
});
hls = hls.replace(/(#EXT-X-STREAM-INF:.*\n)(.*)/g, function (match, p1, p2) {
let up = (!p2.startsWith('http') ? baseUrl : '') + p2;
return p1 + jsBase + Utils.base64Decode(up);
});
hls = hls.replace(/(#EXTINF:.*\n)(.*)/g, function (match, p1, p2) {
let up = (!p2.startsWith('http') ? baseUrl : '') + p2;
return p1 + up;
});
return JSON.stringify({
code: resp.code, content: hls, headers: resp.headers,
});
}
return JSON.stringify({
code: 500, content: '',
});
}
}
let spider = new KuaiKanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,93 +0,0 @@
/*
* @File : liangzi.js
* @Author : jade
* @Date : 2024/1/24 9:15
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 量子资源
*/
import {VodSpider} from "./vodSpider.js";
class LiangziSpider extends VodSpider {
constructor() {
super();
this.siteUrl = "https://cj.lzcaiji.com"
this.remove18 = true
}
getAppName() {
return "量子资源"
}
getName() {
return "🐝┃量子资源┃🐝"
}
getJSName() {
return "liangzi"
}
getType() {
return 3
}
async spiderInit(inReq) {
await super.spiderInit(inReq);
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
}
let spider = new LiangziSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,93 +0,0 @@
/*
* @File : liangzi18.js
* @Author : jade
* @Date : 2024/1/24 9:15
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 量子资源18
*/
import {VodSpider} from "./vodSpider.js";
class Liangzi18Spider extends VodSpider {
constructor() {
super();
this.siteUrl = "https://cj.lzcaiji.com"
this.remove18 = false
}
getAppName() {
return "量子资源18+"
}
getName() {
return "🔞┃量子资源18+┃🔞"
}
getJSName() {
return "liangzi18"
}
getType() {
return 3
}
async spiderInit(inReq) {
await super.spiderInit(inReq);
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
}
let spider = new Liangzi18Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,260 +0,0 @@
/*
* @File : liujiushu.js
* @Author : jade
* @Date : 2024/04/23 10:02
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {BookDetail, BookShort} from "../lib/book.js";
import {formatContent} from "../lib/utils.js";
class LiuJiuShuSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.diyi69.com"
}
getAppName() {
return "六九书吧"
}
getJSName() {
return "liujiushu"
}
getType() {
return 10
}
getName() {
return "📚︎┃六九书吧┃📚︎"
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
parseVodShortFromElement($, element) {
let bookShort = new BookShort()
let bookShortElements = $(element).find("a")
bookShort.book_remarks = $(bookShortElements[2]).text()
bookShort.book_name = $(bookShortElements[1]).text()
bookShort.book_id = bookShortElements[0].attribs.href
bookShort.book_pic = $(element).find("img")[0].attribs["src"]
return bookShort
}
async parseVodShortListFromDoc($) {
let books = []
let bookElements = $($("[class=\"flex\"]")[0]).find("li")
for (const bookElement of bookElements) {
let bookShort = this.parseVodShortFromElement($, bookElement)
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocByCategory($) {
let bookElements = $("ul.flex > li")
let books = [];
for (const item of bookElements) {
let bookShort = new BookShort()
bookShort.book_id = $(item).find('a:first')[0].attribs.href;
const img = $(item).find('img:first')[0];
bookShort.book_name = img.attribs.title
bookShort.book_pic = img.attribs["data-original"]
bookShort.book_remarks = $($(item).find('em:first')).text();
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocBySearch($) {
let books = []
let bookElements = $('li.searchresult')
for (const bookElement of bookElements) {
let bookShort = new BookShort()
let bookShortElements = $(bookElement).find("a")
bookShort.book_remarks = $(bookShortElements[2]).text()
bookShort.book_name = $(bookShortElements[1]).text()
bookShort.book_id = bookShortElements[0].attribs.href
bookShort.book_pic = $(bookShortElements[0]).find("img")[0].attribs["data-original"]
books.push(bookShort)
}
return books
}
async parseVodDetailFromDoc($, id) {
let html = $.html()
let bookDetail = new BookDetail()
bookDetail.book_name = $('[property$=title]')[0].attribs.content
bookDetail.book_year = $('[property$=update_time]')[0].attribs.content
bookDetail.book_director = $('[property$=author]')[0].attribs.content
bookDetail.book_content = $('[property$=description]')[0].attribs.content
bookDetail.book_remarks = $('[property$=category]')[0].attribs.content
bookDetail.book_pic = $('div.novel_info_main>img')[0].attribs.src
bookDetail.book_id = id
const playBook = {};
const sectionsElements = $("[class=\"flex ulcard\"]").find("li")
const urlElements = $("[class=\"section chapter_list\"]")
for (let i = 0; i < sectionsElements.length; i++) {
const sectionElement = sectionsElements[i]
const urlElemnet = urlElements[i]
let vodItems = []
for (const urlEle of $(urlElemnet).find("a")) {
const epName = $(urlEle).text();
const playUrl = epName + "-" + urlEle.attribs.href;
vodItems.push(epName + '$' + playUrl)
}
let name = $($(urlElemnet).find("[class=\"title jcc\"]")).text()
if (_.isEmpty(name)) {
let text = $(sectionElement).text().split("")[0]
playBook[text] = vodItems.join("#")
} else {
name = name.replaceAll("《","").replaceAll("》","").replaceAll(bookDetail.book_name,"")
playBook[name] = vodItems.reverse().join("#")
}
}
bookDetail.volumes = _.keys(playBook).join('$$$');
bookDetail.urls = _.values(playBook).join('$$$');
return bookDetail
}
async setClasses() {
let $ = await this.getHtml()
for (const a of $('div.navigation > nav > a[href!="/"]')) {
let type_id_list = a.attribs.href.split("/").slice(0, 3)
this.classes.push({
type_id: type_id_list.join("/"), type_name: a.children[0].data.trim(), tline: 2,
});
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($, id)
}
async setCategory(tid, pg, filter, extend) {
let $ = await this.getHtml(this.siteUrl + `${tid}/${pg}.html`);
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setPlay(flag, id, flags) {
let id_list = id.split("-")
id = id_list[1]
let content = id_list[0] + "\n\n"
while (true) {
let $ = await this.getHtml(this.siteUrl + id)
content += Utils.formatContent($("[class=\"content\"]").html().trim().replaceAll("<p>", " ").replaceAll("</p>", "\n"));
id = $("[id=\"next_url\"]")[0].attribs.href;
if (id.indexOf('_') < 0) break;
}
this.playUrl = {"content": content}
}
async setSearch(wd, quick) {
let params = {"searchkey": wd, "searchtype": "all", "Submit": ""}
let content = await this.fetch(this.siteUrl + "/search/", params, this.getHeader())
let $ = load(content)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
async proxy(segments, headers) {
await this.jadeLog.debug(`正在设置反向代理 segments = ${segments.join(",")},headers = ${JSON.stringify(headers)}`)
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'img') {
await this.jadeLog.debug(`反向代理ID为:${url}`)
let $ = await this.getHtml(this.siteUrl + url)
let bookDetail = await this.parseVodDetailFromDoc($)
let resp;
if (!_.isEmpty(headers)) {
resp = await req(bookDetail.book_pic, {
buffer: 2, headers: headers
});
} else {
resp = await req(bookDetail.book_pic, {
buffer: 2, headers: {
Referer: url, 'User-Agent': Utils.CHROME,
},
});
}
return JSON.stringify({
code: resp.code, buffer: 2, content: resp.content, headers: resp.headers,
});
}
return JSON.stringify({
code: 500, content: '',
});
}
}
let spider = new LiuJiuShuSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,328 +0,0 @@
/*
* @File : lovemovie.js
* @Author : jade
* @Date : 2024/4/29 09:36
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 爱情电影网
*/
import {Spider} from "./spider.js";
import {_, Crypto, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
import {gbk_us} from "../lib/gbk_us.js";
class LoveMovieSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://b.aqdyje.com"
this.removeKey = "骑兵营"
}
getName() {
return "💕┃爱情电影网┃💕"
}
getAppName() {
return "爱情电影网"
}
getJSName() {
return "lovemovie"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
}
async getHtml(url = this.siteUrl, proxy = false, headers = this.getHeader()) {
let buffer = await this.fetch(url, null, headers, false, false, 1, proxy)
let html = Utils.decode(buffer, "gb2312")
await this.jadeLog.debug(`html content:${html}`)
if (!_.isEmpty(html)) {
return load(html)
} else {
return load(gbkDecode(buffer))
}
}
async getFilter($, navElements) {
let extend_list = []
let extend_dic = {"key": "class", "name": "类型", "value": [this.getFliterDic("全部", "全部")]}
for (const navElement of $(navElements).find("li")) {
let element = $(navElement).find("a")[0]
let type_name = $(element).text()
let type_id = element.attribs.href
extend_dic["value"].push(this.getFliterDic(type_name, type_id))
}
if (extend_dic["value"].length > 1) {
extend_list.push(extend_dic)
}
return extend_list
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $("[class=\"nav-item drop-down \"]")
for (const navElement of navElements) {
let elemenet = $(navElement).find("a")[0]
let type_name = $(elemenet).text()
let type_id = elemenet.attribs.href
if (type_name !== this.removeKey) {
this.classes.push(this.getTypeDic(type_name, type_id))
this.filterObj[type_id] = await this.getFilter($, navElement)
}
}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"play-img\"]")
if (vodElements.length === 0) {
vodElements = $("[class=\"show-list list-mode fn-clear\"]").find("li")
}
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = vodElement.attribs.href
if (_.isEmpty(vodShort.vod_id)) {
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
}
let imgElement = $(vodElement).find("img")[0]
vodShort.vod_pic = imgElement.attribs.src
vodShort.vod_name = imgElement.attribs.alt
for (const element of $(vodElement).find("label")) {
let text = $(element).text().trim()
if (!_.isEmpty(text)) {
vodShort.vod_remarks = text
break
}
}
if (_.isEmpty(vodShort.vod_remarks)) {
vodShort.vod_remarks = $($(vodElement).find("p")[0]).text().replace("\n")
}
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vodElements = $("[class=\"show-list\"]").find("li")
let vod_list = []
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
let imgElement = $(vodElement).find("img")[0]
vodShort.vod_pic = imgElement.attribs.src
vodShort.vod_name = imgElement.attribs.alt
vodShort.vod_remarks = $($(vodElement).find("[class=\"type fn-left\"]")).text().replace("类型:", "")
if (vodShort.vod_remarks !== "社处片" && vodShort.vod_remarks !== "社保片" && vodShort.vod_remarks !== "撸丝片" && vodShort.vod_remarks !== "撸丝动漫") {
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let imgElement = $("[class=\"detail-pic fn-left\"]").find("img")[0]
vodDetail.vod_pic = imgElement.attribs.src
vodDetail.vod_name = imgElement.attribs.alt
let vodInfoElement = $("[class=\"info fn-clear\"]")
for (const vodDlElement of $(vodInfoElement).find("dl")) {
let text = $(vodDlElement).text()
if (text.indexOf("主演") > -1) {
vodDetail.vod_actor = text.replaceAll("主演:", "").replaceAll("\n", "")
}
if (text.indexOf("状态") > -1) {
vodDetail.vod_remarks = text.replaceAll("状态:", "").replaceAll("\n", "")
}
if (text.indexOf("类型") > -1) {
vodDetail.type_name = text.replaceAll("类型:", "").replaceAll("\n", "")
}
if (text.indexOf("地区") > -1) {
vodDetail.vod_area = text.replaceAll("地区:", "").replaceAll("\n", "")
}
if (text.indexOf("导演") > -1) {
vodDetail.vod_director = text.replaceAll("导演:", "").replaceAll("\n", "")
}
if (text.indexOf("年份") > -1) {
vodDetail.vod_year = text.replaceAll("年份:", "").replaceAll("\n", "")
}
if (text.indexOf("剧情") > -1) {
vodDetail.vod_content = text.replaceAll("剧情:", "").replaceAll("\n", "")
}
}
let playList = {}
let html = $.html()
let playListElements = $("[class=\"play-list\"]")
let index = 1
for (const playListElement of playListElements) {
let playName = `播放连接-${index}`
let vodItems = []
for (const playUrlElement of $(playListElement).find("a")) {
let playUrlName = playUrlElement.attribs.title
let playUrl = playUrlElement.attribs.href
vodItems.push(playUrlName + "$" + playUrl)
}
playList[playName] = vodItems.join("#")
index = index + 1
}
index = 1
let ciliListElements = $("[class=\"con4\"]")
for (const ciliListElement of ciliListElements) {
let playName = `磁力链接-${index}`
let vodItems = []
let playUrlName = playName
let playUrl = $($(ciliListElement).find("div")).find("a")[0].attribs.href
if (playUrl !== "javascript:void(0);") {
vodItems.push(playUrlName + "$" + playUrl)
playList[playName] = vodItems.join("#")
index = index + 1
}
}
vodDetail.vod_play_url = _.values(playList).join('$$$');
vodDetail.vod_play_from = _.keys(playList).join('$$$');
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
getExtend(extend) {
if (extend["class"] !== undefined) {
if (extend["class"] !== "全部") {
return extend["class"]
}
}
return undefined
}
async setCategory(tid, pg, filter, extend) {
let classes = this.getExtend(extend) ?? tid
let url
if (classes === tid) {
url = this.siteUrl + classes
} else {
if (parseInt(pg) === 1) {
url = this.siteUrl + classes
} else {
url = this.siteUrl + classes + `index${pg}.html`
}
}
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setPlay(flag, id, flags) {
if (flag.indexOf("磁力") > -1) {
this.playUrl = id
} else {
let idSplitList = id.split("-")
let flag_id = parseInt(idSplitList[1])
let episode = parseInt(idSplitList[2].split(".")[0])
let $ = await this.getHtml(this.siteUrl + id)
let playJsUrl = Utils.getStrByRegex(/<script type="text\/javascript" src="(.*?)">/, $.html())
let playJsContent = await this.fetch(this.siteUrl + playJsUrl, null, this.getHeader())
let playUrlListStr = Utils.getStrByRegex(/var VideoListJson=(.*?),urlinfo=/, playJsContent)
let playDic = eval(playUrlListStr)
this.playUrl = playDic[flag_id][1][episode].split("$")[1]
if (this.playUrl.indexOf("m3u8") === -1) {
let html = await this.fetch(this.playUrl, null, this.getHeader())
this.playUrl = Utils.getStrByRegex(/url: '(.*?)'/, html)
}
}
}
GBKEncode(str) {
var arr_index = 0x8140; //33088;
str += '';
var gbk = [];
var wh = '?'.charCodeAt(0); //gbk中没有的字符的替换符
for (var i = 0; i < str.length; i++) {
var charcode = str.charCodeAt(i);
if (charcode < 0x80) gbk.push(charcode);
else {
var gcode = gbk_us.indexOf(charcode);
if (~gcode) {
gcode += arr_index;
gbk.push(0xFF & (gcode >> 8), 0xFF & gcode);
} else {
gbk.push(wh);
}
}
}
return gbk;
}
encode(str) {
let encodeStr = ""
for (const ch of str) {
let bitArr = this.GBKEncode(ch);
for (let i = 0; i < bitArr.length; i++) {
bitArr[i] = '%' + ('0' + bitArr[i].toString(16)).substr(-2).toUpperCase();
}
encodeStr = encodeStr + bitArr.join('');
}
return encodeStr
}
async setSearch(wd, quick) {
let params = {"searchword": this.encode(wd)}
let buffer = await this.post(this.siteUrl + "/search.asp", params, this.getHeader(), "form", 1)
let $ = load(Utils.decode(buffer, "gb2312"))
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new LoveMovieSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider, LoveMovieSpider}

View File

@ -1,133 +0,0 @@
/*
* @File : lovemovie18.js
* @Author : jade
* @Date : 2024/4/29 09:36
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 爱情电影网
*/
import {LoveMovieSpider} from "./lovemovie.js";
import {VodShort} from "../lib/vod.js";
class LoveMovie18Spider extends LoveMovieSpider {
constructor() {
super();
this.siteUrl = "https://b.aqdyje.com"
this.removeKey = "骑兵营"
}
getName() {
return "🔞┃爱情电影网18+┃🔞"
}
getAppName() {
return "爱情电影网18+"
}
getJSName() {
return "lovemovie18"
}
getType() {
return 3
}
async parseVodShortListFromDocBySearch($) {
let vodElements = $("[class=\"show-list\"]").find("li")
let vod_list = []
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
let imgElement = $(vodElement).find("img")[0]
vodShort.vod_pic = imgElement.attribs.src
vodShort.vod_name = imgElement.attribs.alt
vodShort.vod_remarks = $($(vodElement).find("[class=\"type fn-left\"]")).text().replace("类型:", "")
if (vodShort.vod_remarks === "社处片" || vodShort.vod_remarks === "社保片" || vodShort.vod_remarks === "撸丝片" || vodShort.vod_remarks === "撸丝动漫") {
vod_list.push(vodShort)
}
}
return vod_list
}
async getFilter(type_id) {
let $ = await this.getHtml(this.siteUrl + type_id)
let extend_list = []
let extend_dic = {"key": "class", "name": "类型", "value": []}
for (const navElement of $("[class=\"subnav-tv fn-left\"]").find("a")) {
let type_name = $(navElement).text()
let type_id = navElement.attribs.href
extend_dic["value"].push(this.getFliterDic(type_name, type_id))
}
if (extend_dic["value"].length > 1) {
extend_list.push(extend_dic)
}
return extend_list
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $("[class=\"nav-item drop-down \"]")
this.classes = []
for (const navElement of navElements) {
let element = $(navElement).find("a")[0]
let type_name = $(element).text()
let type_id = element.attribs.href
if (type_name === this.removeKey) {
this.classes.push(this.getTypeDic(type_name, type_id))
this.filterObj[type_id] = await this.getFilter(type_id)
}
}
}
async setCategory(tid, pg, filter, extend) {
let classes = this.getExtend(extend) ?? tid
let url
if (parseInt(pg) === 1) {
url = this.siteUrl + classes
} else {
url = this.siteUrl + classes + `index${pg}.html`
}
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDoc($)
}
}
let spider = new LoveMovie18Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,181 +0,0 @@
/*
* @File : mhdq.js
* @Author : jade
* @Date : 2024/1/24 9:15
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 18+韩漫
*/
import {Spider} from "./spider.js";
import {BookDetail, BookShort} from "../lib/book.js";
class MHDQSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://www.18hanman.com';
}
getName() {
return "🔞|韩漫18|🔞"
}
getAppName() {
return "韩漫18"
}
getJSName() {
return "mhdq"
}
getType() {
return 20
}
async setClasses() {
this.classes = []
let $ = await this.getHtml(this.siteUrl + "/category/")
for (const a of $('div.classopen ul.duzhe a[href!="/"]')) {
this.classes.push({
type_id: a.attribs.href,
type_name: a.children[0].data.trim()
});
}
}
async parseVodShortListFromDocByCategory($) {
const list = eval($('div[class="row exemptComic-box"]')[0].attribs.list);
let books = [];
for (const book of list) {
let bookShort = this.parseVodShortFromJson(book)
books.push(bookShort)
}
return books
}
parseVodShortFromElement($, element) {
let bookShort = new BookShort()
const a = $(element).find('a:first')[0];
const img = $(element).find('img:first-child')[0];
bookShort.book_id = a.attribs.href
bookShort.book_name = $($(element).find("a").slice(-1)[0]).html()
bookShort.book_pic = img.attribs.src
bookShort.book_remarks = $($(element).find("span")).text()
return bookShort
}
async parseVodShortListFromDoc($) {
let vodElements = $('ul.catagory-list li')
let books = []
for (const vodElement of vodElements) {
let bookShort = await this.parseVodShortFromElement($, vodElement)
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocBySearch($) {
let vodElements = $('ul.u_list')
let books = []
for (const vodElement of vodElements) {
let bookShort = await this.parseVodShortFromElement($, vodElement)
books.push(bookShort)
}
return books
}
async parseVodDetailFromDoc($, id) {
let html = $.html()
let bookDetail = new BookDetail()
bookDetail.book_id = id
bookDetail.book_name = $('div.title:first').text().trim()
bookDetail.pic = $($('div.img:first-child')).find("img")[0].attribs.src
let contentElements = $('div.info ').find("p")
for (const contentElelent of contentElements) {
if ($(contentElelent).text().indexOf("更新至")) {
bookDetail.book_remarks = $(contentElelent).text().replaceAll("更新至:","")
}
if ($(contentElelent).text().indexOf("作者")) {
bookDetail.book_director = $(contentElelent).text().replaceAll("作者:","")
}
}
bookDetail.book_content = $("[class=\"text\"]").text()
let urls = [];
const links = $('ul.list a[href!="/"]');
for (const l of links) {
let name = l.children[0].data;
let link = l.attribs.href;
urls.push(name + '$' + link);
}
bookDetail.volumes = '全卷';
bookDetail.urls = urls.join('#');
return bookDetail
}
async setCategory(tid, pg, filter, extend) {
const $ = await this.getHtml(this.siteUrl + `${tid}/page/${pg}`)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + `${id}`)
this.vodDetail = await this.parseVodDetailFromDoc($, id)
}
async setPlay(flag, id, flags) {
const $ = await this.getHtml(this.siteUrl + id);
let content = [];
for (const l of $('div.chapterbox img')) {
const img = $(l).attr('src');
content.push(img);
}
this.playUrl = {
"content": content,
}
}
async setSearch(wd, quick) {
const $ = await this.getHtml(this.siteUrl + `/index.php/search?key=${wd}`);
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new MHDQSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,269 +0,0 @@
/*
* @File : mp4movie.js
* @Author : jade
* @Date : 2024/2/19 9:41
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class DyttSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.mp4us.com"
this.apiUrl = "https://m.mp4us.com"
this.dyttReconnectTimes = 0
}
getName() {
return "🍚┃Mp4电影┃🍚"
}
getAppName() {
return "Mp4电影"
}
getJSName() {
return "mp4movie"
}
getType() {
return 3
}
// getHeader() {
// return {"User-Agent": Utils.CHROME, "Referer": this.siteUrl + "/","Connection":"keep-alive"};
// }
async getFilter() {
let extend_list = []
let $ = await this.getHtml()
let suoyinElement = $("[class=\"nav navbar-nav\"]").find("li").slice(-1)[0]
let souyinUrl = $(suoyinElement).find("a")[0].attribs.href
let souyin$ = await this.getHtml(this.siteUrl + souyinUrl)
let sortElements = souyin$("[class=\"sort-box\"]").find("[class=\"sort-list\"]").slice(1,-1)
for (const sortElement of sortElements){
let name = $($(sortElement).find("h5")).text().replace("","")
let extend_dic = {"key": name, "name":name, "value": []}
for (const ele of $(sortElement).find("a")) {
extend_dic["value"].push({"n": $(ele).text(), "v": ele.attribs.data.split("-")[1]})
}
extend_list.push(extend_dic)
}
return extend_list
}
// async setFilterObj() {
// for (const type_dic of this.classes) {
// let type_id = type_dic["type_id"]
// if (type_id !== "最近更新") {
// this.filterObj[type_id] = await this.getFilter()
// }
// }
// }
async setClasses() {
let $ = await this.getHtml()
let suoyinElement = $("[class=\"nav navbar-nav\"]").find("li").slice(-1)[0]
let souyinUrl = $(suoyinElement).find("a")[0].attribs.href
let souyin$ = await this.getHtml(this.siteUrl + souyinUrl)
let sortElements = souyin$("[class=\"sort-box\"]").find("[class=\"sort-list\"]")
let classElements = $(sortElements[0]).find("li")
for (const classElement of classElements) {
let type_name = $($(classElement).find("a")).text()
let type_id = $(classElement).find("a")[0].attribs.data.replaceAll("id-", "")
if (type_name !== "全部") {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"index_today cclear\"]").find("a")
for (const vodElement of vodElements){
let vodShort = new VodShort();
vodShort.vod_name = vodElement.attribs.title
vodShort.vod_id = vodElement.attribs.href
vodShort.vod_pic = this.detailProxy + Utils.base64Encode(vodShort.vod_id)
vod_list.push(vodShort)
}
return vod_list
}
getSearchHeader() {
let headers = this.getHeader()
headers["Cookie"] = "Hm_lvt_d8c8eecfb13fe991855f511a6e30c3d2=1708243467,1708325624,1708326536;Hm_lpvt_d8c8eecfb13fe991855f511a6e30c3d2;1708326536"
return headers
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let html = $.html()
let detailRootElement = $("[class=\"article-header\"]")
let detailElements = $(detailRootElement).find("p")
let content = ""
for (const detailElement of detailElements){
content = content + $(detailElement).text() + "\n"
}
vodDetail.type_name = $($($(detailRootElement).find("[class=\"post-meta\"]")).find("span")[0]).text()
vodDetail.vod_pic = $(detailRootElement).find("img")[0].attribs.src
vodDetail.vod_name = Utils.getStrByRegex(/名称:(.*?)\n/,content)
vodDetail.vod_actor = Utils.getStrByRegex(/主演:(.*?)\n/,content)
vodDetail.vod_director = Utils.getStrByRegex(/导演:(.*?)\n/,content)
vodDetail.vod_area = Utils.getStrByRegex(/地区:(.*?)\n/,content)
vodDetail.vod_year = Utils.getStrByRegex(/年份:(.*?)\n/,content)
vodDetail.vod_remarks = Utils.getStrByRegex(/更新:(.*?)\n/,content)
let contentElement = $("[class=\"article-related info\"]").find("p")
vodDetail.vod_content = $(contentElement).text()
let downloadElements = $("[class=\"article-related download_url\"]")
let vod_play_from_list = []
let vod_play_list = []
for (let i = 0; i < downloadElements.length; i++) {
let playFormatElement = downloadElements[i]
let format_name = $($(playFormatElement).find("h2")).text().replaceAll(vodDetail.vod_name,"")
vod_play_from_list.push(format_name.replaceAll("下载","播放"))
let vodItems = []
for (const playUrlElement of $(downloadElements[i]).find("a")) {
let episodeName = $(playUrlElement).text().replaceAll("磁力链下载","").replaceAll(".mp4","")
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async parseVodShortListFromJson(obj) {
let vod_list = []
let $ = load(obj["ajaxtxt"])
let vodElements = $($("ul")).find("li");
for (const vodElement of vodElements){
let vodShort = new VodShort()
vodShort.vod_pic = $(vodElement).find("img")[0].attribs["data-original"]
vodShort.vod_name = Utils.getStrByRegex(/《(.*?)》/,$(vodElement).find("img")[0].attribs.alt)
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
vodShort.vod_remarks = "评分:"+ $($(vodElement).find("[class=\"rate badge\"]")).text()
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $($("[id=\"list_all\"]").find("ul")).find("li")
for (const vodElement of vodElements){
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
vodShort.vod_name = Utils.getStrByRegex(/《(.*?)》/,$($($(vodElement).find("[class=\"text_info\"]")).find("a")[0]).text())
vodShort.vod_pic = $(vodElement).find("img")[0].attribs["data-original"]
vodShort.vod_remarks = $($(vodElement).find("[class=\"update_time\"]")).text()
vod_list.push(vodShort)
}
return vod_list
}
async setHomeVod() {
let $ = await this.getHtml();
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
return this.vodDetail
}
async setCategory(tid, pg, filter, extend) {
// let url = this.apiUrl + `/list-index-id-${tid}`
// let area = extend["地区"] ?? ""
// let year = extend["年代"] ?? ""
// let tag = extend["标签"] ?? ""
// if (parseInt(pg) > 1){
// url = url + `-p-${pg}`
// }
// if (!_.isEmpty(area) && area !== "0"){
// url = url + `-area-${area}`
// }
// if (!_.isEmpty(year) && year !== "0"){
// url = url + `-year-${year}`
// }
// if (!_.isEmpty(tag) && tag !== "0"){
// url = url + `-wd-${tag}`
// }
// let resp = await this.fetch(url + ".html",null,this.getHeader())
// this.vodList = await this.parseVodShortListFromJson(JSON.parse(resp))
let url = this.siteUrl + `/list/${tid}-${pg}.html`
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/search/"
let params = {"wd":wd,"p":"1","t":"j/tNgwBS2e8O4x9TuIkYuQ=="}
let html = await this.post(url,params,this.getSearchHeader())
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
}
let spider = new DyttSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

View File

@ -1,429 +0,0 @@
/*
* @File : mxanime.js
* @Author : jade
* @Date : 2024/3/30 14:13
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : MX动漫
*/
import {Spider} from "./spider.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {_, load} from "../lib/cat.js";
import * as Utils from "../lib/utils.js";
class MxAnimeSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.mxdm6.com/"
}
getName() {
return "🍒┃MX动漫┃🍒"
}
getAppName() {
return "MX动漫"
}
getJSName() {
return "mxanime"
}
getType() {
return 3
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $($("[class=\"nav-menu-items\"]")[0]).find("[class=\"nav-menu-item \"]")
for (const navElement of navElements) {
let element = $(navElement).find("a")[0]
let type_name = element.attribs.title
let type_id = element.attribs.href
if (type_name !== "萌图") {
this.classes.push(this.getTypeDic(type_name, Utils.getStrByRegex(/type\/(.*?).html/, type_id)))
}
}
}
async getFilter($) {
let elements = $("[class=\"library-box scroll-box\"]")
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": "", "value": []}
if (i < elements.length - 1) {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(elements[i]).find("a").slice(1)) {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
extend_list.push(extend_dic)
} else {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"] = [{"n": "全部", "v": "0"}, {
"n": $($(elements[i]).find("a")[1]).text(),
"v": "hits"
}, {"n": $($(elements[i]).find("a")[2]).text(), "v": "score"}]
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let $ = await this.getHtml(this.siteUrl + `/type/${type_id}.html`)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
parseVodShortFromElement($, vodElement) {
let vodShort = new VodShort()
let element = $($(vodElement).find("[class=\"module-item-titlebox\"]")).find("a")[0]
vodShort.vod_id = element.attribs.href
vodShort.vod_name = element.attribs.title
vodShort.vod_pic = $($(vodElement).find("[class=\"module-item-pic\"]")).find("img")[0].attribs["data-src"]
vodShort.vod_remarks = $($(vodElement).find("[class=\"module-item-text\"]")).text()
return vodShort
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"module-list module-lines-list mxone-box\"]").find("[class=\"module-item\"]")
for (const vodElement of vodElements) {
let vodShort = await this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $("[class=\"module-item\"]")
for (const vodElement of vodElements) {
let vodShort = await this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"module-search-item\"]")
for (const vodElement of vodElements) {
let vodShort = new VodShort()
let element = $(vodElement).find("[class=\"video-serial\"]")[0]
vodShort.vod_id = element.attribs.href
vodShort.vod_name = element.attribs.title
vodShort.vod_pic = $($(vodElement).find("[class=\"module-item-pic\"]")).find("img")[0].attribs["data-src"]
let remarkElements = $($(vodElement).find("[class=\"video-info-item video-info-actor\"]").slice(-1)[0]).find("a")
let remark_list = []
for (const remarkElement of remarkElements){
let remark = remarkElement.children[0].data
remark_list.push(remark)
}
vodShort.vod_remarks = remark_list.join("*")
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let vodElement = $("[class=\"video-info\"]")
vodDetail.vod_pic = $("[class=\"module-item-pic\"]").find("img")[0].attribs["data-src"]
vodDetail.vod_name = $($(vodElement).find("[class=\"page-title\"]")).text()
let classElements = $(vodElement).find("[class=\"video-info-items\"]")
for (const classElement of classElements){
let text = $(classElement).text().replaceAll("\n","").replaceAll("\t","").replaceAll(" ","") + "end"
if (text.indexOf("年份") > -1){
vodDetail.vod_year = Utils.getStrByRegex(/年份:(.*?)end/,text).replaceAll("/","")
}
if(text.indexOf("备注") > -1){
let x = Utils.getStrByRegex(/备注:(.*?)end/,text)
vodDetail.vod_remarks = Utils.getStrByRegex(/备注:\/(.*?)end/,text)
}
if (text.indexOf("标签") > -1){
vodDetail.type_name = Utils.getStrByRegex(/标签:(.*?)end/,text)
}
if (text.indexOf("剧情") > -1){
vodDetail.vod_content = Utils.getStrByRegex(/剧情:(.*?)end/,text)
}
}
let playFormatElemets = $("[class=\"module-tab-item tab-item\"]")
let playUrlElements = $("[class=\"scroll-content\"]")
let vod_play_from_list = []
let vod_play_list = []
for (let i = 0; i < playFormatElemets.length; i++) {
let playFormatElement = playFormatElemets[i]
vod_play_from_list.push(playFormatElement.attribs["data-dropdown-value"])
let vodItems = []
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
getExtendValue(extent, key) {
if (extent[key] === undefined) {
return ""
} else {
if (extent[key] === "0") {
return ""
} else {
return extent[key]
}
}
}
async setCategory(tid, pg, filter, extend) {
await this.jadeLog.debug(`extend:${JSON.stringify(extend)}`)
let type = this.getExtendValue(extend, "1")
let time = this.getExtendValue(extend, "2")
let word = this.getExtendValue(extend, "3")
let sort = this.getExtendValue(extend, "4")
let urlParams = [tid.toString(), "", sort, type, "", word, "", "", pg.toString(), "", "", time]
let url = this.siteUrl + "/show/" + urlParams.join("-") + ".html"
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setSearch(wd, quick) {
let url = this.siteUrl + `/search/${wd}-------------.html`
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(this.siteUrl + id)
let playerConfig = JSON.parse(Utils.getStrByRegex(/var player_aaaa=(.*?)<\/script>/,$.html()))
const m3mu8_url = "https://danmu.yhdmjx.com/m3u8.php?url=" + playerConfig["url"]
const m3u8_res = await (await this.fetch(m3mu8_url,null,this.getHeader()));
const m3u8_result = m3u8_res.match(/"url": getVideoInfo\("(.*?)"\),/)[1];
const bt_token = m3u8_res.match(/<script>var bt_token = "(.*?)"/)[1];
let m3u8_token_key = await (await this.fetch("https://danmu.yhdmjx.com/js/play.js",null,this.getHeader()));
m3u8_token_key = m3u8_token_key.match(/var _token_key=CryptoJS\['enc'\]\['Utf8'\]\[_0x17f1\('67','qETJ'\)\]\((.*?\))/)[1];
m3u8_token_key = this.decrypt_token_key(m3u8_token_key);
this.playUrl = await this.getVideoInfo(m3u8_result, m3u8_token_key, bt_token);
}
decrypt_token_key(toekn_key){
var _0xod4 = 'jsjiami.com.v6',
_0x175e = [_0xod4, 'JMOsw6omwoDCmw==', 'wp3DkSx5Eg==', 'HB7CscOJfS3DuUjDv2bDjsOmwr3Cm8KcwoI=', 'fR/Dqg==', 'ShRGTcKa', 'w5Y8VBs=', 'esKYKQ==', 'FgIdwrPDnMKOw7k=', 'HhXCmA==', 'woNrRsKSwpnDvcKfw4g=', 'ezBn', 'w43DkcK5w4MaJiE=', 'w44Ob8KjwrjCrMKtUA==', 'HwtswqI=', 'YsKnwrRawro=', 'Sm/CpQXCjz4RH8ORSXw=', 'IsO6w64=', 'T8OeAQ==', 'VcK4Hg==', 'csOmfBJ4', 'd8OAcA5L', 'Tn4RL2s=', 'w7goGizCmw==', 'w6XDlcOGwpoY', 'TsK7wpNPwrg=', 'w7J1CzLCnsO+HA==', 'w4XDkcK0w5YXPg==', 'S8KoCcKS', 'PcKWHcK/Eg==', 'Z2oMJ3rCiw==', 'YsKMG8KMwo0=', 'QsOecgRIwp4=', 'dFzDkUUxw48Qw7nCmX3CicODCMKnw74IOg==', 'acO2KU1B', 'wrAnw6DDrg==', 'w5MsScKwwoA=', 'wohZG8KhBg==', 'b8OieSpZ', 'w4ZmEsORw6I=', 'w7jDhxvCh8KY', 'w7wQa8KFwr0=', 'IMObw4E3wqU=', 'JsOjw5Erwrg=', 'w6MwcsKOwqU=', 'b8KIwqF0wrs=', 'XhXDvT52', 'wrDCmirChSE=', 'w5t1wpvDuwE=', 'XA7CtsKeEA==', 'wonCvVthw78=', 'U8KPP8KMwq4=', 'wp7DhCxjGTU=', 'woPDoBdiEQ==', 'HjzCrE/Dvg==', 'SsOQOWHCgg==', 'w6NdwoXCkMOx', 'w6shYWQ/', 'eE/Cgg==', 'XW/Csj7CmDoA', 'w680OynCgcK5BA8=', 'w4PDoMOTwrog', 'w5R7wqbCpMOPwrMxUcOiM8OuMVLCisKKFsOXAcOWY8O6w5hM', 'WwjDoht0', 'PzXCiHHDiA==', 'QMOFaMKcfQ==', 'bz9bVsK+', 'w7Npwp/DsB9ONw==', 'EcOPBQ3Cig==', 'woHDnzk=', 'DsKQLxtd', 'R8OCJmk=', 'wp55O8On', 'bkXCmhTCqg==', 'w7vDgx3Cg8KU', 'w6nDo8KdAn8=', 'O8KwP8KEDw==', 'wqzCtCHCtCg=', 'w5nDgmYhw5c=', 'wp0OZsK+w4A=', 'wrFxe8KFwp/DvcKew4EbN8K7BMORMx3DuxtOVELChsOEIQ==', 'BMKWRDc=', 'IS5dw6nDhQ==', 'w6geeG8t', 'SsK/wohywpc=', 'LBlnw7jDkA==', 'wodiLsOg', 'Ig5Ow7/Dlw==', 'TMOOewRZwoQ=', 'LjnClV7DvA==', 'woZsO8KcPQ==', 'eWvClMKeKQ==', 'wq1KWsKswr8=', 'w4p+AGFa', 'C8O7F8K2CQcKFxxgwo5sfh3DpAFV', 'w6XDqMKoCw==', 'w6Z8wqnCpMOe', 'w6x/CHRhXhV/w7I=', 'wrvClndGw5Y=', 'VsKcwo5RwoA=', 'ZcK2BMKmLQ==', 'BCcPwofDvQ==', 'eGEsF20=', 'eMOcUglq', 'w4U9XEAMw4/Dm3rCuzpxTg/DvyDDvMONH8OTwpTCtsKbw6k=', 'VwXDkTxG', 'CzHCrl3DkQ==', 'w7PDkVovw4o=', 'dsONYDdj', 'w79pwr3Duh4=', 'w55kwoLCpMOR', 'w6gbc8KGwpw=', 'bCnCtMKCCg==', 'Php5w64=', 'w7x8wpfDtiQ=', 'w4TDk2AB', 'w7lowoHDtgQ=', 'DB/CsnjDuQ==', 'woTDl8K3wp4S', 'wr0Ewq7Dq8Oh', 'GmHCpGxN', 'w5/Dm2XDpw==', 'w5bDpsOCwqoA', 'YMKowphwwqc=', 'ahFuVsK9', 'w57DtEsbw7k=', 'w6LDo8Kq', 'UsKzE8KO', 'w6xlBFl9', 'WMOgIXbCiw==', 'DBhjw5fDhQ==', 'w6pUwoHCnsOs', 'ZF7CtsKiHg==', 'wos4w7wCwr0c', 'JlXCjlpyw5pMw6s=', 'TcO1N8K4wqE=', 'SMOzTcKYRw==', 'w4HDosOzwrUc', 'wqxdwqE2wrY=', 'A8OPGQjChw==', 'wpkxasOxBQ==', 'wpIZSA==', 'VsOnEEvChg==', 'bMOSZy93', 'c8OwZsKnRQ==', 'SsK/wpBHwoQ=', 'ccOsHVFf', 'w6ZKYMO8w6rDr8OrCHxdwqtdwrDDksOMccKZwobDpQPDgsOrAMKXF8OMPcOySsKuL8KLwq8vwr/DkjbDqsOCbRrCkcOTTFfDlsKkw7PChCM1wqTDisKawpHDt8KCQRY3w6DDgMKVw6M=', 'w7hYwq3ClsOa', 'Fic5wqLDiw==', 'KcKqHCVV', 'wqvDucKSwrs/', 'YcOfQcKPSQ==', 'wpjClmNRw7U=', 'wpHClSnCizg=', 'w4PDh8Kw', 'JsOYGwnCpw==', 'w5vDksK8w6sl', 'U8ORCHt+Rw==', 'woVxO8OSJQ==', 'b37Chw/Clw==', 'w6ViBXZlQg==', 'UwPCucKQCgU=', 'UMOeZgs=', 'MTLCtW7Dq2o=', 'wqAQwr/DqcOi', 'DiLDtsOOZsKEbsOrGm03EcKEwr/CplQ=', 'dzPDnRhP', 'wplgT8KBwow=', 'XUzCg8KF', 'K8KTCcKrCQ==', 'w6ZKJMOw', 'LxTCmn/DsA==', 'wooObcKBw6g=', 'w5djwofDoTQ=', 'VMOHeAts', 'Kw96w7bDig==', 'wogpw6crwps=', 'PDzDn8OcWQ==', 'wrfCoWxfw4E=', 'wrrDv8KDwoI+', 'w7hnwrjCssOq', 'w4LDrMOwwpMp', 'S2vCvyjCjic=', 'w6DDoT7CtcKNwoo=', 'wp1Lw5zCpj4=', 'RsOEGcKVwps=', 'woxlwo0twoM=', 'MAZYw7TDmg==', 'w7ENEC7CgA==', 'wolVw4jCryEqVMOYdg==', 'wp45w6cCwqY=', 'w6UhVHs1', 'QBZFW8KH', 'Ozhvw7vDkQ==', 'E8O4DAXCnA==', 'AcOXR8OZ', 'w4NhwqbCk8O6', 'f8OyScKpRRJTBQd9w4t3PgzCtRMQwrjDrUZ9Z8Od', 'A8OHw7Inwoc=', 'wqlQE8KHDg==', 'wqYbZMOVMg==', 'w57DuVwAw60=', 'W8OyQMKtVAk=', 'w60PBwXCng==', 'w4h7w70gw55WbHfDuR0VQ8K+asOxwoJn', 'w5rDhMK2w5gX', 'N0HCklc=', 'w58TTsK4wrg=', 'w7dXNMOhw79pwqBMw70=', 'SsKQCcKf', 'KSXCumrDug==', 'woc1w7gUwrEEw7s=', 'wplowqIvwoFGMQ==', 'acO9DcK+', 'UMKBwpJNwp1ZfA==', 'wpV+NsKCLQ==', 'w5PDrMOrwo4iwrcU', 'XHjCoyPCkw==', 'w5kOUsKkwqXCqcKm', 'QMKRAcKDDMK+AA==', 'bMKoNcKgwrc=', 'w6k0HTPClw==', 'wpUYYcOcBA==', 'w6k6BjnCnMK9', 'w5HDnncPw60=', 'jEsjiamLiI.coRVzmBz.v6gWBKxrg=='];
(function (_0x2410c8, _0x4731c1, _0x21bfda) {
var _0x12d6b4 = function (_0x56792e, _0x26ff38, _0x14a967, _0x1f013c, _0x21c988) {
_0x26ff38 = _0x26ff38 >> 0x8,
_0x21c988 = 'po';
var _0x10be12 = 'shift',
_0x47704d = 'push';
if (_0x26ff38 < _0x56792e) {
while (--_0x56792e) {
_0x1f013c = _0x2410c8[_0x10be12]();
if (_0x26ff38 === _0x56792e) {
_0x26ff38 = _0x1f013c;
_0x14a967 = _0x2410c8[_0x21c988 + 'p']();
} else if (_0x26ff38 && _0x14a967['replace'](/[ELIRVzBzgWBKxrg=]/g, '') === _0x26ff38) {
_0x2410c8[_0x47704d](_0x1f013c);
}
}
_0x2410c8[_0x47704d](_0x2410c8[_0x10be12]());
}
return 0xa44cc;
};
return _0x12d6b4(++_0x4731c1, _0x21bfda) >> _0x4731c1 ^ _0x21bfda;
}(_0x175e, 0x15c, 0x15c00));
var _0x17f1 = function (_0x3abb24, _0x9f8a97) {
_0x3abb24 = ~~'0x' ['concat'](_0x3abb24);
var _0x411694 = _0x175e[_0x3abb24];
if (_0x17f1['nIHPps'] === undefined) {
(function () {
var _0x264909 = typeof window !== 'undefined' ? window : typeof process === 'object' && typeof require === 'function' && typeof global === 'object' ? global : this;
var _0x52b78f = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
// _0x264909['atob'] || (_0x264909['atob'] = function (_0x202c2d) {
// var _0x2e97e4 = String(_0x202c2d)['replace'](/=+$/, '');
// for (var _0x488147 = 0x0,
// _0x1702c1, _0x5d977a, _0x1a87f9 = 0x0,
// _0x2378be = ''; _0x5d977a = _0x2e97e4['charAt'](_0x1a87f9++); ~_0x5d977a && (_0x1702c1 = _0x488147 % 0x4 ? _0x1702c1 * 0x40 + _0x5d977a : _0x5d977a, _0x488147++ % 0x4) ? _0x2378be += String['fromCharCode'](0xff & _0x1702c1 >> (-0x2 * _0x488147 & 0x6)) : 0x0) {
// _0x5d977a = _0x52b78f['indexOf'](_0x5d977a);
// }
// return _0x2378be;
// });
}());
var _0x5cedb3 = function (_0x19b8a7, _0x9f8a97) {
var _0x2b0e6a = [],
_0x4f25fe = 0x0,
_0x29acd8,
_0x2643f2 = '',
_0x58e8bd = '';
_0x19b8a7 = atob(_0x19b8a7);
for (var _0x1ac59f = 0x0,
_0x3346bd = _0x19b8a7['length']; _0x1ac59f < _0x3346bd; _0x1ac59f++) {
_0x58e8bd += '%' + ('00' + _0x19b8a7['charCodeAt'](_0x1ac59f)['toString'](0x10))['slice'](-0x2);
}
_0x19b8a7 = decodeURIComponent(_0x58e8bd);
for (var _0xb0c930 = 0x0; _0xb0c930 < 0x100; _0xb0c930++) {
_0x2b0e6a[_0xb0c930] = _0xb0c930;
}
for (_0xb0c930 = 0x0; _0xb0c930 < 0x100; _0xb0c930++) {
_0x4f25fe = (_0x4f25fe + _0x2b0e6a[_0xb0c930] + _0x9f8a97['charCodeAt'](_0xb0c930 % _0x9f8a97['length'])) % 0x100;
_0x29acd8 = _0x2b0e6a[_0xb0c930];
_0x2b0e6a[_0xb0c930] = _0x2b0e6a[_0x4f25fe];
_0x2b0e6a[_0x4f25fe] = _0x29acd8;
}
_0xb0c930 = 0x0;
_0x4f25fe = 0x0;
for (var _0x4f50dd = 0x0; _0x4f50dd < _0x19b8a7['length']; _0x4f50dd++) {
_0xb0c930 = (_0xb0c930 + 0x1) % 0x100;
_0x4f25fe = (_0x4f25fe + _0x2b0e6a[_0xb0c930]) % 0x100;
_0x29acd8 = _0x2b0e6a[_0xb0c930];
_0x2b0e6a[_0xb0c930] = _0x2b0e6a[_0x4f25fe];
_0x2b0e6a[_0x4f25fe] = _0x29acd8;
_0x2643f2 += String['fromCharCode'](_0x19b8a7['charCodeAt'](_0x4f50dd) ^ _0x2b0e6a[(_0x2b0e6a[_0xb0c930] + _0x2b0e6a[_0x4f25fe]) % 0x100]);
}
return _0x2643f2;
};
_0x17f1['RtnfNa'] = _0x5cedb3;
_0x17f1['afYpDj'] = {};
_0x17f1['nIHPps'] = !![];
}
var _0x5dc739 = _0x17f1['afYpDj'][_0x3abb24];
if (_0x5dc739 === undefined) {
if (_0x17f1['OqAPEJ'] === undefined) {
_0x17f1['OqAPEJ'] = !![];
}
_0x411694 = _0x17f1['RtnfNa'](_0x411694, _0x9f8a97);
_0x17f1['afYpDj'][_0x3abb24] = _0x411694;
} else {
_0x411694 = _0x5dc739;
}
return _0x411694;
};
return eval(toekn_key)
}
async getVideoInfo(data,key,iv) {
/*
Crypto v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
var Crypto=Crypto||function(u,p){var d={},l=d.lib={},s=function(){},t=l.Base={extend:function(a){s.prototype=this;var c=new s;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
r=l.WordArray=t.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=p?c:4*a.length},toString:function(a){return(a||v).stringify(this)},concat:function(a){var c=this.words,e=a.words,j=this.sigBytes;a=a.sigBytes;this.clamp();if(j%4)for(var k=0;k<a;k++)c[j+k>>>2]|=(e[k>>>2]>>>24-8*(k%4)&255)<<24-8*((j+k)%4);else if(65535<e.length)for(k=0;k<a;k+=4)c[j+k>>>2]=e[k>>>2];else c.push.apply(c,e);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
32-8*(c%4);a.length=u.ceil(c/4)},clone:function(){var a=t.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],e=0;e<a;e+=4)c.push(4294967296*u.random()|0);return new r.init(c,a)}}),w=d.enc={},v=w.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++){var k=c[j>>>2]>>>24-8*(j%4)&255;e.push((k>>>4).toString(16));e.push((k&15).toString(16))}return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j+=2)e[j>>>3]|=parseInt(a.substr(j,
2),16)<<24-4*(j%8);return new r.init(e,c/2)}},b=w.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++)e.push(String.fromCharCode(c[j>>>2]>>>24-8*(j%4)&255));return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j++)e[j>>>2]|=(a.charCodeAt(j)&255)<<24-8*(j%4);return new r.init(e,c)}},x=w.Utf8={stringify:function(a){try{return decodeURIComponent(escape(b.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return b.parse(unescape(encodeURIComponent(a)))}},
q=l.BufferedBlockAlgorithm=t.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=x.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,e=c.words,j=c.sigBytes,k=this.blockSize,b=j/(4*k),b=a?u.ceil(b):u.max((b|0)-this._minBufferSize,0);a=b*k;j=u.min(4*a,j);if(a){for(var q=0;q<a;q+=k)this._doProcessBlock(e,q);q=e.splice(0,a);c.sigBytes-=j}return new r.init(q,j)},clone:function(){var a=t.clone.call(this);
a._data=this._data.clone();return a},_minBufferSize:0});l.Hasher=q.extend({cfg:t.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){q.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,e){return(new a.init(e)).finalize(b)}},_createHmacHelper:function(a){return function(b,e){return(new n.HMAC.init(a,
e)).finalize(b)}}});var n=d.algo={};return d}(Math);
(function(){var u=Crypto,p=u.lib.WordArray;u.enc.Base64={stringify:function(d){var l=d.words,p=d.sigBytes,t=this._map;d.clamp();d=[];for(var r=0;r<p;r+=3)for(var w=(l[r>>>2]>>>24-8*(r%4)&255)<<16|(l[r+1>>>2]>>>24-8*((r+1)%4)&255)<<8|l[r+2>>>2]>>>24-8*((r+2)%4)&255,v=0;4>v&&r+0.75*v<p;v++)d.push(t.charAt(w>>>6*(3-v)&63));if(l=t.charAt(64))for(;d.length%4;)d.push(l);return d.join("")},parse:function(d){var l=d.length,s=this._map,t=s.charAt(64);t&&(t=d.indexOf(t),-1!=t&&(l=t));for(var t=[],r=0,w=0;w<
l;w++)if(w%4){var v=s.indexOf(d.charAt(w-1))<<2*(w%4),b=s.indexOf(d.charAt(w))>>>6-2*(w%4);t[r>>>2]|=(v|b)<<24-8*(r%4);r++}return p.create(t,r)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();
(function(u){function p(b,n,a,c,e,j,k){b=b+(n&a|~n&c)+e+k;return(b<<j|b>>>32-j)+n}function d(b,n,a,c,e,j,k){b=b+(n&c|a&~c)+e+k;return(b<<j|b>>>32-j)+n}function l(b,n,a,c,e,j,k){b=b+(n^a^c)+e+k;return(b<<j|b>>>32-j)+n}function s(b,n,a,c,e,j,k){b=b+(a^(n|~c))+e+k;return(b<<j|b>>>32-j)+n}for(var t=Crypto,r=t.lib,w=r.WordArray,v=r.Hasher,r=t.algo,b=[],x=0;64>x;x++)b[x]=4294967296*u.abs(u.sin(x+1))|0;r=r.MD5=v.extend({_doReset:function(){this._hash=new w.init([1732584193,4023233417,2562383102,271733878])},
_doProcessBlock:function(q,n){for(var a=0;16>a;a++){var c=n+a,e=q[c];q[c]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360}var a=this._hash.words,c=q[n+0],e=q[n+1],j=q[n+2],k=q[n+3],z=q[n+4],r=q[n+5],t=q[n+6],w=q[n+7],v=q[n+8],A=q[n+9],B=q[n+10],C=q[n+11],u=q[n+12],D=q[n+13],E=q[n+14],x=q[n+15],f=a[0],m=a[1],g=a[2],h=a[3],f=p(f,m,g,h,c,7,b[0]),h=p(h,f,m,g,e,12,b[1]),g=p(g,h,f,m,j,17,b[2]),m=p(m,g,h,f,k,22,b[3]),f=p(f,m,g,h,z,7,b[4]),h=p(h,f,m,g,r,12,b[5]),g=p(g,h,f,m,t,17,b[6]),m=p(m,g,h,f,w,22,b[7]),
f=p(f,m,g,h,v,7,b[8]),h=p(h,f,m,g,A,12,b[9]),g=p(g,h,f,m,B,17,b[10]),m=p(m,g,h,f,C,22,b[11]),f=p(f,m,g,h,u,7,b[12]),h=p(h,f,m,g,D,12,b[13]),g=p(g,h,f,m,E,17,b[14]),m=p(m,g,h,f,x,22,b[15]),f=d(f,m,g,h,e,5,b[16]),h=d(h,f,m,g,t,9,b[17]),g=d(g,h,f,m,C,14,b[18]),m=d(m,g,h,f,c,20,b[19]),f=d(f,m,g,h,r,5,b[20]),h=d(h,f,m,g,B,9,b[21]),g=d(g,h,f,m,x,14,b[22]),m=d(m,g,h,f,z,20,b[23]),f=d(f,m,g,h,A,5,b[24]),h=d(h,f,m,g,E,9,b[25]),g=d(g,h,f,m,k,14,b[26]),m=d(m,g,h,f,v,20,b[27]),f=d(f,m,g,h,D,5,b[28]),h=d(h,f,
m,g,j,9,b[29]),g=d(g,h,f,m,w,14,b[30]),m=d(m,g,h,f,u,20,b[31]),f=l(f,m,g,h,r,4,b[32]),h=l(h,f,m,g,v,11,b[33]),g=l(g,h,f,m,C,16,b[34]),m=l(m,g,h,f,E,23,b[35]),f=l(f,m,g,h,e,4,b[36]),h=l(h,f,m,g,z,11,b[37]),g=l(g,h,f,m,w,16,b[38]),m=l(m,g,h,f,B,23,b[39]),f=l(f,m,g,h,D,4,b[40]),h=l(h,f,m,g,c,11,b[41]),g=l(g,h,f,m,k,16,b[42]),m=l(m,g,h,f,t,23,b[43]),f=l(f,m,g,h,A,4,b[44]),h=l(h,f,m,g,u,11,b[45]),g=l(g,h,f,m,x,16,b[46]),m=l(m,g,h,f,j,23,b[47]),f=s(f,m,g,h,c,6,b[48]),h=s(h,f,m,g,w,10,b[49]),g=s(g,h,f,m,
E,15,b[50]),m=s(m,g,h,f,r,21,b[51]),f=s(f,m,g,h,u,6,b[52]),h=s(h,f,m,g,k,10,b[53]),g=s(g,h,f,m,B,15,b[54]),m=s(m,g,h,f,e,21,b[55]),f=s(f,m,g,h,v,6,b[56]),h=s(h,f,m,g,x,10,b[57]),g=s(g,h,f,m,t,15,b[58]),m=s(m,g,h,f,D,21,b[59]),f=s(f,m,g,h,z,6,b[60]),h=s(h,f,m,g,C,10,b[61]),g=s(g,h,f,m,j,15,b[62]),m=s(m,g,h,f,A,21,b[63]);a[0]=a[0]+f|0;a[1]=a[1]+m|0;a[2]=a[2]+g|0;a[3]=a[3]+h|0},_doFinalize:function(){var b=this._data,n=b.words,a=8*this._nDataBytes,c=8*b.sigBytes;n[c>>>5]|=128<<24-c%32;var e=u.floor(a/
4294967296);n[(c+64>>>9<<4)+15]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360;n[(c+64>>>9<<4)+14]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;b.sigBytes=4*(n.length+1);this._process();b=this._hash;n=b.words;for(a=0;4>a;a++)c=n[a],n[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360;return b},clone:function(){var b=v.clone.call(this);b._hash=this._hash.clone();return b}});t.MD5=v._createHelper(r);t.HmacMD5=v._createHmacHelper(r)})(Math);
(function(){var u=Crypto,p=u.lib,d=p.Base,l=p.WordArray,p=u.algo,s=p.EvpKDF=d.extend({cfg:d.extend({keySize:4,hasher:p.MD5,iterations:1}),init:function(d){this.cfg=this.cfg.extend(d)},compute:function(d,r){for(var p=this.cfg,s=p.hasher.create(),b=l.create(),u=b.words,q=p.keySize,p=p.iterations;u.length<q;){n&&s.update(n);var n=s.update(d).finalize(r);s.reset();for(var a=1;a<p;a++)n=s.finalize(n),s.reset();b.concat(n)}b.sigBytes=4*q;return b}});u.EvpKDF=function(d,l,p){return s.create(p).compute(d,
l)}})();
Crypto.lib.Cipher||function(u){var p=Crypto,d=p.lib,l=d.Base,s=d.WordArray,t=d.BufferedBlockAlgorithm,r=p.enc.Base64,w=p.algo.EvpKDF,v=d.Cipher=t.extend({cfg:l.extend(),createEncryptor:function(e,a){return this.create(this._ENC_XFORM_MODE,e,a)},createDecryptor:function(e,a){return this.create(this._DEC_XFORM_MODE,e,a)},init:function(e,a,b){this.cfg=this.cfg.extend(b);this._xformMode=e;this._key=a;this.reset()},reset:function(){t.reset.call(this);this._doReset()},process:function(e){this._append(e);return this._process()},
finalize:function(e){e&&this._append(e);return this._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(e){return{encrypt:function(b,k,d){return("string"==typeof k?c:a).encrypt(e,b,k,d)},decrypt:function(b,k,d){return("string"==typeof k?c:a).decrypt(e,b,k,d)}}}});d.StreamCipher=v.extend({_doFinalize:function(){return this._process(!0)},blockSize:1});var b=p.mode={},x=function(e,a,b){var c=this._iv;c?this._iv=u:c=this._prevBlock;for(var d=0;d<b;d++)e[a+d]^=
c[d]},q=(d.BlockCipherMode=l.extend({createEncryptor:function(e,a){return this.Encryptor.create(e,a)},createDecryptor:function(e,a){return this.Decryptor.create(e,a)},init:function(e,a){this._cipher=e;this._iv=a}})).extend();q.Encryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize;x.call(this,e,a,c);b.encryptBlock(e,a);this._prevBlock=e.slice(a,a+c)}});q.Decryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize,d=e.slice(a,a+c);b.decryptBlock(e,a);x.call(this,
e,a,c);this._prevBlock=d}});b=b.CBC=q;q=(p.pad={}).Pkcs7={pad:function(a,b){for(var c=4*b,c=c-a.sigBytes%c,d=c<<24|c<<16|c<<8|c,l=[],n=0;n<c;n+=4)l.push(d);c=s.create(l,c);a.concat(c)},unpad:function(a){a.sigBytes-=a.words[a.sigBytes-1>>>2]&255}};d.BlockCipher=v.extend({cfg:v.cfg.extend({mode:b,padding:q}),reset:function(){v.reset.call(this);var a=this.cfg,b=a.iv,a=a.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=a.createEncryptor;else c=a.createDecryptor,this._minBufferSize=1;this._mode=c.call(a,
this,b&&b.words)},_doProcessBlock:function(a,b){this._mode.processBlock(a,b)},_doFinalize:function(){var a=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){a.pad(this._data,this.blockSize);var b=this._process(!0)}else b=this._process(!0),a.unpad(b);return b},blockSize:4});var n=d.CipherParams=l.extend({init:function(a){this.mixIn(a)},toString:function(a){return(a||this.formatter).stringify(this)}}),b=(p.format={}).OpenSSL={stringify:function(a){var b=a.ciphertext;a=a.salt;return(a?s.create([1398893684,
1701076831]).concat(a).concat(b):b).toString(r)},parse:function(a){a=r.parse(a);var b=a.words;if(1398893684==b[0]&&1701076831==b[1]){var c=s.create(b.slice(2,4));b.splice(0,4);a.sigBytes-=16}return n.create({ciphertext:a,salt:c})}},a=d.SerializableCipher=l.extend({cfg:l.extend({format:b}),encrypt:function(a,b,c,d){d=this.cfg.extend(d);var l=a.createEncryptor(c,d);b=l.finalize(b);l=l.cfg;return n.create({ciphertext:b,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:d.format})},
decrypt:function(a,b,c,d){d=this.cfg.extend(d);b=this._parse(b,d.format);return a.createDecryptor(c,d).finalize(b.ciphertext)},_parse:function(a,b){return"string"==typeof a?b.parse(a,this):a}}),p=(p.kdf={}).OpenSSL={execute:function(a,b,c,d){d||(d=s.random(8));a=w.create({keySize:b+c}).compute(a,d);c=s.create(a.words.slice(b),4*c);a.sigBytes=4*b;return n.create({key:a,iv:c,salt:d})}},c=d.PasswordBasedCipher=a.extend({cfg:a.cfg.extend({kdf:p}),encrypt:function(b,c,d,l){l=this.cfg.extend(l);d=l.kdf.execute(d,
b.keySize,b.ivSize);l.iv=d.iv;b=a.encrypt.call(this,b,c,d.key,l);b.mixIn(d);return b},decrypt:function(b,c,d,l){l=this.cfg.extend(l);c=this._parse(c,l.format);d=l.kdf.execute(d,b.keySize,b.ivSize,c.salt);l.iv=d.iv;return a.decrypt.call(this,b,c,d.key,l)}})}();
(function(){for(var u=Crypto,p=u.lib.BlockCipher,d=u.algo,l=[],s=[],t=[],r=[],w=[],v=[],b=[],x=[],q=[],n=[],a=[],c=0;256>c;c++)a[c]=128>c?c<<1:c<<1^283;for(var e=0,j=0,c=0;256>c;c++){var k=j^j<<1^j<<2^j<<3^j<<4,k=k>>>8^k&255^99;l[e]=k;s[k]=e;var z=a[e],F=a[z],G=a[F],y=257*a[k]^16843008*k;t[e]=y<<24|y>>>8;r[e]=y<<16|y>>>16;w[e]=y<<8|y>>>24;v[e]=y;y=16843009*G^65537*F^257*z^16843008*e;b[k]=y<<24|y>>>8;x[k]=y<<16|y>>>16;q[k]=y<<8|y>>>24;n[k]=y;e?(e=z^a[a[a[G^z]]],j^=a[a[j]]):e=j=1}var H=[0,1,2,4,8,
16,32,64,128,27,54],d=d.AES=p.extend({_doReset:function(){for(var a=this._key,c=a.words,d=a.sigBytes/4,a=4*((this._nRounds=d+6)+1),e=this._keySchedule=[],j=0;j<a;j++)if(j<d)e[j]=c[j];else{var k=e[j-1];j%d?6<d&&4==j%d&&(k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255]):(k=k<<8|k>>>24,k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255],k^=H[j/d|0]<<24);e[j]=e[j-d]^k}c=this._invKeySchedule=[];for(d=0;d<a;d++)j=a-d,k=d%4?e[j]:e[j-4],c[d]=4>d||4>=j?k:b[l[k>>>24]]^x[l[k>>>16&255]]^q[l[k>>>
8&255]]^n[l[k&255]]},encryptBlock:function(a,b){this._doCryptBlock(a,b,this._keySchedule,t,r,w,v,l)},decryptBlock:function(a,c){var d=a[c+1];a[c+1]=a[c+3];a[c+3]=d;this._doCryptBlock(a,c,this._invKeySchedule,b,x,q,n,s);d=a[c+1];a[c+1]=a[c+3];a[c+3]=d},_doCryptBlock:function(a,b,c,d,e,j,l,f){for(var m=this._nRounds,g=a[b]^c[0],h=a[b+1]^c[1],k=a[b+2]^c[2],n=a[b+3]^c[3],p=4,r=1;r<m;r++)var q=d[g>>>24]^e[h>>>16&255]^j[k>>>8&255]^l[n&255]^c[p++],s=d[h>>>24]^e[k>>>16&255]^j[n>>>8&255]^l[g&255]^c[p++],t=
d[k>>>24]^e[n>>>16&255]^j[g>>>8&255]^l[h&255]^c[p++],n=d[n>>>24]^e[g>>>16&255]^j[h>>>8&255]^l[k&255]^c[p++],g=q,h=s,k=t;q=(f[g>>>24]<<24|f[h>>>16&255]<<16|f[k>>>8&255]<<8|f[n&255])^c[p++];s=(f[h>>>24]<<24|f[k>>>16&255]<<16|f[n>>>8&255]<<8|f[g&255])^c[p++];t=(f[k>>>24]<<24|f[n>>>16&255]<<16|f[g>>>8&255]<<8|f[h&255])^c[p++];n=(f[n>>>24]<<24|f[g>>>16&255]<<16|f[h>>>8&255]<<8|f[k&255])^c[p++];a[b]=q;a[b+1]=s;a[b+2]=t;a[b+3]=n},keySize:8});u.AES=p._createHelper(d)})();
iv = Crypto.enc.Utf8.parse(iv);
key = Crypto.enc.Utf8.parse(key);
let result = Crypto.AES.decrypt(data, key,
{
iv : iv,
mode : Crypto.mode.CBC,
})
return Crypto.enc.Utf8.stringify(result).toString();
}
}
let spider = new MxAnimeSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

View File

@ -1,389 +0,0 @@
/*
* @File : nangua.js
* @Author : jade
* @Date : 2024/3/18 10:54
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 南瓜影视
*/
import {Crypto, jinja2, _} from "../lib/cat.js";
import {Spider} from "./spider.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
function stripHtmlTag(src) {
return src
.replace(/<\/?[^>]+(>|$)/g, '')
.replace(/&.{1,5};/g, '')
.replace(/\s{2,}/g, ' ');
}
function formatPlayUrl(src, name) {
return name
.trim()
.replaceAll(src, '')
.replace(/<|>|《|》/g, '')
.replace(/\$|#/g, ' ')
.trim();
}
class NanGuaSpider extends Spider {
constructor() {
super();
this.siteUrl = 'http://ys.changmengyun.com';
}
getName() {
return "🎃┃南瓜影视┃🎃"
}
getAppName() {
return "南瓜影视"
}
getJSName() {
return "nangua"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
}
getHeader() {
let t = new Date().getTime().toString();
return {
'version_name': '1.0.6',
'version_code': '6',
'package_name': 'com.app.nanguatv',
'sign': Crypto.MD5('c431ea542cee9679#uBFszdEM0oL0JRn@' + t).toString().toLowerCase(),
'imei': 'c431ea542cee9679',
'timeMillis': t,
'User-Agent': 'okhttp/4.6.0'
}
}
async setClasses() {
let data = JSON.parse(await this.fetch(this.siteUrl + '/api.php/provide/home_nav', null, this.getHeader()));
for (const key in data) {
if (data[key].name !== '精选') this.classes.push({
type_id: data[key].id, type_name: data[key].name,
});
}
}
async setFilterObj() {
this.filterObj = {
"2": [{
"key": "class",
"name": "类型",
"value": [{"n": "全部", "v": "类型"}, {"n": "国产剧", "v": "国产剧"}, {"n": "港台剧", "v": "港台剧"}]
}, {
"key": "area", "name": "地区", "value": [{"n": "全部", "v": "地区"}, {"n": "内地", "v": "内地"}, {
"n": "香港地区", "v": "香港地区"
}, {"n": "台湾地区", "v": "台湾地区"}]
}, {
"key": "year",
"name": "年份",
"value": [{"n": "全部", "v": "年份"}, {"n": "2024", "v": "2024"}, {
"n": "2023",
"v": "2023"
}, {"n": "2022", "v": "2022"}, {
"n": "2021", "v": "2021"
}, {"n": "2020", "v": "2020"}, {"n": "2019", "v": "2019"}, {"n": "2018", "v": "2018"}, {
"n": "2017", "v": "2017"
}, {"n": "2016", "v": "2016"}, {"n": "2015", "v": "2015"}, {"n": "10年代", "v": "10年代"}, {
"n": "00年代", "v": "00年代"
}, {"n": "90年代", "v": "90年代"}, {"n": "80年代", "v": "80年代"}]
}, {
"key": "by", "name": "排序", "value": [{"n": "热播榜", "v": "热播榜"}, {"n": "好评榜", "v": "好评榜"}, {
"n": "新上线", "v": "新上线"
}]
}], "1": [{
"key": "class", "name": "类型", "value": [{"n": "全部", "v": "类型"}, {"n": "动作片", "v": "动作片"}, {
"n": "喜剧片", "v": "喜剧片"
}, {"n": "爱情片", "v": "爱情片"}, {"n": "科幻片", "v": "科幻片"}, {
"n": "恐怖片", "v": "恐怖片"
}, {"n": "剧情片", "v": "剧情片"}, {"n": "战争片", "v": "战争片"}, {"n": "惊悚片", "v": "惊悚片"}]
}, {
"key": "area", "name": "地区", "value": [{"n": "全部", "v": "地区"}, {"n": "华语", "v": "华语"}, {
"n": "香港地区", "v": "香港地区"
}, {"n": "美国", "v": "美国"}, {"n": "欧洲", "v": "欧洲"}, {"n": "韩国", "v": "韩国"}, {
"n": "日本", "v": "日本"
}, {"n": "台湾地区", "v": "台湾地区"}, {"n": "泰国", "v": "泰国"}, {
"n": "台湾地区", "v": "台湾地区"
}, {"n": "印度", "v": "印度"}, {"n": "其它", "v": "其它"}]
}, {
"key": "year",
"name": "年份",
"value": [{"n": "全部", "v": "年份"}, {"n": "2024", "v": "2024"}, {
"n": "2023",
"v": "2023"
}, {"n": "2022", "v": "2022"}, {
"n": "2021", "v": "2021"
}, {"n": "2020", "v": "2020"}, {"n": "2019", "v": "2019"}, {"n": "2018", "v": "2018"}, {
"n": "2017", "v": "2017"
}, {"n": "2016", "v": "2016"}, {"n": "2015", "v": "2015"}, {"n": "10年代", "v": "10年代"}, {
"n": "00年代", "v": "00年代"
}, {"n": "90年代", "v": "90年代"}, {"n": "80年代", "v": "80年代"}]
}, {
"key": "by", "name": "排序", "value": [{"n": "热播榜", "v": "热播榜"}, {"n": "好评榜", "v": "好评榜"}, {
"n": "新上线", "v": "新上线"
}]
}], "4": [{
"key": "class", "name": "类型", "value": [{"n": "全部", "v": "类型"}, {"n": "国产漫", "v": "国产漫"}, {
"n": "欧美漫", "v": "欧美漫"
}, {"n": "日韩漫", "v": "日韩漫"}, {"n": "港台漫", "v": "港台漫"}]
}, {
"key": "area",
"name": "地区",
"value": [{"n": "全部", "v": "地区"}, {"n": "中国大陆", "v": "中国大陆"}, {
"n": "日本", "v": "日本"
}, {"n": "韩国", "v": "韩国"}, {"n": "欧美", "v": "欧美"}, {"n": "其它", "v": "其它"}]
}, {
"key": "year",
"name": "年份",
"value": [{"n": "全部", "v": "年份"}, {"n": "2024", "v": "2024"}, {
"n": "2023",
"v": "2023"
}, {"n": "2022", "v": "2022"}, {
"n": "2021", "v": "2021"
}, {"n": "2020", "v": "2020"}, {"n": "2019", "v": "2019"}, {"n": "2018", "v": "2018"}, {
"n": "2017", "v": "2017"
}, {"n": "2016", "v": "2016"}, {"n": "2015", "v": "2015"}, {"n": "10年代", "v": "10年代"}, {
"n": "00年代", "v": "00年代"
}, {"n": "90年代", "v": "90年代"}, {"n": "80年代", "v": "80年代"}]
}, {
"key": "by", "name": "排序", "value": [{"n": "热播榜", "v": "热播榜"}, {"n": "新上线", "v": "新上线"}]
}, {
"key": "total",
"name": "状态",
"value": [{"n": "全部", "v": "状态"}, {"n": "连载", "v": "连载"}, {"n": "完结", "v": "完结"}]
}], "3": [{
"key": "class",
"name": "类型",
"value": [{"n": "全部", "v": "类型"}, {"n": "大陆", "v": "大陆"}, {"n": "港台", "v": "港台"}, {
"n": "日韩", "v": "日韩"
}, {"n": "欧美", "v": "欧美"}]
}, {
"key": "area",
"name": "地区",
"value": [{"n": "全部", "v": "地区"}, {"n": "内地", "v": "内地"}, {"n": "港台", "v": "港台"}, {
"n": "日韩", "v": "日韩"
}, {"n": "欧美", "v": "欧美"}, {"n": "其它", "v": "其它"}]
}, {
"key": "year",
"name": "年份",
"value": [{"n": "全部", "v": "年份"}, {"n": "2024", "v": "2024"}, {
"n": "2023",
"v": "2023"
}, {"n": "2022", "v": "2022"}, {
"n": "2021", "v": "2021"
}, {"n": "2020", "v": "2020"}, {"n": "2019", "v": "2019"}, {"n": "2018", "v": "2018"}, {
"n": "2017", "v": "2017"
}, {"n": "2016", "v": "2016"}, {"n": "2015", "v": "2015"}, {"n": "10年代", "v": "10年代"}, {
"n": "00年代", "v": "00年代"
}, {"n": "90年代", "v": "90年代"}, {"n": "80年代", "v": "80年代"}]
}, {
"key": "by", "name": "排序", "value": [{"n": "热播榜", "v": "热播榜"}, {"n": "新上线", "v": "新上线"}]
}], "46": [{
"key": "class", "name": "类型", "value": [{"n": "全部", "v": "类型"}, {"n": "日韩剧", "v": "日韩剧"}, {
"n": "欧美剧", "v": "欧美剧"
}, {"n": "海外剧", "v": "海外剧"}]
}, {
"key": "area",
"name": "地区",
"value": [{"n": "全部", "v": "地区"}, {"n": "韩国", "v": "韩国"}, {"n": "美剧", "v": "美剧"}, {
"n": "日本", "v": "日本"
}, {"n": "泰国", "v": "泰国"}, {"n": "英国", "v": "英国"}, {"n": "新加坡", "v": "新加坡"}, {
"n": "其他", "v": "其他"
}]
}, {
"key": "year",
"name": "年份",
"value": [{"n": "全部", "v": "年份"}, {"n": "2024", "v": "2024"}, {
"n": "2023",
"v": "2023"
}, {"n": "2022", "v": "2022"}, {
"n": "2021", "v": "2021"
}, {"n": "2020", "v": "2020"}, {"n": "2019", "v": "2019"}, {"n": "2018", "v": "2018"}, {
"n": "2017", "v": "2017"
}, {"n": "2016", "v": "2016"}, {"n": "2015", "v": "2015"}, {"n": "10年代", "v": "10年代"}, {
"n": "00年代", "v": "00年代"
}, {"n": "90年代", "v": "90年代"}, {"n": "80年代", "v": "80年代"}]
}, {
"key": "by", "name": "排序", "value": [{"n": "热播榜", "v": "热播榜"}, {"n": "好评榜", "v": "好评榜"}, {
"n": "新上线", "v": "新上线"
}]
}]
};
}
async parseVodShortListFromJSONByHome(obj) {
let vod_list = []
for (const data of obj["video"]) {
let video_vod_list = await this.parseVodShortListFromJson(data["data"])
vod_list.push(...video_vod_list)
}
return vod_list
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const data of obj) {
let vodShort = new VodShort()
vodShort.vod_id = data["id"]
vodShort.vod_name = data["name"]
vodShort.vod_pic = data["img"]
vodShort.vod_remarks = data["remarks"]
if (_.isEmpty(vodShort.vod_remarks)) {
vodShort.vod_remarks = data["msg"]
}
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromJsonBySearch(obj) {
let videos = [];
for (const data of obj){
let vodShort = new VodShort()
vodShort.vod_id = data["id"]
vodShort.vod_name = data["video_name"]
vodShort.vod_remarks = data["qingxidu"]
vodShort.vod_pic = Utils.formatUrl(data["img"])
videos.push(vodShort)
}
return videos
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail()
vodDetail.vod_id = obj["id"]
vodDetail.vod_name = obj["name"]
vodDetail.vod_pic = obj["img"]
vodDetail.type_name = obj["type"]
vodDetail.vod_year = obj["year"]
vodDetail.vod_content = stripHtmlTag(obj["info"])
vodDetail.vod_remarks = '更新至: ' + obj["msg"] + ' / 评分: ' + obj["score"]
let episodes = obj["player_info"];
let playlist = {};
episodes.forEach(function (it) {
let playurls = it["video_info"];
playurls.forEach(function (playurl) {
let source = it.show;
let t = formatPlayUrl(vodDetail.vod_name, playurl.name);
if (t.length === 0) t = playurl.name.trim();
if (!playlist.hasOwnProperty(source)) {
playlist[source] = [];
}
playlist[source].push(t + '$' + playurl.url);
});
});
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
let urls = _.values(playlist);
let vod_play_url = [];
urls.forEach(function (it) {
vod_play_url.push(it.join('#'));
});
vodDetail.vod_play_url = vod_play_url.join('$$$');
return vodDetail
}
async setHomeVod() {
let data = JSON.parse(await this.fetch(this.siteUrl + '/api.php/provide/home_data?app=ylys&devices=android&imei=c431ea542cee9679&deviceModel=Subsystem%20for%20Android(TM)&deviceVersion=33&appVersionName=1.0.9&deviceScreen=427*250&appVersionCode=9&deviceBrand=Windows', null, this.getHeader()));
this.homeVodList = await this.parseVodShortListFromJSONByHome(data)
}
async setCategory(tid, pg, filter, extend) {
if (pg <= 0 || typeof (pg) == 'undefined') pg = 1;
let reqUrl = this.siteUrl + '/api.php/provide/vod_list?app=ylys&id=' + tid + '&page=' + pg + '&imei=c431ea542cee9679&';
reqUrl += jinja2('area={{ext.area}}&year={{ext.year}}&type={{ext.class}}&total={{ext.total}}&order={{ext.by}}', {ext: extend});
let data = JSON.parse(await this.fetch(reqUrl, null, this.getHeader())).list;
this.vodList = await this.parseVodShortListFromJson(data)
let pgChk = JSON.parse(await this.fetch(this.siteUrl + '/api.php/provide/vod_list?app=ylys&id=' + tid + '&page=' + (parseInt(pg) + 1) + '&imei=c431ea542cee9679&', null, this.getHeader())).msg;
this.count = (pgChk === 'ok') ? parseInt(pg) + 1 : parseInt(pg);
this.limit = 20
this.total = this.limit * this.count
}
async setDetail(id) {
let data = JSON.parse(await this.fetch(this.siteUrl + '/api.php/provide/vod_detail?app=ylys&imei=c431ea542cee9679&id=' + id, null, this.getHeader())).data;
this.vodDetail = await this.parseVodDetailfromJson(data)
}
async setSearch(wd, quick, pg) {
let page = parseInt(pg)
const limit = 20
let data = JSON.parse(await this.fetch(this.siteUrl + '/api.php/provide/search_result_more?app=ylys&video_name=' + wd + `&pageSize=${limit}&tid=0&imei=c431ea542cee9679&page=${pg}`, null, this.getHeader())).data;
this.vodList = await this.parseVodShortListFromJsonBySearch(data)
let pageCount = page;
if (this.vodList.length === limit) {
pageCount = page + 1;
}
this.result.setPage(page, pageCount, limit, pageCount)
}
async setPlay(flag, id, flags) {
try {
if (id.indexOf('m3u8') !== -1) {
this.playUrl = id.split('url=')[1]
} else if (id.indexOf(',') !== -1) {
let mjurl = id.split(',')[1]
let jData = JSON.parse(await this.fetch(mjurl, null, this.getHeader()));
this.playUrl = jData["data"]["url"]
} else {
let jData = JSON.parse(await this.fetch(id, null, this.getHeader()));
this.playUrl = jData["data"]["url"]
}
} catch (e) {
await this.jadeLog.error("播放失败")
}
}
}
let spider = new NanGuaSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,261 +0,0 @@
/*
* @File : newvision.js
* @Author : jade
* @Date : 2024/2/20 14:14
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 新视觉影院
*/
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {Crypto} from "../lib/cat.js";
class NewVisionSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.6080yy3.com"
}
getAppName() {
return "新视觉影院"
}
getName() {
return "🐼┃新视觉影院┃🐼"
}
getJSName() {
return "newvision"
}
getType() {
return 3
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $($("[class=\"nav-menu-items\"]")[0]).find("a")
for (const navElement of navElements) {
let type_id = Utils.getStrByRegex(/\/vodtype\/(.*?).html/, navElement.attribs.href)
let type_name = navElement.attribs.title
if (Utils.isNumeric(type_id)) {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($) {
let elements = $("[class='scroll-content']").slice(1)
let extend_list = []
let type_key_list = [3, 1, 11, 2]
for (let i = 0; i < elements.length; i++) {
let name = $($(elements[i]).find("a")[0]).text()
let extend_dic = {"key": name, "name": name, "value": []}
extend_dic["name"] = name
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(elements[i]).find("a").slice(1)) {
let type_id_list = Utils.getStrByRegex(/\/vodshow\/(.*?).html/, ele.attribs.href).split("-")
extend_dic["value"].push({
"n": $(ele).text(), "v": decodeURIComponent(type_id_list[type_key_list[i]])
})
}
extend_list.push(extend_dic)
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let url = this.siteUrl + `/vodshow/${type_id}-----------.html`
let $ = await this.getHtml(url)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async parseVodShortListFromDoc($) {
let items = $('.module-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
let oneA = $(item).find('.module-item-cover .module-item-pic a').first();
vodShort.vod_id = oneA.attr('href');
vodShort.vod_name = oneA.attr('title');
vodShort.vod_pic = $(item).find('.module-item-cover .module-item-pic img').first().attr('data-src');
if (vodShort.vod_pic.indexOf("img.php?url=") > 0) {
vodShort.vod_pic = vodShort.vod_pic.split("img.php?url=")[1]
}
vodShort.vod_remarks = $(item).find('.module-item-text').first().text();
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const result of obj["Data"]["result"]){
let vodShort = new VodShort()
vodShort.vod_id = result["vod_url"].replaceAll(this.siteUrl,"")
vodShort.vod_pic = result["vod_pic"]
vodShort.vod_name = result["vod_name"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let html = $.html()
let vodDetail = new VodDetail()
let vodDetailElement = $("[class=\"box view-heading\"]")
vodDetail.vod_name = $($(vodDetailElement).find("[class=\"page-title\"]")).text()
let typeElements = $($(vodDetailElement).find("[class=\"tag-link\"]").find("a"))
vodDetail.vod_area = $($(vodDetailElement).find("[class=\"tag-link\"]").slice(-1)[0]).text()
let type_list = []
for (const typeElement of typeElements) {
type_list.push($(typeElement).text())
}
vodDetail.type_name = type_list.join("/")
let itemElements = $(vodDetailElement).find("[class=\"video-info-items\"]")
vodDetail.vod_director = $($(itemElements[0]).find("a")).text()
let actor_list = []
for (const actorElement of $(itemElements[1]).find("a")) {
actor_list.push($(actorElement).text())
}
vodDetail.vod_pic = $($(vodDetailElement).find("[class=\"module-item-pic\"]")).find("img")[0].attribs["data-src"]
vodDetail.vod_actor = actor_list.join("/")
vodDetail.vod_year = $($(itemElements[2]).find("[class=\"video-info-item\"]")).text()
vodDetail.vod_remarks = $($(itemElements[3]).find("[class=\"video-info-item\"]")).text()
vodDetail.vod_content = $($(itemElements[5]).find("[class=\"video-info-item video-info-content vod_content\"]")).text().replaceAll("\n", "\t").replaceAll("\t收起", "")
let playerformatElements = $("[class=\"module-tab-item tab-item\"]")
let playUrlElements = $("[class=\"scroll-content\"]")
let vod_play_from_list = []
let vod_play_list = []
for (let i = 0; i < playerformatElements.length; i++) {
let playFormatElement = playerformatElements[i]
let format_name = playFormatElement.attribs["data-dropdown-value"]
if (format_name.indexOf("夸克") === -1) {
vod_play_from_list.push(format_name)
let vodItems = []
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let urlParams = [tid.toString(), "", "", "", "", "", "", "", pg.toString(), "", "", ""]
let type_key_list = [3, 11, 1, 2]
if (extend["全部剧情"] !== undefined && extend["全部剧情"] !== "0") {
urlParams[type_key_list[0]] = extend["全部剧情"]
}
if (extend["全部时间"] !== undefined && extend["全部时间"] !== "0") {
urlParams[type_key_list[1]] = extend["全部时间"]
}
if (extend["全部地区"] !== undefined && extend["全部地区"] !== "0") {
urlParams[type_key_list[2]] = extend["全部地区"]
}
if (extend["时间排序"] !== undefined && extend["时间排序"] !== "0") {
urlParams[type_key_list[3]] = extend["时间排序"]
}
let reqUrl = this.siteUrl + '/index.php/vodshow/' + urlParams.join("-") + '.html';
let $ = await this.getHtml(reqUrl)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
uic(url,uid){
let ut = Crypto.enc.Utf8.parse('2890'+uid+'tB959C')
let mm = Crypto.enc.Utf8.parse("2F131BE91247866E")
let decrypted = Crypto.AES.decrypt(url, ut, {iv: mm, mode: Crypto.mode.CBC, padding: Crypto.pad.Pkcs7});
return Crypto.enc.Utf8.stringify(decrypted);
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(this.siteUrl + id)
let playUrl = $("[id=\"bfurl\"]")[0].attribs.href
if (playUrl.indexOf("http") > -1){
this.playUrl = playUrl
}else{
//需要解析URL,支持弹幕
let newUrl = "https://jiexi.xn--1lq90i13mxk5bolhm8k.xn--fiqs8s/player/ec.php?code=ak&if=1&url=" + playUrl
let play$ = await this.getHtml(newUrl)
let playHtml = play$.html()
let playConfig = JSON.parse(Utils.getStrByRegex(/let ConFig = (.*?),box = /,playHtml))
this.playUrl = this.uic(playConfig["url"],playConfig["config"]["uid"])
}
}
async setSearch(wd, quick) {
let url = `http://123.207.150.253/zxapi/public/?service=App.F.Fetch&req_p=${wd}&type=6080`
let content = await this.fetch(url,null,this.getHeader())
this.vodList = await this.parseVodShortListFromJson(JSON.parse(content))
}
}
let spider = new NewVisionSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,243 +0,0 @@
/*
* @File : nivod.js
* @Author : jade
* @Date : 2023/12/19 14:23
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {getHeader, createSign, desDecrypt, ChannelResponse, getVod} from "../lib/nivid_object.js"
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
class NivodSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.nivodz.com"
}
getName() {
return "👑‍┃泥视频┃墙👑"
}
getAppName() {
return "泥视频"
}
getJSName() {
return "nivod"
}
getType() {
return 3
}
async setClasses() {
this.Remove18ChannelCode = parseInt(this.cfgObj["code"])
let url = this.siteUrl + "/show/channel/list/WEB/3.2" + await createSign()
let content = desDecrypt(await this.post(url, null, getHeader()))
if (content !== null) {
let channelResponse = new ChannelResponse()
channelResponse.fromJsonString(content, this.Remove18ChannelCode)
let filterUrl = this.siteUrl + "/show/filter/condition/WEB/3.2" + await createSign()
let filterContent = desDecrypt(await this.post(filterUrl, null, getHeader()))
if (filterContent !== null) {
channelResponse.setChannelFilters(filterContent)
this.classes = channelResponse.getClassList()
this.filterObj = channelResponse.getFilters()
}
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const cate_dic of obj) {
for (const row of cate_dic.rows) {
for (const cells of row.cells) {
let vodShort = new VodShort()
vodShort.vod_id = cells.show["showIdCode"]
vodShort.vod_pic = cells.img
vodShort.vod_name = cells.title
vodShort.vod_remarks = this.getVodRemarks(cells.show["hot"], cells.show["playResolutions"])
vod_list.push(vodShort)
}
}
}
return vod_list
}
async parseVodDetailfromJson(vod_dic) {
let vodDetail = new VodDetail()
vodDetail.vod_id = vod_dic["showIdCode"]
vodDetail.vod_name = vod_dic["showTitle"]
vodDetail.vod_remarks = this.getVodRemarks(vod_dic["hot"], vod_dic["playResolutions"])
vodDetail.vod_pic = vod_dic["showImg"]
vodDetail.vod_director = vod_dic["director"]
vodDetail.vod_actor = vod_dic["actors"]
vodDetail.vod_year = vod_dic["postYear"]
vodDetail.vod_content = vod_dic["showDesc"]
vodDetail.type_name = vod_dic["showTypeName"]
vodDetail.vod_area = vod_dic["regionName"]
return vodDetail
}
getVodRemarks(hot, playResolutions) {
let vod_remarks
if (this.catOpenStatus) {
vod_remarks = `清晰度:${playResolutions[0]}`
} else {
vod_remarks = `清晰度:${playResolutions[0]},热度:${(Math.floor(parseInt(hot) / 1000)).toString()}k`
}
return vod_remarks
}
getExtendDic(extend, params) {
if (extend["5"] === undefined) {
delete params.year_range
} else {
if (extend["5"] === "0") {
delete params.year_range
} else {
params.year_range = extend["5"]
}
}
if (extend["1"] !== undefined) {
params.sort_by = extend["1"]
}
if (extend["2"] !== undefined) {
params.show_type_id = extend["2"]
}
if (extend["3"] !== undefined) {
params.region_id = extend["3"]
}
if (extend["4"] !== undefined) {
params.lang_id = extend["4"]
}
return params
}
async setHomeVod() {
let url = this.siteUrl + "/index/mobile/WAP/3.0" + await createSign()
let content = desDecrypt(await this.post(url, null, getHeader()))
if (content !== null) {
let content_json = JSON.parse(content)
let cate_list = content_json.list
for (const cate_dic of cate_list) {
for (const row of cate_dic.rows) {
for (const cells of row.cells) {
let vodShort = new VodShort()
vodShort.vod_id = cells.show["showIdCode"]
vodShort.vod_pic = cells.img
vodShort.vod_name = cells.title
vodShort.vod_remarks = this.getVodRemarks(cells.show["hot"], cells.show["playResolutions"])
this.homeVodList.push(vodShort)
}
}
}
}
}
async setCategory(tid, pg, filter, extend) {
let params = {
"sort_by": "0",
"channel_id": tid.toString(),
"show_type_id": "0",
"region_id": "0",
"lang_id": "0",
"year_range": "2023",
"start": ((parseInt(pg) - 1) * 20).toString()
}
this.limit = 20;
params = this.getExtendDic(extend, params)
let url = this.siteUrl + "/show/filter/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
for (const vod_dic of content_json["list"]) {
let vodShort = new VodShort()
vodShort.vod_id = vod_dic["showIdCode"]
vodShort.vod_name = vod_dic["showTitle"]
vodShort.vod_pic = vod_dic["showImg"]
vodShort.vod_remarks = this.getVodRemarks(vod_dic["hot"], vod_dic["playResolutions"])
this.vodList.push(vodShort)
}
}
}
async setDetail(id) {
let params = {
"show_id_code": id.toString()
}
let url = this.siteUrl + "/show/detail/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
let vod_dic = content_json["entity"]
this.vodDetail = await this.parseVodDetailfromJson(vod_dic)
let niBaVodDetail = getVod(vod_dic["plays"], ["原画"], id.toString())
this.vodDetail.vod_play_from = niBaVodDetail.vod_play_from
this.vodDetail.vod_play_url = niBaVodDetail.vod_play_url
}
}
async setSearch(wd, quick) {
let params = {"cat_id": "1", "keyword": wd, "keyword_type": "0", "start": "0"}
let url = this.siteUrl + "/show/search/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
for (const vod_dic of content_json["list"]) {
let vod_detail = await this.parseVodDetailfromJson(vod_dic)
this.vodList.push(vod_detail)
}
}
}
async setPlay(flag, id, flags) {
let playId = id.split("@")[0]
let showId = id.split("@")[1]
let params = {
"show_id_code": showId,
"play_id_code": playId
}
let url = this.siteUrl + "/show/play/info/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params,getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
this.playUrl = content_json["entity"]["playUrl"]
}
}
}
let spider = new NivodSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,242 +0,0 @@
/*
* @File : nivod18.js
* @Author : jade
* @Date : 2023/12/19 14:23
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {getHeader, createSign, desDecrypt, ChannelResponse, getVod} from "../lib/nivid_object.js"
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
class Nivod18Spider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.nivodz.com"
}
getName() {
return "🔞┃泥视频18+┃🔞"
}
getAppName() {
return "泥视频18+"
}
getJSName() {
return "nivod_18"
}
getType() {
return 3
}
async setClasses() {
let url = this.siteUrl + "/show/channel/list/WEB/3.2" + await createSign()
let content = desDecrypt(await this.post(url, null, getHeader()))
if (content !== null) {
let channelResponse = new ChannelResponse()
channelResponse.fromJsonString(content, 2)
let filterUrl = this.siteUrl + "/show/filter/condition/WEB/3.2" + await createSign()
let filterContent = desDecrypt(await this.post(filterUrl, null, getHeader()))
if (filterContent !== null) {
channelResponse.setChannelFilters(filterContent)
this.classes = channelResponse.getClassList()
this.filterObj = channelResponse.getFilters()
}
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const cate_dic of obj) {
for (const row of cate_dic.rows) {
for (const cells of row.cells) {
let vodShort = new VodShort()
vodShort.vod_id = cells.show["showIdCode"]
vodShort.vod_pic = cells.img
vodShort.vod_name = cells.title
vodShort.vod_remarks = this.getVodRemarks(cells.show["hot"], cells.show["playResolutions"])
vod_list.push(vodShort)
}
}
}
return vod_list
}
async parseVodDetailfromJson(vod_dic) {
let vodDetail = new VodDetail()
vodDetail.vod_id = vod_dic["showIdCode"]
vodDetail.vod_name = vod_dic["showTitle"]
vodDetail.vod_remarks = this.getVodRemarks(vod_dic["hot"], vod_dic["playResolutions"])
vodDetail.vod_pic = vod_dic["showImg"]
vodDetail.vod_director = vod_dic["director"]
vodDetail.vod_actor = vod_dic["actors"]
vodDetail.vod_year = vod_dic["postYear"]
vodDetail.vod_content = vod_dic["showDesc"]
vodDetail.type_name = vod_dic["showTypeName"]
vodDetail.vod_area = vod_dic["regionName"]
return vodDetail
}
getVodRemarks(hot, playResolutions) {
let vod_remarks
if (this.catOpenStatus) {
vod_remarks = `清晰度:${playResolutions[0]}`
} else {
vod_remarks = `清晰度:${playResolutions[0]},热度:${(Math.floor(parseInt(hot) / 1000)).toString()}k`
}
return vod_remarks
}
getExtendDic(extend, params) {
if (extend["5"] === undefined) {
delete params.year_range
} else {
if (extend["5"] === "0") {
delete params.year_range
} else {
params.year_range = extend["5"]
}
}
if (extend["1"] !== undefined) {
params.sort_by = extend["1"]
}
if (extend["2"] !== undefined) {
params.show_type_id = extend["2"]
}
if (extend["3"] !== undefined) {
params.region_id = extend["3"]
}
if (extend["4"] !== undefined) {
params.lang_id = extend["4"]
}
return params
}
async setHomeVod() {
let url = this.siteUrl + "/index/mobile/WAP/3.0" + await createSign()
let content = desDecrypt(await this.post(url, null, getHeader()))
if (content !== null) {
let content_json = JSON.parse(content)
let cate_list = content_json.list
for (const cate_dic of cate_list) {
for (const row of cate_dic.rows) {
for (const cells of row.cells) {
let vodShort = new VodShort()
vodShort.vod_id = cells.show["showIdCode"]
vodShort.vod_pic = cells.img
vodShort.vod_name = cells.title
vodShort.vod_remarks = this.getVodRemarks(cells.show["hot"], cells.show["playResolutions"])
this.homeVodList.push(vodShort)
}
}
}
}
}
async setCategory(tid, pg, filter, extend) {
let params = {
"sort_by": "0",
"channel_id": tid.toString(),
"show_type_id": "0",
"region_id": "0",
"lang_id": "0",
"year_range": "2023",
"start": ((parseInt(pg) - 1) * 20).toString()
}
this.limit = 20;
params = this.getExtendDic(extend, params)
let url = this.siteUrl + "/show/filter/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
for (const vod_dic of content_json["list"]) {
let vodShort = new VodShort()
vodShort.vod_id = vod_dic["showIdCode"]
vodShort.vod_name = vod_dic["showTitle"]
vodShort.vod_pic = vod_dic["showImg"]
vodShort.vod_remarks = this.getVodRemarks(vod_dic["hot"], vod_dic["playResolutions"])
this.vodList.push(vodShort)
}
}
}
async setDetail(id) {
let params = {
"show_id_code": id.toString()
}
let url = this.siteUrl + "/show/detail/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
let vod_dic = content_json["entity"]
this.vodDetail = await this.parseVodDetailfromJson(vod_dic)
let niBaVodDetail = getVod(vod_dic["plays"], ["原画"], id.toString())
this.vodDetail.vod_play_from = niBaVodDetail.vod_play_from
this.vodDetail.vod_play_url = niBaVodDetail.vod_play_url
}
}
async setSearch(wd, quick) {
let params = {"cat_id": "1", "keyword": wd, "keyword_type": "0", "start": "0"}
let url = this.siteUrl + "/show/search/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
for (const vod_dic of content_json["list"]) {
let vod_detail = await this.parseVodDetailfromJson(vod_dic)
this.vodList.push(vod_detail)
}
}
}
async setPlay(flag, id, flags) {
let playId = id.split("@")[0]
let showId = id.split("@")[1]
let params = {
"show_id_code": showId,
"play_id_code": playId
}
let url = this.siteUrl + "/show/play/info/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params,getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
this.playUrl = content_json["entity"]["playUrl"]
}
}
}
let spider = new Nivod18Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,152 +0,0 @@
/*
* @File : pan_search.js
* @Author : jade
* @Date : 2023/12/25 17:18
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 阿里盘搜仅支持搜搜
*/
import {_, load} from "../lib/cat.js";
import {Spider} from "./spider.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {detailContent, initAli, playContent} from "../lib/ali.js";
class PanSearchSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.pansearch.me/"
}
getName() {
return "🗂️┃阿里盘搜┃🗂️"
}
getAppName() {
return "阿里盘搜"
}
getJSName() {
return "pan_search"
}
getType() {
return 3
}
getSearchHeader() {
let headers = this.getHeader();
headers["x-nextjs-data"] = "1";
return headers;
}
async init(cfg) {
await super.init(cfg);
await initAli(this.cfgObj["token"]);
}
async parseVodDetailfromJson(obj) {
let item = JSON.parse(obj)
let vodDetail = new VodDetail();
let splitList = item["content"].split("\n");
vodDetail.vod_name = splitList[0].replaceAll(/<\\?[^>]+>/g, "").replace("名称:", "");
let date = new Date(item["time"])
vodDetail.vod_remarks = date.toLocaleDateString().replace(/\//g, "-") + " " + date.toTimeString().substr(0, 8)
vodDetail.vod_pic = item["image"]
let share_url = ""
for (const content of splitList) {
if (content.indexOf("描述") > -1) {
vodDetail.vod_content = content.replace("描述:", "").replaceAll(/<\\?[^>]+>/g, "")
}
if (content.indexOf("标签:") > -1) {
vodDetail.type_name = content.replace("🏷 标签:", "")
}
if (content.indexOf("链接:") > -1) {
share_url = content.replaceAll(/<\\?[^>]+>/g, "").replace("链接:", "");
}
}
try {
let aliVodDetail = await detailContent([share_url])
vodDetail.vod_play_url = aliVodDetail.vod_play_url
vodDetail.vod_play_from = aliVodDetail.vod_play_from
} catch (e) {
await this.jadeLog.error(`获取阿里视频播放失败,失败原因为:${e}`)
}
return vodDetail
}
async parseVodShortListFromDocBySearch($, wd) {
let vod_list = []
let buildId = JSON.parse($("script[id=__NEXT_DATA__]")[0].children[0].data)["buildId"]
let url = this.siteUrl + "_next/data/" + buildId + "/search.json?keyword=" + encodeURIComponent(wd) + "&pan=aliyundrive";
let aliContent = await this.fetch(url, null, this.getSearchHeader())
if (!_.isEmpty(aliContent)) {
let items = JSON.parse(aliContent)["pageProps"]["data"]["data"]
for (const item of items) {
let vodShort = new VodShort()
vodShort.vod_id = JSON.stringify(item)
let splitList = item["content"].split("\n");
vodShort.vod_name = splitList[0].replaceAll(/<\\?[^>]+>/g, "").replace("名称:", "");
let date = new Date(item["time"])
vodShort.vod_remarks = date.toLocaleDateString().replace(/\//g, "-") + " " + date.toTimeString().substr(0, 8)
vodShort.vod_pic = item["image"]
vod_list.push(vodShort)
}
return vod_list
} else {
await this.jadeLog.error("搜索页面解析失败", true)
}
}
async setDetail(id) {
this.vodDetail = await this.parseVodDetailfromJson(id)
}
async setSearch(wd, quick) {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($, wd)
}
}
async play(flag, id, flags) {
return await playContent(flag, id, flags);
}
}
let spider = new PanSearchSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,459 +0,0 @@
/*
* @File : pipixia.js
* @Author : jade
* @Date : 2024/2/2 13:33
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 完成所有的功能开发(已失效)
*/
import {_, Crypto, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {pipixiaMd5} from "../lib/pipiXiaObject.js"
class PiPiXiaSpider extends Spider {
constructor() {
super();
this.siteUrl = "http://aikun.tv/"
this.pipixiaReconnectTimes = 0
}
getHeader() {
let headers = super.getHeader();
headers["Connection"] = "keep-alive"
headers["Host"] = "pipixia.vip"
return headers
}
getName() {
return `🦐┃皮皮虾影视┃🦐`
}
getAppName() {
return `皮皮虾影视`
}
getJSName() {
return "pipixia"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $($("[class=\"wow fadeInUp animated\"]")).find("[class=\"public-list-box public-pic-b\"]")
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = Utils.getStrByRegex(/v\/(.*?).html/, $(vodElement).find("a")[0].attribs.href)
vodShort.vod_name = $(vodElement).find("a")[0].attribs.title
vodShort.vod_pic = this.baseProxy + Utils.base64Encode(this.siteUrl + "/" + $(vodElement).find("[class=\"lazy gen-movie-img mask-1\"]")[0].attribs["data-original"])
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"row-right hide\"]").find("[class=\"search-box flex rel\"]")
for (const vodElement of vodElements) {
let vodShort = new VodShort();
vodShort.vod_pic = this.baseProxy + Utils.base64Encode(this.siteUrl + "/" + Utils.getStrByRegex(/url\((.*?)\);/, $(vodElement).find("[class=\"cover\"]")[0].attribs.style))
vodShort.vod_remarks = $($(vodElement).find("[class=\"public-list-prb hide ft2\"]")).html()
vodShort.vod_name = $($(vodElement).find("[class=\"thumb-txt cor4 hide\"]")).html()
vodShort.vod_id = Utils.getStrByRegex(/v\/(.*?).html/, $(vodElement).find("[class=\"button\"]")[0].attribs.href)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const vod_json of obj["list"]) {
let vodShort = new VodShort();
vodShort.vod_name = vod_json["vod_name"]
vodShort.vod_id = vod_json["vod_id"]
vodShort.vod_pic = this.baseProxy + Utils.base64Encode(this.siteUrl + "/" + vod_json["vod_pic"])
vodShort.vod_remarks = vod_json["vod_remarks"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let detailElement = $("[class=\"vod-detail style-detail rel box cor1\"]")
vodDetail.vod_name = $($(detailElement).find("[class=\"slide-info-title hide\"]")).text()
vodDetail.vod_pic = this.siteUrl + $(detailElement).find("[class=\"detail-pic lazy mask-1\"]")[0].attribs["data-original"]
vodDetail.vod_remarks = $($($(detailElement).find("[class=\"slide-info hide\"]")[0]).find("[class=\"slide-info-remarks\"]")[0]).text()
vodDetail.vod_year = $($($(detailElement).find("[class=\"slide-info hide\"]")[0]).find("[class=\"slide-info-remarks\"]")[1]).text()
vodDetail.vod_area = $($($(detailElement).find("[class=\"slide-info hide\"]")[0]).find("[class=\"slide-info-remarks\"]")[2]).text()
vodDetail.vod_director = $($($(detailElement).find("[class=\"slide-info hide\"]")[1]).find("a")).text()
vodDetail.vod_actor = $($($(detailElement).find("[class=\"slide-info hide\"]")[2]).find("a")).text()
let type_list = []
for (const typeEle of $($(detailElement).find("[class=\"slide-info hide\"]")[3]).find("a")) {
type_list.push($(typeEle).text())
}
vodDetail.type_name = type_list.join("/")
vodDetail.vod_content = $($("[class=\"check text selected cor3\"]")).text()
let playElemet = $("[class=\"anthology wow fadeInUp animated\"]")
let playFormatElemets = $(playElemet).find("[class=\"swiper-slide\"]")
let playUrlElements = $(playElemet).find("[class=\"anthology-list-play size\"]")
let vod_play_from_list = []
let vod_play_list = []
for (let i = 0; i < playFormatElemets.length; i++) {
let playFormatElement = playFormatElemets[i]
vod_play_from_list.push(playFormatElement.children[1].data)
let vodItems = []
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async getHtml(url = this.siteUrl, headers = this.getHeader()) {
try {
let html = await this.fetch(url, null, headers)
if (!_.isEmpty(html) && html.indexOf("江苏反诈公益宣传") === -1) {
return load(html)
} else {
if (this.pipixiaReconnectTimes < this.maxReconnectTimes) {
Utils.sleep(2)
this.pipixiaReconnectTimes = this.pipixiaReconnectTimes + 1
return await this.getHtml(url, headers)
} else {
await this.jadeLog.error(`html获取失败`, true)
}
}
} catch (e) {
await this.jadeLog.error(`获取html出错,出错原因为${e}`)
}
}
async setClasses() {
let $ = await this.getHtml()
this.classes = [this.getTypeDic("首页", "最近更新")]
let $2 = await this.getHtml(this.siteUrl + "/s/1.html")
let classElemets = $2("[class=\"nav-swiper rel\"]")[0]
for (const classElement of $(classElemets).find("a")) {
let type_id = Utils.getStrByRegex(/\/s\/(.*?).html/, classElement.attribs.href)
let type_name = $(classElement).text()
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
async getFilter($) {
let elements = $("[class=\"nav-swiper rel\"]")
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let element = elements[i]
let name = $($($(element).find("[class=\"filter-text bj cor5\"]")).find("span")).html()
if (name !== "频道") {
let extend_dic = {"key": (i + 1).toString(), "name": name, "value": []}
for (const ele of $(element).find("a")) {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (Utils.isNumeric(type_id)) {
let url = this.siteUrl + `/s/${type_id}.html`
let $ = await this.getHtml(url)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl + "/map.html")
this.homeVodList = await this.parseVodShortListFromDoc($)
}
getExtend(extend, key) {
if (extend[key] !== undefined && extend[key] !== "全部") {
return extend[key]
} else {
return null
}
}
getExtendDic(params, extend) {
let class_value = this.getExtend(extend, "2")
if (class_value !== null) {
params["class"] = class_value
}
let area_value = this.getExtend(extend, "3")
if (area_value !== null) {
params["area"] = area_value
}
let year_value = this.getExtend(extend, "4")
if (year_value !== null) {
params["year"] = year_value
}
let lang_value = this.getExtend(extend, "5")
if (lang_value !== null) {
params["lang"] = lang_value
}
let letter_value = this.getExtend(extend, "6")
if (letter_value !== null) {
params["letter"] = letter_value
}
return params
}
async setCategory(tid, pg, filter, extend) {
if (Utils.isNumeric(tid)) {
let url = this.siteUrl + "/index.php/api/vod"
let time_1 = Math.floor(new Date().getTime() / 1000)
let key_1 = pipixiaMd5(time_1)
let params = {
"type": tid, "page": pg, "time": time_1.toString(), "key": key_1
}
params = this.getExtendDic(params, extend)
let content = await this.post(url, params, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
if (content_json["code"] === 1) {
this.vodList = await this.parseVodShortListFromJson(content_json)
}
}
}
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + `/v/${id}.html`)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async getPlayConfig(element) {
// let playJSUrl = this.siteUrl + element.attribs.src
// let jsContent = await this.fetch(playJSUrl,null,null)
// let playListConfig = JSON.parse(Utils.getStrByRegex(/MacPlayerConfig.player_list=(.*?),MacPlayerConfig/,jsContent))
//
let playListConfig = {
"qq": {
"show": "QQ虾线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "qiyi": {
"show": "QY虾线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qiyi&if=1&url="
}, "youku": {
"show": "YK虾线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=youku&if=1&url="
}, "mgtv": {
"show": "MG虾线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=mgtv&if=1&url="
}, "NBY": {
"show": "极速线路",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "SLNB": {
"show": "三路极速",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "FYNB": {
"show": "APP专享线路",
"des": "",
"ps": "0",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "SPA": {
"show": "极速A",
"des": "",
"ps": "0",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "SPB": {
"show": "极速B",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "kyB": {
"show": "极速直连",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "JMZN": {
"show": "极速直连",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "ZNJSON": {
"show": "极速直连",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "znkan": {
"show": "极速直连",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "bilibili": {
"show": "BLBL虾线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "pptv": {
"show": "PP虾线", "des": "", "ps": "1", "parse": "http://play.shijie.chat/player/?url="
}, "letv": {
"show": "LE虾线", "des": "", "ps": "1", "parse": "http://play.shijie.chat/player/?url="
}, "sohu": {
"show": "SH虾线", "des": "", "ps": "1", "parse": "http://play.shijie.chat/player/?url="
}, "DJMP4": {
"show": "短剧专用",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "CLDJ": {
"show": "短剧①",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "ChenXi": {
"show": "短剧专用2",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "HT-": {
"show": "自营线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "htys": {
"show": "解说线路", "des": "", "ps": "1", "parse": "http://play.shijie.chat/player/?url="
}, "sgdj": {
"show": "短剧③",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}
}
return playListConfig
}
uic(url, uid) {
let ut = Crypto.enc.Utf8.parse('2890' + uid + 'tB959C');
let mm = Crypto.enc.Utf8.parse("2F131BE91247866E");
let decrypted = Crypto.AES.decrypt(url, ut, {iv: mm, mode: Crypto.mode.CBC, padding: Crypto.pad.Pkcs7});
return Crypto.enc.Utf8.stringify(decrypted);
}
async setVideoProxy(playUrl){
let urls = []
urls.push('proxy');
urls.push(playUrl);
const pUrls = urls
for (let index = 1; index < pUrls.length; index += 2) {
pUrls[index] = js2Proxy(false, this.siteType, this.siteKey, 'hls/' + encodeURIComponent(pUrls[index]), {});
}
pUrls.push('original');
pUrls.push(playUrl);
return pUrls
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(this.siteUrl + id)
let playElements = $("[class=\"player-left\"]")
let scriptElements = $(playElements).find("script")
await this.jadeLog.debug($(scriptElements[0]).html())
let playConfig = JSON.parse($(scriptElements[0]).html().replaceAll("var player_aaaa=", ""))
let playListConfig = await this.getPlayConfig(scriptElements[1])
let jiexiUrl = playListConfig[playConfig["from"]]["parse"] + playConfig["url"]
let jiexi$ = await this.getHtml(jiexiUrl, {"User-Agent": Utils.CHROME})
let ConFig = JSON.parse(Utils.getStrByRegex(/let ConFig = (.*?),box = /, jiexi$.html()))
let playUrl = this.uic(ConFig["url"], ConFig.config.uid)
await this.jadeLog.debug(`播放链接为:${playUrl}`)
if (flag.indexOf("极速") > -1) {
this.playUrl = playUrl
} else {
if (this.catOpenStatus) {
this.playUrl = await this.setVideoProxy(playUrl)
} else {
this.playUrl = playUrl
}
}
}
async setSearch(wd, quick) {
let $ = await this.getHtml(this.siteUrl + `/vodsearch.html?wd=${decodeURI(wd)}`)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new PiPiXiaSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

View File

@ -1,108 +0,0 @@
/*
* @File : push_agent.js
* @Author : jade
* @Date : 2024/3/6 9:30
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {Spider} from "./spider.js";
import {VodDetail} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
import {detailContent, initAli, playContent} from "../lib/ali.js";
class PushSpider extends Spider {
constructor() {
super();
}
getName() {
return "┃推送┃"
}
getAppName() {
return "推送"
}
getJSName() {
return "push"
}
getType() {
return 4
}
async init(cfg) {
try {
this.cfgObj = await this.SpiderInit(cfg)
this.catOpenStatus = this.cfgObj.CatOpenStatus
await initAli(this.cfgObj["token"]);
} catch (e) {
await this.jadeLog.error(`初始化失败,失败原因为:${e}`)
}
}
async check(args){
// CatVodOpen目前支持http链接和https链接
await spider.jadeLog.debug(`剪切板输入内容为:${args}`)
if (this.catOpenStatus){
return !!args.startsWith("http");
}else{
// TV目前支持http链接和https链接和Ftp和magnet等格式
return !!(args.startsWith("http") || args.startsWith("ftp") || args.startsWith("magnet"));
}
}
async parseVodDetailfromJson(id) {
let vodDetail = new VodDetail()
vodDetail.vod_pic = Utils.RESOURCEURL + "/resources/push.jpg"
let mather = Utils.patternAli.exec(id)
if (mather !== null && mather.length > 0) {
let aliVodDetail = await detailContent([id])
vodDetail.vod_play_url = aliVodDetail.vod_play_url
vodDetail.vod_play_from = aliVodDetail.vod_play_from
} else {
vodDetail.vod_play_from = '推送';
vodDetail.vod_play_url = '推送$' + id;
}
return vodDetail
}
async setDetail(id) {
this.vodDetail = await this.parseVodDetailfromJson(id)
}
async setPlay(flag, id, flags) {
if (flag === "推送"){
this.playUrl = id
}else{
this.playUrl = JSON.parse(await playContent(flag, id, flags))["url"];
}
}
}
let spider = new PushSpider()
async function check(args) {
return await spider.check(args)
}
async function init(cfg) {
await spider.init(cfg)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
export function __jsEvalReturn() {
return {
support: check, init: init, detail: detail, play: play,
};
}
export {spider}

View File

@ -1,251 +0,0 @@
/*
* @File : sehuatang
* @Author : jade
* @Date : 2024/1/24 16:47
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 色花堂BT
*/
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {_} from "../lib/cat.js";
class SHTSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.sehuatang.net"
}
getAppName() {
return "色花堂BT"
}
getName() {
return "🔞┃色花堂BT┃🔞"
}
getJSName() {
return "sehuatang"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.jsBaseDetail = await js2Proxy(true, this.siteType, this.siteKey, 'detail/', {});
}
getHeader() {
return {
"User-Agent": "PostmanRuntime/7.36.1",
"Host": "www.sehuatang.net",
"Cookie": "cPNj_2132_saltkey=Q4BKEOEC; cf_clearance=6Gz2tvOXPkkJP2UhLnSsN4s0RrnDUy0jBN0kUvC5FNQ-1706109144-1-AebvwBnAURwWWQhj0QRBrRPku2n8xI73PIeuZVj2ckqY9zjQ7zFzDviX7Gkex1P1bUw9SXHGEYnkBB9nmWe6Nhk=; _safe=vqd37pjm4p5uodq339yzk6b7jdt6oich",
}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodShortElements = $("[id=\"portal_block_43_content\"]").find("li")
for (const vodShortElement of vodShortElements) {
let vodShort = new VodShort()
vodShort.vod_remarks = $($(vodShortElement).find("a")[1]).text()
vodShort.vod_id = $(vodShortElement).find("a")[2].attribs["href"]
vodShort.vod_name = $(vodShortElement).find("a")[2].attribs["title"]
vodShort.vod_pic = this.jsBaseDetail + Utils.base64Encode(vodShort.vod_id)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $($("[class=\"bm_c\"]")[0]).find("tbody")
for (const vodElement of vodElements) {
let user_name = $($($(vodElement).find("cite")).find("a")[0]).text()
if (user_name !== "admin" && user_name !== undefined && !_.isEmpty(user_name)) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs["href"]
vodShort.vod_remarks = $($(vodElement).find("a")[2]).text()
vodShort.vod_name = $($(vodElement).find("a")[3]).text()
vodShort.vod_pic = this.jsBaseDetail + Utils.base64Encode(vodShort.vod_id)
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let vodElement = $("[class=\"t_f\"]")[0]
let content = $(vodElement).text().replaceAll("", ":").replaceAll("【", "").replaceAll("】", "")
vodDetail.vod_pic = $(vodElement).find("img")[0].attribs["file"]
vodDetail.vod_name = Utils.getStrByRegex(/影片名称(.*?)\n/, content).replaceAll(":", "").replaceAll("\n", "")
vodDetail.vod_actor = Utils.getStrByRegex(/出演女优(.*?)\n/, content).replaceAll(":", "").replaceAll("\n", "")
vodDetail.vod_remarks = Utils.getStrByRegex(/是否有码(.*?)\n/, content).replaceAll(":", "").replaceAll("\n", "")
vodDetail.vod_play_from = "BT"
vodDetail.vod_play_url = vodDetail.vod_name + "$" + Utils.getStrByRegex(/磁力链接: (.*)复制代码/, content)
return vodDetail
}
async setClasses() {
let $ = await this.getHtml()
let tagElements = $("[id=\"category_1\"]").find("tr").slice(0, -1)
for (const tagElement of tagElements) {
let classElements = $($(tagElement).find("[class=\"fl_icn_g\"]")).find("a")
for (const classElement of classElements) {
let type_id = classElement.attribs["href"]
let type_name = $(classElement).find("img")[0].attribs["alt"]
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($) {
let extend_list = []
let extend_dic1 = {"key": 1, "name": "类型", "value": []}
let typeElements = $("[id=\"thread_types\"]").find("a")
for (const typeElement of typeElements){
let type_name = ""
if (typeElement.children.length > 1){
type_name = typeElement.children[0].data + ":" + $(typeElement.children[1]).text()
}else{
type_name = typeElement.children[0].data
}
extend_dic1["value"].push({"n":type_name,"v":typeElement.attribs["href"]})
}
extend_list.push(extend_dic1)
let extend_dic2 = {"key": 1, "name": "主题", "value": []}
let themeElements = $("[class=\"tf\"]").find("a")
for (const themeElement of themeElements){
let type_name = $(themeElement).text()
if (type_name !== "更多" && type_name !== "显示置顶"){
extend_dic2["value"].push({"n":$(themeElement).text(),"v":themeElement.attribs["href"]})
}
}
extend_list.push(extend_dic2)
return extend_list
}
async setFilterObj() {
for (const class_dic of this.classes){
let type_name = class_dic["type_name"]
let type_id = class_dic["type_id"]
if (type_name !== "最近更新"){
let $ = await this.getHtml(this.siteUrl + '/' + type_id)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
if (extend["1"]!==undefined && extend[1] ==="javascript:;"){
}else{
tid = extend["1"] ?? tid
}
let cateUrl
let tid_list = tid.split(".")[0].split("-")
if (tid_list.length > 2){
tid_list[2] = pg
cateUrl = this.siteUrl + "/" + tid_list.join("-") + ".html"
}else{
cateUrl = this.siteUrl + "/" + tid + "&page=" + pg
}
let $ = await this.getHtml(cateUrl)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + "/" + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async proxy(segments, headers) {
await this.jadeLog.debug(`正在设置反向代理 segments = ${segments.join(",")},headers = ${JSON.stringify(headers)}`)
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'detail') {
await this.jadeLog.debug(`反向代理ID为:${url}`)
let $ = await this.getHtml(this.siteUrl + "/" + url)
let vodDetail = await this.parseVodDetailFromDoc($)
await this.jadeLog.debug(`图片地址为:${vodDetail.vod_pic}`)
let resp;
if (!_.isEmpty(headers)) {
resp = await req(vodDetail.vod_pic, {
buffer: 2, headers: headers
});
} else {
resp = await req(vodDetail.vod_pic, {
buffer: 2, headers: {
Referer: url, 'User-Agent': Utils.CHROME,
},
});
}
return JSON.stringify({
code: resp.code, buffer: 2, content: resp.content, headers: resp.headers,
});
}
return JSON.stringify({
code: 500, content: '',
});
}
}
let spider = new SHTSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,672 +0,0 @@
/*
* @File : sp360.js
* @Author : jade
* @Date : 2024/3/21 11:18
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : SP360(需要用到解析)
*/
import {Spider} from "./spider.js";
import {_, Crypto, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class Sp360Spider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.web.360kan.com"
}
getName() {
return "🥎┃360影视┃🥎"
}
getAppName() {
return "360"
}
getJSName() {
return "sp360"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
}
async setClasses() {
this.classes = [this.getTypeDic("最近更新", "最近更新"), this.getTypeDic("电影", "1"), this.getTypeDic("剧集", "2"), this.getTypeDic("综艺", "3"), this.getTypeDic("动漫", "4")]
}
async setFilterObj() {
this.filterObj = {
"1": [{
"key": "cat", "name": "类型", "value": [{
"n": "全部", "v": ""
}, {
"n": "喜剧", "v": "喜剧"
}, {
"n": "爱情", "v": "爱情"
}, {
"n": "动作", "v": "动作"
}, {
"n": "恐怖", "v": "恐怖"
}, {
"n": "科幻", "v": "科幻"
}, {
"n": "剧情", "v": "剧情"
}, {
"n": "犯罪", "v": "犯罪"
}, {
"n": "奇幻", "v": "奇幻"
}, {
"n": "战争", "v": "战争"
}, {
"n": "悬疑", "v": "悬疑"
}, {
"n": "动画", "v": "动画"
}, {
"n": "文艺", "v": "文艺"
}, {
"n": "纪录", "v": "纪录"
}, {
"n": "传记", "v": "传记"
}, {
"n": "歌舞", "v": "歌舞"
}, {
"n": "古装", "v": "古装"
}, {
"n": "历史", "v": "历史"
}, {
"n": "惊悚", "v": "惊悚"
}, {
"n": "伦理", "v": "伦理"
}, {
"n": "其他", "v": "其他"
}]
}, {
"key": "year", "name": "年代", "value": [{
"n": "全部", "v": ""
}, {
"n": "2024", "v": "2024"
}, {
"n": "2023", "v": "2023"
}, {
"n": "2022", "v": "2022"
}, {
"n": "2021", "v": "2021"
}, {
"n": "2020", "v": "2020"
}, {
"n": "2019", "v": "2019"
}, {
"n": "2018", "v": "2018"
}, {
"n": "2017", "v": "2017"
}, {
"n": "2016", "v": "2016"
}, {
"n": "2015", "v": "2015"
}, {
"n": "2014", "v": "2014"
}, {
"n": "2013", "v": "2013"
}, {
"n": "2012", "v": "2012"
}, {
"n": "2010", "v": "2010"
}, {
"n": "2009", "v": "2009"
}, {
"n": "2008", "v": "2008"
}, {
"n": "2007", "v": "2007"
}, {
"n": "更早", "v": "lt_year"
}]
}, {
"key": "area", "name": "地区", "value": [{
"n": "全部", "v": ""
}, {
"n": "内地", "v": "大陆"
}, {
"n": "中国香港", "v": "香港"
}, {
"n": "中国台湾", "v": "台湾"
}, {
"n": "泰国", "v": "泰国"
}, {
"n": "美国", "v": "美国"
}, {
"n": "韩国", "v": "韩国"
}, {
"n": "日本", "v": "日本"
}, {
"n": "法国", "v": "法国"
}, {
"n": "英国", "v": "英国"
}, {
"n": "德国", "v": "德国"
}, {
"n": "印度", "v": "印度"
}, {
"n": "其他", "v": "其他"
}]
}, {
"key": "rank", "name": "排序", "value": [{
"n": "最近热映", "v": "rankhot"
}, {
"n": "最近上映", "v": "ranklatest"
}, {
"n": "最受好评", "v": "rankpoint"
}]
}], "2": [{
"key": "cat", "name": "类型", "value": [{
"n": "全部", "v": ""
}, {
"n": "言情", "v": "言情"
}, {
"n": "剧情", "v": "剧情"
}, {
"n": "伦理", "v": "伦理"
}, {
"n": "喜剧", "v": "喜剧"
}, {
"n": "悬疑", "v": "悬疑"
}, {
"n": "都市", "v": "都市"
}, {
"n": "偶像", "v": "偶像"
}, {
"n": "古装", "v": "古装"
}, {
"n": "军事", "v": "军事"
}, {
"n": "警匪", "v": "警匪"
}, {
"n": "历史", "v": "历史"
}, {
"n": "励志", "v": "励志"
}, {
"n": "神话", "v": "神话"
}, {
"n": "谍战", "v": "谍战"
}, {
"n": "青春", "v": "青春剧"
}, {
"n": "家庭", "v": "家庭剧"
}, {
"n": "动作", "v": "动作"
}, {
"n": "情景", "v": "情景"
}, {
"n": "武侠", "v": "武侠"
}, {
"n": "科幻", "v": "科幻"
}, {
"n": "其他", "v": "其他"
}, {
"n": "全部", "v": ""
}]
}, {
"key": "year", "name": "年代", "value": [{
"n": "2024", "v": "2024"
}, {
"n": "2023", "v": "2023"
}, {
"n": "2022", "v": "2022"
}, {
"n": "2021", "v": "2021"
}, {
"n": "2020", "v": "2020"
}, {
"n": "2019", "v": "2019"
}, {
"n": "2018", "v": "2018"
}, {
"n": "2017", "v": "2017"
}, {
"n": "2016", "v": "2016"
}, {
"n": "2015", "v": "2015"
}, {
"n": "2014", "v": "2014"
}, {
"n": "2013", "v": "2013"
}, {
"n": "2012", "v": "2012"
}, {
"n": "2010", "v": "2010"
}, {
"n": "2009", "v": "2009"
}, {
"n": "2008", "v": "2008"
}, {
"n": "2007", "v": "2007"
}, {
"n": "更早", "v": "lt_year"
}]
}, {
"key": "area", "name": "地区", "value": [{
"n": "全部", "v": ""
}, {
"n": "内地", "v": "内地"
}, {
"n": "中国香港", "v": "香港"
}, {
"n": "中国台湾", "v": "台湾"
}, {
"n": "泰国", "v": "泰国"
}, {
"n": "日本", "v": "日本"
}, {
"n": "韩国", "v": "韩国"
}, {
"n": "美国", "v": "美国"
}, {
"n": "英国", "v": "英国"
}, {
"n": "新加坡", "v": "新加坡"
}]
}, {
"key": "rank", "name": "排序", "value": [{
"n": "最近热映", "v": "rankhot"
}, {
"n": "最近上映", "v": "ranklatest"
}, {
"n": "最受好评", "v": "rankpoint"
}]
}], "3": [{
"key": "cat", "name": "类型", "value": [{
"n": "全部", "v": ""
}, {
"n": "脱口秀", "v": "脱口秀"
}, {
"n": "真人秀", "v": "真人秀"
}, {
"n": "搞笑", "v": "搞笑"
}, {
"n": "选秀", "v": "选秀"
}, {
"n": "八卦", "v": "八卦"
}, {
"n": "访谈", "v": "访谈"
}, {
"n": "情感", "v": "情感"
}, {
"n": "生活", "v": "生活"
}, {
"n": "晚会", "v": "晚会"
}, {
"n": "音乐", "v": "音乐"
}, {
"n": "职场", "v": "职场"
}, {
"n": "美食", "v": "美食"
}, {
"n": "时尚", "v": "时尚"
}, {
"n": "游戏", "v": "游戏"
}, {
"n": "少儿", "v": "少儿"
}, {
"n": "体育", "v": "体育"
}, {
"n": "纪实", "v": "纪实"
}, {
"n": "科教", "v": "科教"
}, {
"n": "曲艺", "v": "曲艺"
}, {
"n": "歌舞", "v": "歌舞"
}, {
"n": "财经", "v": "财经"
}, {
"n": "汽车", "v": "汽车"
}, {
"n": "播报", "v": "播报"
}, {
"n": "其他", "v": "其他"
}]
}, {
"key": "area", "name": "地区", "value": [{
"n": "全部", "v": ""
}, {
"n": "内地", "v": "大陆"
}, {
"n": "中国香港", "v": "香港"
}, {
"n": "中国台湾", "v": "台湾"
}, {
"n": "日本", "v": "日本"
}, {
"n": "欧美", "v": "欧美"
}]
}, {
"key": "rank", "name": "排序", "value": [{
"n": "最近热映", "v": "rankhot"
}, {
"n": "最近上映", "v": "ranklatest"
}]
}], "4": [{
"key": "cat", "name": "类型", "value": [{
"n": "全部", "v": ""
}, {
"n": "热血", "v": "热血"
}, {
"n": "科幻", "v": "科幻"
}, {
"n": "美少女", "v": "美少女"
}, {
"n": "魔幻", "v": "魔幻"
}, {
"n": "经典", "v": "经典"
}, {
"n": "励志", "v": "励志"
}, {
"n": "少儿", "v": "少儿"
}, {
"n": "冒险", "v": "冒险"
}, {
"n": "搞笑", "v": "搞笑"
}, {
"n": "推理", "v": "推理"
}, {
"n": "恋爱", "v": "恋爱"
}, {
"n": "治愈", "v": "治愈"
}, {
"n": "幻想", "v": "幻想"
}, {
"n": "校园", "v": "校园"
}, {
"n": "动物", "v": "动物"
}, {
"n": "机战", "v": "机战"
}, {
"n": "亲子", "v": "亲子"
}, {
"n": "儿歌", "v": "儿歌"
}, {
"n": "运动", "v": "运动"
}, {
"n": "悬疑", "v": "悬疑"
}, {
"n": "怪物", "v": "怪物"
}, {
"n": "战争", "v": "战争"
}, {
"n": "益智", "v": "益智"
}, {
"n": "青春", "v": "青春"
}, {
"n": "童话", "v": "童话"
}, {
"n": "竞技", "v": "竞技"
}, {
"n": "动作", "v": "动作"
}, {
"n": "社会", "v": "社会"
}, {
"n": "友情", "v": "友情"
}, {
"n": "真人版", "v": "真人版"
}, {
"n": "电影版", "v": "电影版"
}, {
"n": "OVA版", "v": "OVA版"
}, {
"n": "TV版", "v": "TV版"
}, {
"n": "新番动画", "v": "新番动画"
}, {
"n": "完结动画", "v": "完结动画"
}]
}, {
"key": "year", "name": "年代", "value": [{
"n": "全部", "v": ""
}, {
"n": "2024", "v": "2024"
}, {
"n": "2023", "v": "2023"
}, {
"n": "2022", "v": "2022"
}, {
"n": "2021", "v": "2021"
}, {
"n": "2020", "v": "2020"
}, {
"n": "2019", "v": "2019"
}, {
"n": "2018", "v": "2018"
}, {
"n": "2017", "v": "2017"
}, {
"n": "2016", "v": "2016"
}, {
"n": "2015", "v": "2015"
}, {
"n": "2014", "v": "2014"
}, {
"n": "2013", "v": "2013"
}, {
"n": "2012", "v": "2012"
}, {
"n": "2011", "v": "2011"
}, {
"n": "2010", "v": "2010"
}, {
"n": "2009", "v": "2009"
}, {
"n": "2008", "v": "2008"
}, {
"n": "2007", "v": "2007"
}, {
"n": "2006", "v": "2006"
}, {
"n": "2005", "v": "2005"
}, {
"n": "2004", "v": "2004"
}, {
"n": "更早", "v": "更早"
}]
}, {
"key": "area", "name": "地区", "value": [{
"n": "全部", "v": ""
}, {
"n": "内地", "v": "大陆"
}, {
"n": "日本", "v": "日本"
}, {
"n": "美国", "v": "美国"
}]
}, {
"key": "rank", "name": "排序", "value": [{
"n": "最近热映", "v": "rankhot"
}, {
"n": "最近上映", "v": "ranklatest"
}]
}]
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const data of obj["data"]) {
let vodShort = new VodShort();
vodShort.vod_id = data["ent_id"] + "+" + data["cat"]
if (!data["cover"].startsWith("http")) {
vodShort.vod_pic = "https:" + data["cover"]
} else {
vodShort.vod_pic = data["cover"]
}
vodShort.vod_name = data["title"]
vodShort.vod_remarks = data["upinfo"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromJsonByCategory(obj, tid) {
let vod_list = []
for (const data of obj["data"]["movies"]) {
let vodShort = new VodShort();
vodShort.vod_id = data["id"] + "+" + tid
if (!data["cover"].startsWith("http")) {
vodShort.vod_pic = "https:" + data["cover"]
} else {
vodShort.vod_pic = data["cover"]
}
vodShort.vod_name = data["title"]
vodShort.vod_remarks = data["tag"]
if (!_.isEmpty(data["doubanscore"])) {
vodShort.vod_remarks = "豆瓣评分:" + data["doubanscore"]
} else {
if (_.isEmpty(vodShort.vod_remarks)) {
vodShort.vod_remarks = data["pubdate"]
}
}
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail()
let data = obj["data"]
vodDetail.vod_name = data["title"]
vodDetail.vod_pic = data["cdncover"]
vodDetail.vod_remarks = data["pubdate"]
vodDetail.vod_actor = data["actor"].join("*")
vodDetail.vod_director = data["director"].join("*")
vodDetail.type_name = data["moviecategory"].join("*")
vodDetail.vod_year = data["pubdate"]
vodDetail.vod_area = data["area"].join("*")
vodDetail.vod_content = data["description"]
let playlist = {}
for (const playFormat of data["playlink_sites"]) {
let vodItems = []
if (!_.isEmpty(data["allepidetail"])) {
if (data["allepidetail"][playFormat] !== undefined) {
for (const items of data["allepidetail"][playFormat]) {
let episodeUrl = items["url"]
let episodeName = items["playlink_num"]
vodItems.push(episodeName + "$" + episodeUrl);
}
}
} else {
let items = data["playlinksdetail"][playFormat]
let episodeUrl = items["default_url"]
let episodeName = items["quality"]
vodItems.push(episodeName + "$" + episodeUrl);
}
if (vodItems.length > 0){
playlist[playFormat] = vodItems.join("#")
}
}
vodDetail.vod_play_url = _.values(playlist).join('$$$');
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
return vodDetail
}
async parseVodShortListFromJsonBySearch(obj) {
let vod_list = []
for (const data of obj["data"]["longData"]["rows"]) {
let vodShort = new VodShort();
vodShort.vod_id = data["en_id"] + "+" + data["cat_id"]
if (!data["cover"].startsWith("http")) {
vodShort.vod_pic = "https:" + data["cover"]
} else {
vodShort.vod_pic = data["cover"]
}
vodShort.vod_name = data["titleTxt"]
vodShort.vod_remarks = data["coverInfo"]["txt"]
vod_list.push(vodShort)
}
return vod_list
}
async setHomeVod() {
let response = await this.fetch(this.siteUrl + "/v1/rank?cat=1", null, this.getHeader())
this.homeVodList = await this.parseVodShortListFromJson(JSON.parse(response))
}
async setCategory(tid, pg, filter, extend) {
let rank = extend["by"] ?? "rankhot"
let year = extend["year"] ?? ""
let cat = extend["cat"] ?? ""
let area = extend["area"] ?? ""
let url = this.siteUrl + `/v1/filter/list?catid=${tid}&rank=${rank}&cat=${cat}&year=${year}&area=${area}&act=&size=35&pageno=${pg}&callback=`
let response = await this.fetch(url, null, this.getHeader())
this.vodList = await this.parseVodShortListFromJsonByCategory(JSON.parse(response), tid)
}
async setDetail(id) {
let tid_list = id.split("+")
let url = this.siteUrl + `/v1/detail?cat=${tid_list[1]}&id=${tid_list[0]}`
let response = await this.fetch(url, null, this.getHeader())
this.vodDetail = await this.parseVodDetailfromJson(JSON.parse(response))
}
async setSearch(wd, quick) {
let url = `https://api.so.360kan.com/index?force_v=1&kw=${wd}&from=&pageno=1&v_ap=1&tab=all`
let response = await this.fetch(url, null, this.getHeader())
this.vodList = await this.parseVodShortListFromJsonBySearch(JSON.parse(response))
}
async setPlay(flag, id, flags) {
if (this.danmuStaus && ! this.catOpenStatus) {
this.danmuUrl = await this.danmuSpider.getVideoUrl(id, 0)
}
this.result.parse = 1 //启用自动解析
this.result.jx = 1
this.playUrl = id
}
}
let spider = new Sp360Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,902 +0,0 @@
/*
* @File : spider.js
* @Author : jade
* @Date : 2023/12/25 17:19
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {JadeLogging} from "../lib/log.js";
import * as Utils from "../lib/utils.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {_, load, Uri} from "../lib/cat.js";
import * as HLS from "../lib/hls.js";
import {hlsCache, tsCache} from "../lib/ffm3u8_open.js";
import {DanmuSpider} from "../lib/danmuSpider.js";
import {initAli} from "../lib/ali.js";
class Result {
constructor() {
this.class = []
this.list = []
this.filters = []
this.header = {"User-Agent": Utils.CHROME};
this.format = "";
this.danmaku = "";
this.url = "";
this.subs = [];
this.parse = 0
this.jx = 0;
this.page = 0
this.pagecount = 0
this.limit = 0;
this.total = 0;
this.extra = {}
}
get() {
return new Result()
}
home(classes, list, filters) {
return JSON.stringify({
"class": classes, "list": list, "filters": filters
})
}
homeVod(vod_list) {
return JSON.stringify({"page": this.page, "list": vod_list, "pagecount": this.page, "total": this.page})
}
category(vod_list, page, count, limit, total) {
return JSON.stringify({
page: parseInt(page), pagecount: count, limit: limit, total: total, list: vod_list,
});
}
search(vod_list) {
return JSON.stringify({"list": vod_list,"page":this.page,"pagecount":this.pagecount,"total":this.total})
}
detail(vod_detail) {
return JSON.stringify({"list": [vod_detail]})
}
play(url) {
if (!_.isEmpty(this.danmaku)) {
return JSON.stringify({
"url": url,
"parse": this.parse,
"header": this.header,
"format": this.format,
"subs": this.subs,
"danmaku": this.danmaku,
"extra": this.extra,
"jx": this.jx
})
} else {
return JSON.stringify({
"url": url,
"parse": this.parse,
"header": this.header,
"format": this.format,
"subs": this.subs,
"extra": this.extra,
"jx": this.jx
})
}
}
playTxt(url) {
return url
}
errorCategory(error_message) {
let vodShort = new VodShort()
vodShort.vod_name = "错误:打开无效"
vodShort.vod_id = "error"
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/error.png"
vodShort.vod_remarks = error_message
return JSON.stringify({
page: parseInt(0), pagecount: 0, limit: 0, total: 0, list: [vodShort],
})
}
setClass(classes) {
this.class = classes;
return this;
}
setVod(list) {
if (typeof list === "object" && Array.isArray(list)) {
this.list = list;
} else if (list !== undefined) {
this.list = [list]
}
return this;
}
setFilters(filters) {
this.filters = filters;
return this;
}
setHeader(header) {
this.header = header;
return this;
}
setParse(parse) {
this.parse = parse;
return this;
}
setJx() {
this.jx = 1;
return this;
}
setUrl(url) {
this.url = url;
return this;
}
danmu(danmaku) {
this.danmaku = danmaku;
return this;
}
setFormat(format) {
this.format = format;
return this;
}
setSubs(subs) {
this.subs = subs;
return this;
}
dash() {
this.format = "application/dash+xml";
return this;
}
m3u8() {
this.format = "application/x-mpegURL";
return this;
}
rtsp() {
this.format = "application/x-rtsp";
return this;
}
octet() {
this.format = "application/octet-stream";
return this;
}
setPage(page, count, limit, total) {
this.page = page
this.limit = limit
this.total = total
this.pagecount = count
return this;
}
toString() {
return JSON.stringify(this);
}
}
class Spider {
constructor() {
this.siteKey = ""
this.siteType = 0
this.jadeLog = new JadeLogging(this.getAppName(), "DEBUG")
this.classes = []
this.filterObj = {}
this.result = new Result()
this.catOpenStatus = true
this.danmuStaus = false
this.reconnectTimes = 0
this.maxReconnectTimes = 5
this.siteUrl = ""
this.vodList = []
this.homeVodList = []
this.count = 0
this.limit = 0
this.total = 0
this.page = 0
this.vodDetail = new VodDetail()
this.playUrl = ""
this.header = {}
this.remove18 = false
this.type_id_18 = 0
this.type_name_18 = "伦理片"
this.episodeObj = {}
this.danmuUrl = ""
this.cfgObj = {}
}
async reconnnect(reqUrl, params, headers, redirect_url, return_cookie, buffer) {
await this.jadeLog.error("请求失败,请检查url:" + reqUrl + ",两秒后重试")
Utils.sleep(2)
if (this.reconnectTimes < this.maxReconnectTimes) {
this.reconnectTimes = this.reconnectTimes + 1
return await this.fetch(reqUrl, params, headers, redirect_url, return_cookie, buffer)
} else {
await this.jadeLog.error("请求失败,重连失败")
return null
}
}
getClassIdList() {
let class_id_list = []
for (const class_dic of this.classes) {
class_id_list.push(class_dic["type_id"])
}
return class_id_list
}
getTypeDic(type_name, type_id) {
return {"type_name": type_name, "type_id": type_id}
}
getFliterDic(type_name, type_id) {
return {"n": type_name, "v": type_id}
}
async getHtml(url = this.siteUrl, proxy = false, headers = this.getHeader()) {
let html = await this.fetch(url, null, headers, false, false, 0, proxy)
if (!_.isEmpty(html)) {
return load(html)
} else {
await this.jadeLog.error(`html获取失败`, true)
}
}
getClassNameList() {
let class_name_list = []
for (const class_dic of this.classes) {
class_name_list.push(class_dic["type_name"])
}
return class_name_list
}
async postReconnect(reqUrl, params, headers,postType,buffer) {
await this.jadeLog.error("请求失败,请检查url:" + reqUrl + ",两秒后重试")
Utils.sleep(2)
if (this.reconnectTimes < this.maxReconnectTimes) {
this.reconnectTimes = this.reconnectTimes + 1
return await this.post(reqUrl, params, headers,postType,buffer)
} else {
await this.jadeLog.error("请求失败,重连失败")
return null
}
}
getHeader() {
return {"User-Agent": Utils.CHROME, "Referer": this.siteUrl + "/"};
}
async getResponse(reqUrl, params, headers, redirect_url, return_cookie, buffer, response,proxy) {
{
if (response.headers["location"] !== undefined) {
if (redirect_url) {
await this.jadeLog.debug(`返回重定向连接:${response.headers["location"]}`)
return response.headers["location"]
} else {
return this.fetch(response.headers["location"], params, headers, redirect_url, return_cookie, buffer,proxy)
}
} else if (response.content.length > 0) {
this.reconnectTimes = 0
if (return_cookie) {
return {"cookie": response.headers["set-cookie"], "content": response.content}
} else {
return response.content
}
} else if (buffer === 1) {
this.reconnectTimes = 0
return response.content
} else {
await this.jadeLog.error(`请求失败,请求url为:${reqUrl},回复内容为:${JSON.stringify(response)}`)
return await this.reconnnect(reqUrl, params, headers, redirect_url, return_cookie, buffer,proxy)
}
}
}
async fetch(reqUrl, params, headers, redirect_url = false, return_cookie = false, buffer = 0, proxy = false) {
let data = Utils.objectToStr(params)
let url = reqUrl
if (!_.isEmpty(data)) {
url = reqUrl + "?" + data
}
let uri = new Uri(url);
let response;
if (redirect_url) {
response = await req(uri.toString(), {
method: "get", headers: headers, buffer: buffer, data: null, redirect: 2, proxy: proxy
})
} else {
response = await req(uri.toString(), {method: "get", headers: headers, buffer: buffer, data: null,proxy:proxy,timeout:10000});
}
if (response.code === 200 || response.code === 302 || response.code === 301 || return_cookie) {
return await this.getResponse(reqUrl, params, headers, redirect_url, return_cookie, buffer, response,proxy)
} else {
await this.jadeLog.error(`请求失败,失败原因为:状态码出错,请求url为:${uri},回复内容为:${JSON.stringify(response)}`)
return await this.reconnnect(reqUrl, params, headers, redirect_url, return_cookie, buffer)
}
}
async redirect(response) {
}
async post(reqUrl, params, headers, postType = "form",buffer = 0) {
let uri = new Uri(reqUrl);
let response = await req(uri.toString(), {
method: "post", headers: headers, data: params, postType: postType,buffer: buffer
});
if (response.code === 200 || response.code === undefined || response.code === 302) {
// 重定向
if (response.headers["location"] !== undefined) {
return await this.redirect(response)
} else if (!_.isEmpty(response.content)) {
this.reconnectTimes = 0
return response.content
} else {
return await this.postReconnect(reqUrl, params, headers,postType,buffer)
}
} else {
await this.jadeLog.error(`请求失败,请求url为:${reqUrl},回复内容为${JSON.stringify(response)}`)
return await this.postReconnect(reqUrl, params, headers,postType,buffer)
}
}
getName() {
return `🍥┃基础┃🍥`
}
getAppName() {
return `基础`
}
getJSName() {
return "base"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
}
async parseVodShortListFromJson(obj) {
}
parseVodShortFromElement($, element) {
}
async parseVodShortListFromDocByCategory($) {
}
async getFilter($) {
}
async setClasses() {
}
async setFilterObj() {
}
async parseVodShortListFromDocBySearch($) {
return []
}
async parseVodDetailFromDoc($) {
}
async parseVodDetailfromJson(obj) {
}
async parseVodPlayFromUrl(flag, play_url) {
}
async parseVodPlayFromDoc(flag, $) {
}
async SpiderInit(cfg) {
try {
this.siteKey = cfg["skey"]
this.siteType = parseInt(cfg["stype"].toString())
let extObj = null;
if (typeof cfg.ext === "string") {
await this.jadeLog.info(`读取配置文件,ext为:${cfg.ext}`)
extObj = JSON.parse(cfg.ext)
} else if (typeof cfg.ext === "object") {
await this.jadeLog.info(`读取配置文件,所有参数为:${JSON.stringify(cfg)}`)
await this.jadeLog.info(`读取配置文件,ext为:${JSON.stringify(cfg.ext)}`)
extObj = cfg.ext
} else {
await this.jadeLog.error(`不支持的数据类型,数据类型为${typeof cfg.ext}`)
}
let boxType = extObj["box"]
extObj["CatOpenStatus"] = boxType === "CatOpen";
return extObj
} catch (e) {
await this.jadeLog.error("初始化失败,失败原因为:" + e.message)
return {"token": null, "CatOpenStatus": false, "code": 0}
}
}
async initAli(token, db = null) {
await initAli(token, db)
}
async spiderInit() {
}
async init(cfg) {
this.danmuSpider = new DanmuSpider()
this.cfgObj = await this.SpiderInit(cfg)
await this.jadeLog.debug(`初始化参数为:${JSON.stringify(cfg)}`)
this.catOpenStatus = this.cfgObj.CatOpenStatus
this.danmuStaus = this.cfgObj["danmu"] ?? this.danmuStaus
try {
if (await this.loadFilterAndClasses()) {
await this.jadeLog.debug(`读取缓存列表和二级菜单成功`)
} else {
await this.jadeLog.warning(`读取缓存列表和二级菜单失败`)
await this.writeFilterAndClasses()
}
} catch (e) {
await local.set(this.siteKey, "classes", JSON.stringify([]));
await local.set(this.siteKey, "filterObj", JSON.stringify({}));
await this.jadeLog.error("读取缓存失败,失败原因为:" + e)
}
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', {});
this.douBanjsBase = await js2Proxy(true, this.siteType, this.siteKey, 'douban/', {});
this.baseProxy = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
this.videoProxy = await js2Proxy(true, this.siteType, this.siteKey, 'm3u8/', {});
this.detailProxy = await js2Proxy(true, this.siteType, this.siteKey, 'detail/', this.getHeader());
}
async loadFilterAndClasses() {
// 强制清空
// await local.set(this.siteKey, "classes", JSON.stringify([]));
// await local.set(this.siteKey, "filterObj", JSON.stringify({}));
this.classes = await this.getClassesCache()
this.filterObj = await this.getFiletObjCache()
if (this.classes.length > 0) {
return true
} else {
await local.set(this.siteKey, "classes", JSON.stringify([]));
await local.set(this.siteKey, "filterObj", JSON.stringify({}));
return false
}
}
async writeFilterAndClasses() {
if (this.catOpenStatus) {
this.classes.push({"type_name": "最近更新", "type_id": "最近更新"})
}
await this.setClasses()
await this.setFilterObj()
await local.set(this.siteKey, "classes", JSON.stringify(this.classes));
await local.set(this.siteKey, "filterObj", JSON.stringify(this.filterObj));
}
async getClassesCache() {
let cacheClasses = await local.get(this.siteKey, "classes")
if (!_.isEmpty(cacheClasses)) {
return JSON.parse(cacheClasses)
} else {
return this.classes
}
}
async getFiletObjCache() {
let cacheFilterObj = await local.get(this.siteKey, "filterObj")
if (!_.isEmpty(cacheFilterObj)) {
return JSON.parse(cacheFilterObj)
} else {
return this.filterObj
}
}
async setHome(filter) {
}
async home(filter) {
this.vodList = []
await this.jadeLog.info("正在解析首页类别", true)
await this.setHome(filter)
await this.jadeLog.debug(`首页类别内容为:${this.result.home(this.classes, [], this.filterObj)}`)
await this.jadeLog.info("首页类别解析完成", true)
return this.result.home(this.classes, [], this.filterObj)
}
async setHomeVod() {
}
async homeVod() {
await this.jadeLog.info("正在解析首页内容", true)
await this.setHomeVod()
await this.jadeLog.debug(`首页内容为:${this.result.homeVod(this.homeVodList)}`)
await this.jadeLog.info("首页内容解析完成", true)
return this.result.homeVod(this.homeVodList)
}
async setCategory(tid, pg, filter, extend) {
}
async category(tid, pg, filter, extend) {
this.page = parseInt(pg)
await this.jadeLog.info(`正在解析分类页面,tid = ${tid},pg = ${pg},filter = ${filter},extend = ${JSON.stringify(extend)}`)
if (tid === "最近更新") {
this.page = 0
return await this.homeVod()
} else {
try {
this.vodList = []
await this.setCategory(tid, pg, filter, extend)
await this.jadeLog.debug(`分类页面内容为:${this.result.category(this.vodList, this.page, this.count, this.limit, this.total)}`)
await this.jadeLog.info("分类页面解析完成", true)
return this.result.category(this.vodList, this.page, this.count, this.limit, this.total)
} catch (e) {
await this.jadeLog.error(`分类页解析失败,失败原因为:${e}`)
}
}
}
async setDetail(id) {
}
setEpisodeCache() {
// 记录每个播放链接的集数
let episodeObj = {
"vodDetail": this.vodDetail.to_dict(),
}
let vod_url_channels_list = this.vodDetail.vod_play_url.split("$$$")
for (const vodItemsStr of vod_url_channels_list) {
let vodItems = vodItemsStr.split("#")
for (const vodItem of vodItems) {
let episodeName = vodItem.split("$")[0].split(" ")[0]
let episodeUrl = vodItem.split("$")[1]
let matchers = episodeName.match(/\d+/g)
if (matchers !== null && matchers.length > 0) {
episodeName = matchers[0]
}
episodeObj[episodeUrl] = {"episodeName": episodeName, "episodeId": episodeName}
}
}
return episodeObj
}
async detail(id) {
this.vodDetail = new VodDetail();
await this.jadeLog.info(`正在获取详情页面,id为:${id}`)
try {
await this.setDetail(id)
await this.jadeLog.debug(`详情页面内容为:${this.result.detail(this.vodDetail)}`)
await this.jadeLog.info("详情页面解析完成", true)
this.vodDetail.vod_id = id
if (this.siteType === 3) {
this.episodeObj = this.setEpisodeCache()
}
return this.result.detail(this.vodDetail)
} catch (e) {
await this.jadeLog.error("详情界面获取失败,失败原因为:" + e)
}
}
async setPlay(flag, id, flags) {
this.playUrl = id
}
async setDanmu(id) {
await this.jadeLog.debug(`${JSON.stringify(this.episodeObj)}`)
let episodeId = this.episodeObj[id]
let vodDetail = JSON.parse(this.episodeObj["vodDetail"])
delete vodDetail.vod_content;
delete vodDetail.vod_play_from;
delete vodDetail.vod_play_url;
delete vodDetail.vod_pic;
await this.jadeLog.debug(`正在加载弹幕,视频详情为:${JSON.stringify(vodDetail)},集数:${JSON.stringify(this.episodeObj[id])}`)
//区分电影还是电视剧
return await this.danmuSpider.getDammu(vodDetail, episodeId)
}
async play(flag, id, flags) {
await this.jadeLog.info(`正在解析播放页面,flag:${flag},id:${id},flags:${flags}`, true)
try {
let return_result;
await this.setPlay(flag, id, flags)
if (this.playUrl["content"] !== undefined) {
return_result = this.result.playTxt(this.playUrl)
} else {
if (this.danmuStaus && !this.catOpenStatus) {
if (!_.isEmpty(this.danmuUrl)) {
await this.jadeLog.debug("播放详情页面有弹幕,所以不需要再查找弹幕")
return_result = this.result.danmu(this.danmuUrl).play(this.playUrl)
} else {
let danmuUrl;
try {
danmuUrl = await this.setDanmu(id)
} catch (e) {
await this.jadeLog.error(`弹幕加载失败,失败原因为:${e}`)
}
return_result = this.result.danmu(danmuUrl).play(this.playUrl)
}
} else {
await this.jadeLog.debug("不需要加载弹幕", true)
return_result = this.result.play(this.playUrl)
}
}
await this.jadeLog.info("播放页面解析完成", true)
await this.jadeLog.debug(`播放页面内容为:${return_result}`)
return return_result;
} catch (e) {
await this.jadeLog.error("解析播放页面出错,失败原因为:" + e)
}
}
async setSearch(wd, quick) {
}
async search(wd, quick) {
this.vodList = []
await this.jadeLog.info(`正在解析搜索页面,关键词为 = ${wd},quick = ${quick}`)
await this.setSearch(wd, quick,1)
if (this.vodList.length === 0) {
if (wd.indexOf(" ") > -1) {
await this.jadeLog.debug(`搜索关键词为:${wd},其中有空格,去除空格在搜索一次`)
await this.search(wd.replaceAll(" ", "").replaceAll("", ""), quick)
}
}
await this.jadeLog.debug(`搜索页面内容为:${this.result.search(this.vodList)}`)
await this.jadeLog.info("搜索页面解析完成", true)
return this.result.search(this.vodList)
}
async getImg(url, headers) {
let resp;
let vpn_proxy = headers["Proxy"] // 使用代理不需要加headers
if (_.isEmpty(headers)) {
headers = {Referer: url, 'User-Agent': Utils.CHROME}
}
resp = await req(url, {buffer: 2, headers: headers,proxy:vpn_proxy});
try {
//二进制文件是不能使用Base64编码格式的
Utils.base64Decode(resp.content)
if (vpn_proxy){
await this.jadeLog.error(`使用VPN代理,图片地址为:${url},headers:${JSON.stringify(headers)},代理失败,准备重连,输出内容为:${JSON.stringify(resp)}`)
}else {
await this.jadeLog.error(`使用普通代理,图片地址为:${url},headers:${JSON.stringify(headers)},代理失败,准备重连,输出内容为:${JSON.stringify(resp)}`)
}
if (this.reconnectTimes < this.maxReconnectTimes){
this.reconnectTimes = this.reconnectTimes + 1
return await this.getImg(url,headers)
}else{
return {"code": 500, "headers": headers, "content": "加载失败"}
}
} catch (e) {
await this.jadeLog.debug("图片代理成功", true)
this.reconnectTimes = 0
return resp
}
}
async proxy(segments, headers) {
await this.jadeLog.debug(`正在设置反向代理 segments = ${segments.join(",")},headers = ${JSON.stringify(headers)}`)
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
await this.jadeLog.debug(`反向代理参数为:${url}`)
if (what === 'img') {
await this.jadeLog.debug("通过代理获取图片", true)
let resp = await this.getImg(url, headers)
return JSON.stringify({
code: resp.code, buffer: 2, content: resp.content, headers: resp.headers,
});
} else if (what === "douban") {
let vod_list = await this.doubanSearch(url)
if (vod_list !== null) {
let vod_pic = vod_list[0].vod_pic
let resp;
if (!_.isEmpty(headers)) {
resp = await req(vod_pic, {
buffer: 2, headers: headers
});
} else {
resp = await req(vod_pic, {
buffer: 2, headers: {
Referer: vod_pic, 'User-Agent': Utils.CHROME,
},
});
}
return JSON.stringify({
code: resp.code, buffer: 2, content: resp.content, headers: resp.headers,
});
}
} else if (what === "m3u8") {
let content;
if (!_.isEmpty(headers)) {
content = await this.fetch(url, null, headers, false, false, 2)
} else {
content = await this.fetch(url, null, {"Referer": url, 'User-Agent': Utils.CHROME}, false, false, 2)
}
await this.jadeLog.debug(`m3u8返回内容为:${Utils.base64Decode(content)}`)
if (!_.isEmpty(content)) {
return JSON.stringify({
code: 200, buffer: 2, content: content, headers: {},
});
} else {
return JSON.stringify({
code: 500, buffer: 2, content: content, headers: {},
})
}
} else if (what === 'hls') {
function hlsHeader(data, hls) {
let hlsHeaders = {};
if (data.headers['content-length']) {
Object.assign(hlsHeaders, data.headers, {'content-length': hls.length.toString()});
} else {
Object.assign(hlsHeaders, data.headers);
}
delete hlsHeaders['transfer-encoding'];
if (hlsHeaders['content-encoding'] == 'gzip') {
delete hlsHeaders['content-encoding'];
}
return hlsHeaders;
}
const hlsData = await hlsCache(url, headers);
if (hlsData.variants) {
// variants -> variants -> .... ignore
const hls = HLS.stringify(hlsData.plist);
return {
code: hlsData.code, content: hls, headers: hlsHeader(hlsData, hls),
};
} else {
const hls = HLS.stringify(hlsData.plist, (segment) => {
return js2Proxy(false, this.siteType, this.siteKey, 'ts/' + encodeURIComponent(hlsData.key + '/' + segment.mediaSequenceNumber.toString()), headers);
});
return {
code: hlsData.code, content: hls, headers: hlsHeader(hlsData, hls),
};
}
} else if (what === 'ts') {
const info = url.split('/');
const hlsKey = info[0];
const segIdx = parseInt(info[1]);
return await tsCache(hlsKey, segIdx, headers);
} else if (what === "detail") {
let $ = await this.getHtml(this.siteUrl + url)
let vodDetail = await this.parseVodDetailFromDoc($)
let resp = await this.getImg(vodDetail.vod_pic, headers)
return JSON.stringify({
code: resp.code, buffer: 2, content: resp.content, headers: resp.headers,
});
} else {
return JSON.stringify({
code: 500, content: '',
});
}
}
getSearchHeader() {
const UserAgents = ["api-client/1 com.douban.frodo/7.22.0.beta9(231) Android/23 product/Mate 40 vendor/HUAWEI model/Mate 40 brand/HUAWEI rom/android network/wifi platform/AndroidPad", "api-client/1 com.douban.frodo/7.18.0(230) Android/22 product/MI 9 vendor/Xiaomi model/MI 9 brand/Android rom/miui6 network/wifi platform/mobile nd/1", "api-client/1 com.douban.frodo/7.1.0(205) Android/29 product/perseus vendor/Xiaomi model/Mi MIX 3 rom/miui6 network/wifi platform/mobile nd/1", "api-client/1 com.douban.frodo/7.3.0(207) Android/22 product/MI 9 vendor/Xiaomi model/MI 9 brand/Android rom/miui6 network/wifi platform/mobile nd/1"]
let randomNumber = Math.floor(Math.random() * UserAgents.length); // 生成一个介于0到9之间的随机整数
return {
'User-Agent': UserAgents[randomNumber]
}
}
async parseDoubanVodShortListFromJson(obj) {
let vod_list = []
for (const item of obj) {
let vod_short = new VodShort()
vod_short.vod_id = "msearch:" + item["id"]
if (item["title"] === undefined) {
vod_short.vod_name = item["target"]["title"]
} else {
vod_short.vod_name = item["title"]
}
if (item["pic"] === undefined) {
vod_short.vod_pic = item["target"]["cover_url"]
} else {
vod_short.vod_pic = item["pic"]["normal"]
}
if (item["rating"] === undefined) {
vod_short.vod_remarks = "评分:" + item["target"]["rating"]["value"].toString()
} else {
vod_short.vod_remarks = "评分:" + item["rating"]["value"].toString()
}
vod_list.push(vod_short);
}
return vod_list
}
sign(url, ts, method = 'GET') {
let _api_secret_key = "bf7dddc7c9cfe6f7"
let url_path = "%2F" + url.split("/").slice(3).join("%2F")
let raw_sign = [method.toLocaleUpperCase(), url_path, ts.toString()].join("&")
return CryptoJS.HmacSHA1(raw_sign, _api_secret_key).toString(CryptoJS.enc.Base64)
}
async doubanSearch(wd) {
try {
let _api_url = "https://frodo.douban.com/api/v2"
let _api_key = "0dad551ec0f84ed02907ff5c42e8ec70"
let url = _api_url + "/search/movie"
let date = new Date()
let ts = date.getFullYear().toString() + (date.getMonth() + 1).toString() + date.getDate().toString()
let params = {
'_sig': this.sign(url, ts),
'_ts': ts,
'apiKey': _api_key,
'count': 20,
'os_rom': 'android',
'q': encodeURIComponent(wd),
'start': 0
}
let content = await this.fetch(url, params, this.getSearchHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
await this.jadeLog.debug(`豆瓣搜索结果:${content}`)
return await this.parseDoubanVodShortListFromJson(content_json["items"])
}
return null
} catch (e) {
await this.jadeLog.error("反向代理出错,失败原因为:" + e)
}
}
}
export {Spider, Result}

View File

@ -1,290 +0,0 @@
/*
* @File : star.js
* @Author : jade
* @Date : 2024/2/21 10:36
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 星视界 需要翻墙
*/
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {_} from "../lib/cat.js";
class StarSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.histar.tv"
this.apiUrl = "https://aws.ulivetv.net"
}
getAppName() {
return "星视界"
}
getName() {
return "☄️┃星视界┃墙☄️"
}
getJSName() {
return "star"
}
getType() {
return 3
}
getApiHeader() {
return {'User-Agent': Utils.MOBILEUA, "Content-Type": 'application/json'}
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $($("[class=\"nav_nav__zgz60\"]")[0]).find("a")
for (const navElement of navElements) {
let type_id = navElement.attribs.href
let type_name = $(navElement).text()
if (type_id !== "/" && type_name !== "电视直播") {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
convertTypeData(typeData, key, name) {
if (!typeData || !typeData[key] || typeData[key].length <= 2) {
return null;
}
let valueList = typeData[key];
if (key === 'time') {
valueList = valueList.sort((a, b) => {
return b - a;
});
valueList.pop();
}
const values = _.map(valueList, (item) => {
let name;
let value;
if (item instanceof Array) {
name = item[0];
value = item[0];
} else {
name = item.toString();
value = item.toString();
}
return {
n: name, v: value,
};
});
values.unshift({
n: '全部', v: '',
});
return {
key: key, name: name, init: '', value: values,
};
}
async getFilter($) {
const json = $('#__NEXT_DATA__')[0].children[0].data;
const obj = JSON.parse(json).props["pageProps"]["filterCondition"];
const label = this.convertTypeData(obj, 'label', '类型');
const country = this.convertTypeData(obj, 'country', '地区');
const time = this.convertTypeData(obj, 'time', '年份');
return [label, country, time];
}
async setFilterObj() {
for (const type_dic of this.classes.slice(0, 4)) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let url = this.siteUrl + `${type_id}/all/all/all`
let $ = await this.getHtml(url)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
parseVodShortFromtJson(obj) {
let vodShort = new VodShort()
vodShort.vod_id = obj["id"]
vodShort.vod_name = obj["name"]
vodShort.vod_pic = obj["img"]
if (_.isEmpty(vodShort.vod_pic)) {
vodShort.vod_pic = obj["picurl"] ?? ""
}
vodShort.vod_remarks = obj["countStr"]
if (_.isEmpty(vodShort.vod_remarks)) {
vodShort.vod_remarks = obj["time"]
}
return vodShort
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const results of obj) {
let name = results["name"]
if (name !== "电视直播") {
let cards = results["cards"]
for (const result of cards) {
let vodShort = this.parseVodShortFromtJson(result)
vod_list.push(vodShort)
}
}
}
return vod_list
}
async parseVodShortListFromJsonByCategory(obj) {
let vod_list = []
for (const result of obj.list) {
let vodShort = this.parseVodShortFromtJson(result)
vod_list.push(vodShort)
}
return vod_list
}
getObjectValues(objList,key){
let value_list = []
for (const result of objList){
value_list.push(result[key])
}
return value_list
}
async parseVodDetailfromJson(obj) {
const vObj = obj["collectionInfo"];
let vodDetail = new VodDetail();
vodDetail.vod_name = vObj["name"]
vodDetail.type_name = vObj["chname"]
vodDetail.vod_pic = vObj["picurl"]
vodDetail.vod_area = vObj["country"]
vodDetail.vod_remarks = vObj["countStr"]
vodDetail.vod_actor = this.getObjectValues(vObj["actor"],"name").join("/")
vodDetail.vod_director = this.getObjectValues(vObj["director"],"name").join("/")
vodDetail.vod_content = vObj["desc"]
const playInfo = vObj["videosGroup"];
const playVod = {};
_.each(playInfo, (info) => {
const sourceName = info.name;
let playList = '';
const videoInfo = info["videos"];
const vodItems = _.map(videoInfo, (epObj) => {
const epName = "第" + epObj["eporder"] + "集";
const playUrl = epObj["purl"]
return epName + '$' + playUrl;
});
if (_.isEmpty(vodItems)) return;
playList = vodItems.join('#');
playVod[sourceName] = playList;
});
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
return vodDetail
}
async setHomeVod() {
let json = await this.fetch(this.apiUrl + "/v3/web/api/home?chName=首页", null, this.getApiHeader())
const obj = JSON.parse(json)["data"]["cardsGroup"];
this.homeVodList = await this.parseVodShortListFromJson(obj)
}
getClassChName(tid) {
for (const class_dic of this.classes) {
if (tid === class_dic["type_id"]) {
return class_dic["type_name"]
}
}
}
async setCategory(tid, pg, filter, extend) {
this.limit = 16;
const param = {
chName: this.getClassChName(tid), page: parseInt(pg), pageSize: this.limit
};
if (extend["label"] !== undefined) {
param["label"] = extend["label"]
}
if (extend["country"] !== undefined) {
param["country"] = extend["country"]
}
if (extend["time"] !== undefined) {
const year = parseInt(extend["time"]);
param["startTime"] = year;
param["endTime"] = year;
}
const json = await this.post(this.apiUrl + '/v3/web/api/filter', JSON.stringify(param), {
'User-Agent': Utils.MOBILEUA, "Content-Type": 'application/json'
}, "")
const data = JSON.parse(json).data;
this.vodList = await this.parseVodShortListFromJsonByCategory(data)
this.count = Math.floor(data["total"] / this.limit);
this.total = data.total
}
async setDetail(id) {
const $ = await this.getHtml(this.siteUrl + '/vod/detail/' + id);
const json = $('#__NEXT_DATA__')[0].children[0].data;
const obj = JSON.parse(json).props["pageProps"];
this.vodDetail = await this.parseVodDetailfromJson(obj)
}
async setSearch(wd, quick) {
const limit = 20;
const param = {
word: wd, page: 1, pageSize: limit,
};
const json = await this.post(this.apiUrl + '/v3/web/api/search', JSON.stringify(param), this.getApiHeader(), "");
const data = JSON.parse(json).data;
this.vodList = await this.parseVodShortListFromJsonByCategory(data)
}
}
let spider = new StarSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,117 +0,0 @@
import {__jsEvalReturn} from './wogg.js';
import * as Utils from "../lib/utils.js";
let spider = __jsEvalReturn();
async function testPlay(vodDetail) {
if (vodDetail.list && vodDetail.list.length > 0) {
const pFlag = vodDetail.list[0].vod_play_from.split('$$$');
const pUrls = vodDetail.list[0].vod_play_url.split('$$$');
if (pFlag.length > 0 && pUrls.length > 0) {
for (const i in pFlag) {
// console.debug(i)
let flag = pFlag[i];
let urls = pUrls[i].split('#');
// console.debug(flag, urls)
for (const j in urls) {
var name = urls[j].split('$')[0];
var url = urls[j].split('$')[1];
console.debug(flag + " | " + name + " | " + url);
var playUrl = await spider.play(flag, url, []);
console.debug('playURL: ' + playUrl);
}
}
}
}
}
async function testMusicPlay(vodDetail) {
if (vodDetail.list && vodDetail.list.length > 0) {
const pFlag = vodDetail.list[0].volumes.split('$$$');
const pUrls = vodDetail.list[0].urls.split('$$$');
if (pFlag.length > 0 && pUrls.length > 0) {
for (const i in pFlag) {
// console.debug(i)
let flag = pFlag[i];
let urls = pUrls[i].split('#');
// console.debug(flag, urls)
for (const j in urls) {
var name = urls[j].split('$')[0];
var url = urls[j].split('$')[1];
console.debug(flag + " | " + name + " | " + url);
var playUrl = await spider.play(flag, url, []);
console.debug('playURL: ' + playUrl);
}
break
}
}
}
}
async function test() {
let siteKey = 'wogg';
let siteType = 3;
await spider.init({
skey: siteKey, stype: siteType, ext: {
"token": "51427b95ab9d47a6921a27951ebd3f1e",
"box": "TV",
"code": "1",
"from": "star",
"danmu": true,
"cookie": "buvid3=02675249-8ED3-C418-87F5-59E18316459714816infoc; b_nut=1704421014; _uuid=5D435F74-F574-D9AB-62C1-B9294DE465D913102infoc; buvid_fp=e8c5650c749398e9b5cad3f3ddb5081e; buvid4=007E85D1-52C1-7E6E-07CF-837FFBC9349516677-024010502-J5vTDSZDCw4fNnXRejbSVg%3D%3D; rpdid=|()kYJmulRu0J'u~|RRJl)JR; PVID=1; SESSDATA=3be091d3%2C1720332009%2C699ed%2A11CjAcCdwXG5kY1umhCOpQHOn_WP7L9xFBfWO7KKd4BPweodpR6VyIfeNyPiRmkr5jCqsSVjg0R0dZOVVHRUo3RnhPRTZFc3JPbGdiUjFCdHpiRDhiTkticmdKTjVyS1VhbDdvNjFMSDJlbUJydUlRdjFUNGFBNkJlV2ZTa0N1Q1BEVi1QYTQzTUh3IIEC; bili_jct=b0ee7b5d3f27df893545d811d95506d4; DedeUserID=78014638; DedeUserID__ckMd5=4c8c5d65065e468a; enable_web_push=DISABLE; header_theme_version=CLOSE; home_feed_column=5; CURRENT_BLACKGAP=0; CURRENT_FNVAL=4048; b_lsid=75E916AA_18EA1A8D995; bsource=search_baidu; FEED_LIVE_VERSION=V_HEADER_LIVE_NO_POP; browser_resolution=1507-691; bili_ticket=eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTIzNjk5MTMsImlhdCI6MTcxMjExMDY1MywicGx0IjotMX0.8zQW_fNTCSBlK_JkHnzu3gDw62wuTK1qgKcbGec3swM; bili_ticket_expires=171236985"
}
});
let classes = JSON.parse(await spider.home(true));
console.debug(JSON.stringify(classes))
// 测试搜索
let search_page = JSON.parse(await spider.search("甄嬛传", false, 1))
console.debug(JSON.stringify(search_page))
//测试首页列表
let homeVod = JSON.parse(await spider.homeVod())
console.debug(JSON.stringify(homeVod));
// 测试详情
let detail1 = JSON.parse(await spider.detail("1872"))
await testPlay(detail1)
// 测试分类
let catePage = JSON.parse(await spider.category("2", "1", undefined, {}));
console.debug(JSON.stringify(catePage))
// 测试详情
if (search_page.list && search_page.list.length > 0) {
for (const k in search_page.list) {
// console.debug(k)
if (k >= 1) break;
let obj = search_page.list[k]
let spVid = search_page.list[k].vod_id
console.debug("===", spVid)
var detail = JSON.parse(await spider.detail(spVid || search_page.list[k].vod_id));
await testPlay(detail);
}
}
}
export {test};

View File

@ -1,286 +0,0 @@
/*
* @File : tiantian.js
* @Author : jade
* @Date : 2024/04/15 10:48
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 天天影视
*/
import {Spider} from "./spider.js";
import {_} from "../lib/cat.js";
import * as Utils from "../lib/utils.js";
import {VodDetail, VodShort} from "../lib/vod.js";
class TianTianSpider extends Spider {
constructor() {
super();
this.siteUrl = "http://op.ysdqjs.cn"
this.cookie = ""
this.extendObj = {"extend": "类型", "area": "地区", "year": "年代"}
this.parseMap = {};
}
async request(reqUrl, method, data) {
const headers = {
'User-Agent': Utils.CHROME,
};
if (!_.isEmpty(this.cookie)) {
headers['Cookie'] = this.cookie;
}
const postType = method === 'post' ? 'form-data' : '';
let res = await req(reqUrl, {
method: method || 'get', headers: headers, data: data, postType: postType,
});
if (res.code === 403) {
const path = res.data.match(/window\.location\.href ="(.*?)"/)[1];
this.cookie = _.isArray(res.headers['set-cookie']) ? res.headers['set-cookie'].join(';') : res.headers['set-cookie'];
headers['Cookie'] = this.cookie;
res = await req(this.siteUrl + path, {
method: method || 'get', headers: headers, data: data, postType: postType,
});
}
return res.content;
}
async postData(url, data) {
const timestamp = Math.floor(new Date().getTime() / 1000);
const key = 'kj5649ertj84ks89r4jh8s45hf84hjfds04k';
const sign = md5X(key + timestamp).toString();
let defaultData = {
sign: sign, timestamp: timestamp,
};
const reqData = data ? _.merge(defaultData, data) : defaultData;
return await this.request(url, 'post', reqData);
}
getName() {
return "⛄┃天天影视┃⛄"
}
getAppName() {
return "天天影视"
}
getJSName() {
return "tiantian"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
}
generateParam(tid, pg, extend, limit) {
const param = {
type_id: tid, page: pg, limit: limit,
};
if (extend["extend"] !== undefined && extend["extend"] !== "全部") {
param.class = extend["extend"];
}
if (extend["area"] !== undefined && extend["area"] !== "全部") {
param.area = extend.area;
}
if (extend["lang"] !== undefined && extend["lang"] !== "全部") {
param.lang = extend.lang;
}
if (extend["year"] !== undefined && extend["year"] !== "全部") {
param.year = extend.year;
}
return param;
}
async getFilter(data) {
let extend_list = []
Object.keys(data).forEach(key => {
if (Array.isArray(data[key])) {
if (!_.isEmpty(this.extendObj[key])) {
let extend_dic = {"key": key, "name": this.extendObj[key], "value": []}
let add_year_status = false
for (const extend_data of data[key]) {
if (key === "year") {
if (!data[key].includes("2024") && extend_data !== "全部" && !add_year_status) {
extend_dic["value"].push({"n": "2024", "v": "2024"})
add_year_status = true
}
}
if (!_.isEmpty(extend_data)) {
extend_dic["value"].push({"n": extend_data, "v": extend_data})
}
}
if (extend_dic["value"].length > 1) {
extend_list.push(extend_dic)
}
}
}
})
return extend_list
}
async setClasses() {
let resJson = JSON.parse(await this.postData(this.siteUrl + '/v2/type/top_type'))
for (const data of resJson["data"]["list"]) {
let type_name = data["type_name"]
let type_id = data["type_id"].toString()
this.classes.push(this.getTypeDic(type_name, type_id))
this.filterObj[type_id] = await this.getFilter(data)
}
}
async parseVodShortListFromJson(vodList) {
let vod_list = []
for (const vodData of vodList) {
let vodShort = new VodShort()
vodShort.load_data(vodData)
if (_.isEmpty(vodShort.vod_pic) && vodData["vod_pic_thumb"] !== undefined) {
vodShort.vod_pic = vodData["vod_pic_thumb"]
}
if (vodShort.vod_name !== "首页轮播") {
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailfromJson(detailObj) {
let vodDetail = new VodDetail()
vodDetail.load_data(detailObj)
vodDetail.vod_content = Utils.formatContent(vodDetail.vod_content)
const playInfo = detailObj["vod_play_list"];
const playVod = {};
_.each(playInfo, (obj) => {
const sourceName = obj.name;
let playList = '';
const videoInfo = obj.urls;
const parse = obj["parse_urls"];
if (!_.isEmpty(parse)) this.parseMap[sourceName] = parse;
const vodItems = _.map(videoInfo, (epObj) => {
const epName = epObj.name;
const playUrl = epObj.url;
return epName + '$' + playUrl;
});
if (_.isEmpty(vodItems)) return;
playList = vodItems.join('#');
playVod[sourceName] = playList;
});
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
return vodDetail
}
async setHomeVod() {
let resJson = JSON.parse(await this.postData(this.siteUrl + '/v2/type/tj_vod'))
let vod_list = []
for (const data of resJson["data"]["type_vod"]) {
if (data["type_name"] !== "广告") {
vod_list = await this.parseVodShortListFromJson(data["vod"])
this.homeVodList = [...this.homeVodList, ...vod_list]
}
}
vod_list = await this.parseVodShortListFromJson(resJson["data"]["loop"])
this.homeVodList = [...this.homeVodList, ...vod_list]
vod_list = await this.parseVodShortListFromJson(resJson["data"]["cai"])
this.homeVodList = [...this.homeVodList, ...vod_list]
}
async setCategory(tid, pg, filter, extend) {
const limit = 12;
const param = this.generateParam(tid, pg, extend, limit);
const resJson = JSON.parse(await this.postData(this.siteUrl + '/v2/home/type_search', param));
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["list"])
}
async setDetail(id) {
const param = {
vod_id: id,
}
const resJson = JSON.parse(await this.postData(this.siteUrl + '/v2/home/vod_details', param));
this.vodDetail = await this.parseVodDetailfromJson(resJson["data"])
}
async setPlay(flag, id, flags) {
const parsers = this.parseMap[flag];
if (flag.indexOf("芒果") > -1 || flag.indexOf("腾讯") > -1 || flag.indexOf("爱奇艺") > -1) {
if (!this.catOpenStatus) {
this.danmuUrl = await this.danmuSpider.downloadDanmu("https://dmku.thefilehosting.com/?ac=dm&url=" + id)
}
}
if (!_.isEmpty(parsers)) {
for (const parser of parsers) {
if (_.isEmpty(parser)) continue;
try {
const resp = await this.request(parser + id);
const json = JSON.parse(resp);
if (!_.isEmpty(json.url)) {
this.playUrl = json.url;
break;
}
} catch (e) {
}
}
}
}
async setSearch(wd, quick, pg) {
const limit = 12;
const param = {
keyword: wd, page: pg, limit: limit,
};
const resJson = JSON.parse(await this.postData(this.siteUrl + '/v2/home/search', param));
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["list"])
const page = parseInt(pg);
let pageCount = page;
if (this.vodList.length === limit) {
pageCount = page + 1;
}
this.result.setPage(page, pageCount, limit, pageCount)
}
}
let spider = new TianTianSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider, TianTianSpider}

View File

@ -1,343 +0,0 @@
/*
* @File : ttkan.js
* @Author : jade
* @Date : 2024/5/10 9:59
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {BookDetail, BookShort} from "../lib/book.js";
class TTKanSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://cn.ttkan.co"
this.apiUrl = "https://cn.ttkan.co/api"
}
getAppName() {
return "天天看小说"
}
getJSName() {
return "ttkan"
}
getType() {
return 10
}
getName() {
return "📚︎┃天天看小说┃📚︎"
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
parseVodShortFromElement($, element) {
let bookShort = new BookShort()
let bookShortElements = $(element).find("a")
bookShort.book_name = bookShortElements[0].attribs["aria-label"]
bookShort.book_id = bookShortElements[0].attribs.href
if ($(element).find("amp-img").length > 0) {
bookShort.book_pic = $(element).find("amp-img")[0].attribs["src"].split("?")[0]
}
bookShort.book_remarks = $($(element).find("p")[0]).text()
return bookShort
}
async parseVodShortListFromDoc($) {
let books = []
let bookElements = $("[class=\"frame_body\"]").find("[class=\"pure-g\"]").slice(-1)[0]
for (const bookElement of bookElements.children) {
let bookShort = this.parseVodShortFromElement($, $(bookElement).find("li")[0])
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocByCategory($) {
let bookImgElements = $("[class=\"pure-u-xl-1-5 pure-u-lg-1-4 pure-u-md-1-3 pure-u-sm-1-3 pure-u-13-24\"]")
let bookMsgElements = $("[class=\"pure-u-xl-4-5 pure-u-lg-3-4 pure-u-md-2-3 pure-u-sm-2-3 pure-u-11-24\"]")
let books = [];
for (let i = 0; i < bookImgElements.length; i++) {
let bookShort = new BookShort()
let imgElement = bookImgElements[i]
let msgElement = bookMsgElements[i]
let element = $(imgElement).find('a')[0]
bookShort.book_id = element.attribs.href;
const img = $(imgElement).find('amp-img')[0];
bookShort.book_name = $(element).text()
bookShort.book_pic = img.attribs["src"].split("?")[0]
bookShort.book_name = img.attribs["alt"]
bookShort.book_remarks = $($(msgElement).find('li').slice(-1)).text().replaceAll("状态:","");
books.push(bookShort)
}
return books
}
async parseVodShortListFromJson(obj) {
let books = [];
for (const data of obj) {
let bookShort = new BookShort()
bookShort.book_id = "/novel/chapters/" + data["novel_id"]
bookShort.book_name = data["name"]
bookShort.book_remarks = "作者:" + data.author
bookShort.book_pic = "https://static.ttkan.co/cover/" + data["topic_img"]
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocBySearch($) {
let books = []
let bookElements = $("[class=\"frame_body\"]").find("[class=\"pure-g\"]").slice(-1)[0]
for (const bookElement of bookElements.children) {
let bookShort = new BookShort()
bookShort.book_id = $(bookElement).find("a")[0].attribs.href
bookShort.book_name = $($(bookElement).find("li")[0]).text()
bookShort.book_remarks = $($(bookElement).find("li")[1]).text()
bookShort.book_pic = $(bookElement).find("amp-img")[0].attribs.src.split("?")[0]
books.push(bookShort)
}
return books
}
async parseVodDetailFromDoc($, id) {
let html = $.html()
let bookDetail = new BookDetail()
let infoElement = $("[class=\"pure-g novel_info\"]")
bookDetail.book_pic = $(infoElement).find("amp-img")[0].attribs.src.split("?")[0]
let elements = $(infoElement).find("[class=\"pure-u-xl-5-6 pure-u-lg-5-6 pure-u-md-2-3 pure-u-1-2\"]").find("li")
bookDetail.book_name = $(elements[0]).text()
bookDetail.book_director = $(elements[1]).text().replaceAll("作者:","")
bookDetail.book_remarks = $(elements[3]).text().replaceAll("状态:","")
bookDetail.book_year= $("[class=\"near_chapter\"]").find("time")[0].attribs.datetime.replaceAll("T"," ").split(".")[0]
bookDetail.book_content = $($('[class="description"]')).text().trim()
bookDetail.book_id = id
const playBook = {};
const nearElement = $('[class="near_chapter"]').find("a")[0]
let nearVodItems = []
const epName = $(nearElement).text();
const page = nearElement.attribs.href.split("&page=").slice(-1)[0]
const playUrl = epName + "+" + `${id.replaceAll("/novel/chapters/","")}_${page}.html` ;
nearVodItems.push(epName + '$' + playUrl)
const lastestElements = $('[class="chapters_frame"]').find("a")
for (const lastestElement of lastestElements){
const epName = $(lastestElement).text();
const page = lastestElement.attribs.href.split("&page=").slice(-1)[0]
const playUrl = epName + "+" + `${id.replaceAll("/novel/chapters/","")}_${page}.html` ;
nearVodItems.push(epName + '$' + playUrl)
}
playBook["最近章节"] = nearVodItems.reverse().join("#")
let params = {"language":"cn","novel_id":id.replaceAll("/novel/chapters/",""),"__amp_source_origin":encodeURIComponent(this.siteUrl)}
let resJSon = JSON.parse(await this.fetch(this.apiUrl + "/nq/amp_novel_chapters" ,params,this.getHeader()))
let allVodItems = []
for (const data of resJSon["items"]){
const epName = data.chapter_name;
const playUrl = epName + "+" + `${id.replaceAll("/novel/chapters/","")}_${data.chapter_id}.html` ;
allVodItems.push(epName + '$' + playUrl)
}
playBook["目录"] = allVodItems.join("#")
bookDetail.volumes = _.keys(playBook).join('$$$');
bookDetail.urls = _.values(playBook).join('$$$');
return bookDetail
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $('div.novel_class_nav > a')
for (const element of navElements) {
let type_id = element.attribs.href
let type_name = $(element).text()
this.classes.push(this.getTypeDic(type_name, type_id));
}
}
async getFilter($) {
let extend_list = []
let extend_dic = {"name": "排序", "key": "sort", "value": []}
let elements = $('div.rank_nav > a')
let sortList = []
let isNewSort = false
if (elements.length === 0) {
elements = $('div.nav_filter_inner > a')
isNewSort = true
}
for (const element of elements) {
let type_name = $(element).text()
let type_id = element.attribs.href
sortList.push(this.getFliterDic(type_name, type_id))
}
if (isNewSort) {
const lastItem = sortList.splice(-1, 1);
sortList = lastItem.concat(sortList);
}
extend_dic["value"] = sortList
extend_list.push(extend_dic)
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let $ = await this.getHtml(this.siteUrl + type_id)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($, id)
}
getExtend(extend) {
if (extend["sort"] === undefined) {
return "*"
}
if (extend["sort"] === "全部") {
return "*"
} else {
let value = extend["sort"].replaceAll("/novel/", "").replaceAll("class/", "")
if (value.indexOf("_") > -1){
return value.split("_").slice(-1)[0]
}else{
return value
}
}
}
async setCategory(tid, pg, filter, extend) {
if (tid === "/novel/rank") {
tid = extend["sort"] ?? tid
let $ = await this.getHtml(this.siteUrl + tid)
this.vodList = await this.parseVodShortListFromDocByCategory($)
let x = 0
} else {
let extendFilter = this.getExtend(extend)
let limit = 18
let params = {
"language": "cn",
"limit": limit,
"type": tid.replaceAll("/novel/", "").replaceAll("class/", ""),
"filter": extendFilter,
"page": parseInt(pg),
"__amp_source_origin": encodeURIComponent(this.siteUrl)
}
let resJson = JSON.parse(await this.fetch(this.apiUrl + "/nq/amp_novel_list", params, this.getHeader()))
this.vodList = await this.parseVodShortListFromJson(resJson["items"])
}
}
async setPlay(flag, id, flags) {
let id_list = id.split("-")
id = id_list[1]
let content = id_list[0] + "\n\n"
while (true) {
let $ = await this.getHtml(this.siteUrl + id)
content += Utils.formatContent($("[class=\"content\"]").html().trim().replaceAll("<p>", " ").replaceAll("</p>", "\n"));
id = $("[id=\"next_url\"]")[0].attribs.href;
if (id.indexOf('_') < 0) break;
}
this.playUrl = {"content": content}
}
async setSearch(wd, quick) {
let params = {"q":encodeURIComponent(wd)}
let content = await this.fetch(this.siteUrl + "/novel/search", params, this.getHeader())
let $ = load(content)
this.vodList = await this.parseVodShortListFromDocBySearch($)
let x = 0
}
async setPlay(flag, id, flags) {
let id_list = id.split("+")
id = id_list[1]
let content = id_list[0] + "\n\n"
let $ = await this.getHtml(this.siteUrl + "/novel/pagea/" + id)
let bookContentList = $('[class="content"]').text().trim().replaceAll("章节报错 分享给朋友:","").replaceAll(" ","").split("\n")
let newBookContentList = []
for (const bookContent of bookContentList){
if (!_.isEmpty(bookContent.replaceAll(" ",""))){
newBookContentList.push(bookContent.replaceAll(" "," "))
}
}
content = content + " " + newBookContentList.join("\n\n")
this.playUrl = {"content": content}
}
}
let spider = new TTKanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,192 +0,0 @@
/*
* @File : vodSpider.js
* @Author : jade
* @Date : 2024/2/6 16:53
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class VodSpider extends Spider {
constructor() {
super();
this.siteUrl = "http://cj.ffzyapi.com"
this.remove18 = false
this.type_id_18 = 34
}
async spiderInit(inReq) {
if (inReq !== null) {
this.detailProxy = await js2Proxy(inReq, "detail", this.getHeader());
} else {
this.detailProxy = await js2Proxy(true, this.siteType, this.siteKey, 'detail/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
async parseVodShortListFromJson(obj, isSearch = false) {
let vod_list = []
let vodShort;
for (const vod_data of obj["list"]) {
if (!isSearch) {
vodShort = this.parseVodDetail(vod_data)
} else {
vodShort = new VodShort();
vodShort.vod_pic = this.detailProxy + Utils.base64Encode(vod_data["vod_id"])
vodShort.vod_id = vod_data["vod_id"]
vodShort.vod_name = vod_data["vod_name"]
vodShort.vod_remarks = vod_data["vod_remarks"]
}
if (this.remove18 && vod_data["type_id"] !== this.type_id_18) {
vod_list.push(vodShort)
}
if (!this.remove18 && vod_data["type_id"] === this.type_id_18) {
vod_list.push(vodShort)
}
}
return vod_list
}
parseVodDetail(vod_data) {
let vodDetail = new VodDetail()
vodDetail.vod_id = vod_data["vod_id"]
vodDetail.vod_name = vod_data["vod_name"]
vodDetail.vod_pic = vod_data["vod_pic"]
vodDetail.vod_remarks = vod_data["vod_remarks"]
vodDetail.vod_area = vod_data["vod_area"]
vodDetail.vod_year = vod_data["vod_year"]
vodDetail.vod_actor = vod_data["vod_actor"]
vodDetail.vod_director = vod_data["vod_director"]
let $ = load(vod_data['vod_content'])
vodDetail.vod_content = $.text()
if (vod_data["vod_down_url"] !== undefined) {
if (vod_data["vod_down_url"].length > 0) {
vodDetail.vod_play_from = "直链播放$$$"
vodDetail.vod_play_url = vod_data["vod_down_url"] + "$$$"
}
}
vodDetail.vod_play_from = vodDetail.vod_play_from + vod_data["vod_play_from"]
vodDetail.vod_play_url = vodDetail.vod_play_url + vod_data["vod_play_url"]
vodDetail.type_name = vod_data["type_name"]
return vodDetail
}
async parseVodDetailfromJson(obj) {
let vodDetail;
let vod_data_list = obj["list"]
if (vod_data_list.length > 0) {
let vod_data = vod_data_list[0]
vodDetail = this.parseVodDetail(vod_data)
}
return vodDetail
}
async setClasses() {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod/from", {"ac": "list"}, this.getHeader())
let content_json = JSON.parse(content)
for (const class_dic of content_json["class"]) {
if (class_dic["type_pid"] !== 0) {
this.classes.push(this.getTypeDic(class_dic["type_name"], class_dic["type_id"]))
}
}
}
async setFilterObj() {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod/from", {"ac": "list"}, this.getHeader())
let content_json = JSON.parse(content)
for (const root_class_dic of this.classes) {
let type_id = root_class_dic["type_id"].toString()
if (type_id !== "最近更新") {
let extend_dic = {"key": "1", "name": "分类", "value": [{"n": "全部", "v": type_id}]}
for (const class_dic of content_json["class"]) {
let type_name = class_dic["type_name"]
if (type_name === this.type_name_18) {
this.type_id_18 = class_dic["type_id"].toString()
}
if (this.remove18) {
if (class_dic["type_pid"] === root_class_dic["type_id"] && type_name !== this.type_name_18) {
extend_dic["value"].push({"n": type_name, "v": class_dic["type_id"].toString()})
}
} else {
if (class_dic["type_pid"] === root_class_dic["type_id"] && type_name === this.type_name_18) {
extend_dic["value"].push({"n": type_name, "v": class_dic["type_id"].toString()})
}
}
}
if (!this.remove18) {
this.classes = [this.getTypeDic("最近更新", "最近更新"), this.getTypeDic(this.type_name_18, this.type_id_18)]
} else {
this.filterObj[type_id] = [extend_dic]
}
}
}
}
async setHomeVod() {
let content = await this.fetch(this.siteUrl + "/index.php/ajax/data", {
"mid": "1"
}, this.getHeader())
this.homeVodList = await this.parseVodShortListFromJson(JSON.parse(content))
}
async setDetail(id) {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod", {
"ac": "detail", "ids": id
}, this.getHeader())
this.vodDetail = await this.parseVodDetailfromJson(JSON.parse(content))
}
async setCategory(tid, pg, filter, extend) {
tid = extend["1"] ?? tid
let url = this.siteUrl + `/index.php/ajax/data?mid=1&tid=${tid}&page=${pg}&limit=20`
await this.jadeLog.debug(`分类URL:${url}`)
let content = await this.fetch(url, null, this.getHeader())
await this.jadeLog.debug(`分类内容为:${content}`)
this.vodList = await this.parseVodShortListFromJson(JSON.parse(content))
}
async setSearch(wd, quick) {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod/", {"wd": wd}, this.getHeader())
this.vodList = await this.parseVodShortListFromJson(JSON.parse(content), true)
}
async proxy(segments, headers) {
await this.jadeLog.debug(`正在设置反向代理 segments = ${segments.join(",")},headers = ${JSON.stringify(headers)}`)
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
await this.jadeLog.debug(`反向代理参数为:${url}`)
if (what === 'detail') {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod", {
"ac": "detail", "ids": url
}, this.getHeader())
let vod_detail = await this.parseVodDetailfromJson(JSON.parse(content))
let pic_content = await this.fetch(vod_detail.vod_pic, null, this.getHeader(), false, false, 2)
if (!_.isEmpty(pic_content)) {
return JSON.stringify({
code: 200, buffer: 2, content: pic_content, headers: {},
});
} else {
return JSON.stringify({
code: 500, buffer: 2, content: "", headers: {},
});
}
}
}
}
export {VodSpider}

View File

@ -1,322 +0,0 @@
/*
* @Author: samples jadehh@live.com
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples jadehh@live.com
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: js/weixine.js
* @Description: 阿里影视(已失效)
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import {detailContent, initAli, playContent} from "../lib/ali.js";
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class WeiXineSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://www.weixine.link';
}
async init(cfg) {
await super.init(cfg);
await initAli(this.cfgObj["token"]);
}
getName() {
return `💂‍┃阿里影视┃💂`
}
getAppName() {
return "阿里影视"
}
getJSName() {
return "weixine"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let items = $('.module-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
let oneA = $(item).find('.module-item-cover .module-item-pic a').first();
vodShort.vod_id = oneA.attr('href');
vodShort.vod_name = oneA.attr('title');
vodShort.vod_pic = $(item).find('.module-item-cover .module-item-pic img').first().attr('data-src');
if (vodShort.vod_pic.indexOf("img.php?url=") > 0) {
vodShort.vod_pic = vodShort.vod_pic.split("img.php?url=")[1]
}
vodShort.vod_remarks = $(item).find('.module-item-text').first().text();
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
vodDetail.vod_name = $('.page-title')[0].children[0].data
vodDetail.vod_pic = $($(".mobile-play")).find(".lazyload")[0].attribs["data-src"]
let video_info_aux_list = $($(".video-info-aux")).find(".tag-link")[1].children
for (const video_info_aux of video_info_aux_list) {
try {
vodDetail.type_name = vodDetail.type_name + video_info_aux.children[0].data
} catch {
}
}
let video_items = $('.video-info-items')
vodDetail.vod_director = $(video_items[0]).find("a")[0].children[0].data
let vidoe_info_actor_list = $(video_items[1]).find("a")
let actor_list = []
for (const video_info_actor of vidoe_info_actor_list) {
if (video_info_actor.children.length > 0) {
actor_list.push(video_info_actor.children[0].data)
}
}
vodDetail.vod_actor = actor_list.join(" * ")
vodDetail.vod_year = $(video_items[2]).find("a")[0].children[0].data
vodDetail.vod_remarks = `清晰度:${$(video_items[3]).find("div")[0].children[0].data}, 制作人:Jade`
vodDetail.vod_content = $(video_items[4]).find("p")[0].children[0].data
vodDetail.vod_content = vodDetail.vod_content.replace("[收起部分]", "").replace("[展开全部]", "")
const share_url_list = [];
let items = $('.module-row-info')
for (const item of items) {
let aliUrl = $(item).find("p")[0].children[0].data
let matches = aliUrl.match(Utils.patternAli);
if (!_.isEmpty(matches)) share_url_list.push(matches[1])
}
if (share_url_list.length > 0) {
let aliVodDetail = await detailContent(share_url_list)
vodDetail.vod_play_url = aliVodDetail.vod_play_url
vodDetail.vod_play_from = aliVodDetail.vod_play_from
} else {
await this.jadeLog.warning(`获取详情界面失败,失败原因为:没有分享链接`)
}
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let items = $('.module-search-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
vodShort.vod_id = $(item).find(".video-serial")[0].attribs.href;
vodShort.vod_name = $(item).find(".video-serial")[0].attribs.title;
vodShort.vod_pic = $(item).find(".module-item-pic > img")[0].attribs['data-src'];
vodShort.vod_remarks = '';
vod_list.push(vodShort);
}
return vod_list
}
get_extend_sort_dic(tid) {
/***
tid为1,2,3的时候,电影,剧情,动漫
urlParams#0表示类别,1表示全部地区,2表示人气评分,3表示全部剧情,4表示全部语言,5表示字母查找,6表示页数,11表示时间
#key为1,代表全部剧情
#key为2,代表全部地区
#key为3,代表全部语言
#key为4,代表全部时间
#key为5,字幕查找
#key为6,时间排序
https://www.wogg.xyz/index.php/vodshow/1-全部地区-时间排序-全部剧情-全部语言-字幕查找------全部时间.html
tid为4,综艺
#key为1,代表全部地区
#key为2,代表全部时间
#key为3,字幕查找
#key为4,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/4-全部地区-时间排序---字母查找------全部时间.html
tid为5:音乐
#key为1,字幕查找
#key为2,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/5--时间排序---字幕查找------.html
tid为6,短剧
#key为1,代表全部剧情
#key为2,代表全部地区
#key为3,代表全部时间
#key为4,字幕查找
#key为5,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/6-全部地区-时间排序-全部剧情--字母查找------全部时间.html
*/
let extend_dic = {}
if (tid < 4) {
extend_dic = {
"1": 3, "2": 1, "3": 4, "4": 11, "5": 5, "6": 2
}
} else if (tid === 4) {
extend_dic = {
"1": 1, "2": 11, "3": 5, "4": 2,
}
} else if (tid === 6) {
extend_dic = {
"1": 3, "2": 1, "3": 11, "4": 5, "5": 2,
}
} else if (tid === 5) {
extend_dic = {
"1": 5, "2": 2,
}
}
return extend_dic
}
async setClasses() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
let elements = $('.nav-link')
for (const element of elements) {
let type_id = parseInt(element.attribs.href.split("/").slice(-1)[0].split(".html")[0])
let type_name = element.children.slice(-1)[0].data.replaceAll("\n", "").replaceAll(" ", "").replaceAll("玩偶", "").replaceAll("\t", "")
let type_dic = {"type_id": type_id, "type_name": type_name}
this.classes.push(type_dic)
}
}
}
async getFilter($) {
let elements = $("[class='scroll-content']").slice(1)
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": "", "value": []}
if (i < elements.length - 1) {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(elements[i]).find("a").slice(1)) {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
extend_list.push(extend_dic)
} else {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"] = [{"n": "全部", "v": "0"}, {
"n": $($(elements[i]).find("a")[1]).text(), "v": "hits"
}, {"n": $($(elements[i]).find("a")[2]).text(), "v": "score"}]
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "/" && type_id !== "最近更新") {
let url = this.siteUrl + `/index.php/vodshow/${type_id}--------1---.html`
let html = await this.fetch(url, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
}
async setHomeVod() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
async setCategory(tid, pg, filter, extend) {
let urlParams = [tid.toString(), "", "", "", "", "", "", "", pg.toString(), "", "", ""]
let extend_dic = this.get_extend_sort_dic(parseInt(tid))
for (const key of Object.keys(extend_dic)) {
if (extend[key] === "0") {
urlParams[extend_dic[key]] = ""
} else {
urlParams[extend_dic[key]] = extend[key]
}
}
let reqUrl = this.siteUrl + '/index.php/vodshow/' + urlParams.join("-") + '.html';
let html = await this.fetch(reqUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
let total = Utils.getStrByRegex(/\$\("\.mac_total"\)\.text\('(\d+)'\)/, html)
this.limit = 72;
if (total.length > 0) {
this.total = parseInt(total)
}
if (this.total <= this.limit) {
this.count = 1
} else {
this.count = Math.ceil(this.total / this.limit)
}
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id;
let html = await this.fetch(detailUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async play(flag, id, flags) {
return await playContent(flag, id, flags);
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + '/index.php/vodsearch/-------------.html?wd=' + wd;
let html = await this.fetch(searchUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
}
let spider = new WeiXineSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,319 +0,0 @@
/*
* @Author: samples jadehh@live.com
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples jadehh@live.com
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: js/wogg.js
* @Description: 玩偶哥哥爬虫类
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import {detailContent, initAli, playContent} from "../lib/ali.js";
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class WoggSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://www.wogg.net';
this.woggTypeObj = {"玩偶电影":"电影","玩偶剧集":"电视剧"}
}
async init(cfg) {
await super.init(cfg);
await initAli(this.cfgObj["token"]);
this.danmuStaus = true
}
getName() {
return "💂‍┃阿里玩偶┃💂"
}
getAppName() {
return "阿里玩偶"
}
getJSName() {
return "wogg"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let items = $('.module-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
let oneA = $(item).find('.module-item-cover .module-item-pic a').first();
vodShort.vod_id = oneA.attr('href');
vodShort.vod_name = oneA.attr('title');
vodShort.vod_pic = $(item).find('.module-item-cover .module-item-pic img').first().attr('data-src');
if (vodShort.vod_pic.indexOf("img.php?url=") > 0) {
vodShort.vod_pic = vodShort.vod_pic.split("img.php?url=")[1]
}
vodShort.vod_remarks = $(item).find('.module-item-text').first().text();
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
vodDetail.vod_name = $('.page-title')[0].children[0].data
vodDetail.vod_pic = $($(".mobile-play")).find(".lazyload")[0].attribs["data-src"]
vodDetail.type_name = this.woggTypeObj[$("[class=\"video-info-aux\"]").find("a")[0].attribs.title]
let video_items = $('.video-info-items')
vodDetail.vod_director = $(video_items[0]).find("a")[0].children[0].data
let vidoe_info_actor_list = $(video_items[1]).find("a")
let actor_list = []
for (const video_info_actor of vidoe_info_actor_list) {
if (video_info_actor.children.length > 0){
actor_list.push(video_info_actor.children[0].data)
}
}
vodDetail.vod_actor = actor_list.join(" * ")
vodDetail.vod_year = $(video_items[2]).find("a")[0].children[0].data
vodDetail.vod_remarks = `${$(video_items[3]).find("div")[0].children[0].data}, 制作人:Jade`
vodDetail.vod_content = $(video_items[4]).find("p")[0].children[0].data
vodDetail.vod_content = vodDetail.vod_content.replace("[收起部分]", "").replace("[展开全部]", "")
const share_url_list = [];
let items = $('.module-row-info')
for (const item of items) {
let aliUrl = $(item).find("p")[0].children[0].data
let matches = aliUrl.match(Utils.patternAli);
if (!_.isEmpty(matches)) share_url_list.push(matches[1])
}
if (share_url_list.length > 0) {
let aliVodDetail = await detailContent(share_url_list,vodDetail.type_name)
vodDetail.vod_play_url = aliVodDetail.vod_play_url
vodDetail.vod_play_from = aliVodDetail.vod_play_from
} else {
await this.jadeLog.warning(`获取详情界面失败,失败原因为:没有分享链接`)
}
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let items = $('.module-search-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
vodShort.vod_id = $(item).find(".video-serial")[0].attribs.href;
vodShort.vod_name = $(item).find(".video-serial")[0].attribs.title;
vodShort.vod_pic = $(item).find(".module-item-pic > img")[0].attribs['data-src'];
vodShort.vod_remarks = $($(item).find(".video-serial")[0]).text();
vod_list.push(vodShort);
}
return vod_list
}
get_extend_sort_dic(tid) {
/***
tid为1,2,3的时候,电影,剧情,动漫
urlParams#0表示类别,1表示全部地区,2表示人气评分,3表示全部剧情,4表示全部语言,5表示字母查找,6表示页数,11表示时间
#key为1,代表全部剧情
#key为2,代表全部地区
#key为3,代表全部语言
#key为4,代表全部时间
#key为5,字幕查找
#key为6,时间排序
https://www.wogg.xyz/index.php/vodshow/1-全部地区-时间排序-全部剧情-全部语言-字幕查找------全部时间.html
tid为4,综艺
#key为1,代表全部地区
#key为2,代表全部时间
#key为3,字幕查找
#key为4,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/4-全部地区-时间排序---字母查找------全部时间.html
tid为5:音乐
#key为1,字幕查找
#key为2,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/5--时间排序---字幕查找------.html
tid为6,短剧
#key为1,代表全部剧情
#key为2,代表全部地区
#key为3,代表全部时间
#key为4,字幕查找
#key为5,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/6-全部地区-时间排序-全部剧情--字母查找------全部时间.html
*/
let extend_dic = {}
if (tid < 4) {
extend_dic = {
"1": 3, "2": 1, "3": 4, "4": 11, "5": 5, "6": 2
}
} else if (tid === 4) {
extend_dic = {
"1": 1, "2": 11, "3": 5, "4": 2,
}
} else if (tid === 6) {
extend_dic = {
"1": 3, "2": 1, "3": 11, "4": 5, "5": 2,
}
} else if (tid === 5) {
extend_dic = {
"1": 5, "2": 2,
}
}
return extend_dic
}
async setClasses() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
let elements = $('.nav-link')
for (const element of elements) {
let type_id = parseInt(element.attribs.href.split("/").slice(-1)[0].split(".html")[0])
let type_name = element.children.slice(-1)[0].data.replace("\n", "").replace(" ", "").replace("玩偶", "")
let type_dic = {"type_id": type_id, "type_name": type_name}
this.classes.push(type_dic)
}
}
}
async getFilter($) {
let elements = $("[class='scroll-content']").slice(1)
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": "", "value": []}
if (i < elements.length - 1) {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(elements[i]).find("a").slice(1)) {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
extend_list.push(extend_dic)
} else {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"] = [{"n": "全部", "v": "0"}, {
"n": $($(elements[i]).find("a")[1]).text(),
"v": "hits"
}, {"n": $($(elements[i]).find("a")[2]).text(), "v": "score"}]
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "/" && type_id !== "最近更新") {
let url = this.siteUrl + `/index.php/vodshow/${type_id}--------1---.html`
let html = await this.fetch(url, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
}
async setHomeVod() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
async setCategory(tid, pg, filter, extend) {
let urlParams = [tid.toString(), "", "", "", "", "", "", "", pg.toString(), "", "", ""]
let extend_dic = this.get_extend_sort_dic(parseInt(tid))
for (const key of Object.keys(extend_dic)) {
if (extend[key] === "0") {
urlParams[extend_dic[key]] = ""
} else {
urlParams[extend_dic[key]] = extend[key]
}
}
let reqUrl = this.siteUrl + '/index.php/vodshow/' + urlParams.join("-") + '.html';
let html = await this.fetch(reqUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
let total = Utils.getStrByRegex(/\$\("\.mac_total"\)\.text\('(\d+)'\)/, html)
this.limit = 72;
if (total.length > 0) {
this.total = parseInt(total)
}
if (this.total <= this.limit) {
this.count = 1
} else {
this.count = Math.ceil(this.total / this.limit)
}
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id;
let html = await this.fetch(detailUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setPlay(flag, id, flags) {
let playObjStr = await playContent(flag, id, flags);
this.playUrl = JSON.parse(playObjStr)["url"]
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + '/index.php/vodsearch/-------------.html?wd=' + wd;
let html = await this.fetch(searchUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
}
let spider = new WoggSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,304 +0,0 @@
/*
* @File : xb6v.js
* @Author : jade
* @Date : 2023/12/26 10:13
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import * as Utils from "../lib/utils.js";
import {_, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
class Xb6vSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.xb6v.com";
}
getName() {
return "🧲┃磁力新6V┃🧲"
}
getAppName() {
return "磁力新6V"
}
getJSName() {
return "xb6v"
}
getType() {
return 3
}
async redirect(response) {
await this.jadeLog.debug(`重定向回复值为:${response.content}`)
let matcher = /<a HREF=(.*?)>/.exec(response.content)
if (matcher.length > 1) {
let new_url = this.siteUrl + "/e/search/" + matcher[1].replaceAll("\\", "").replaceAll("\"", "")
await this.jadeLog.info(`重定向url为:${new_url}`)
return await this.fetch(new_url, null, this.getHeader())
}
}
getActorOrDirector(pattern, str) {
return Utils.getStrByRegex(pattern, str)
.replace(/<br>/g, "")
.replace(/&nbsp;./g, "")
.replace(/&amp;/g, "")
.replace(/middot;/g, "・")
.replace(/     /g, ",")
.replace(/      /g, ",")
.replace(/ /g, "");
}
getDescription(pattern, str) {
return Utils.getStrByRegex(pattern, str)
.replace(/<\/?[^>]+>/g, "")
.replace(/\n/g, "")
.replace(/&amp;/g, "")
.replace(/middot;/g, "・")
.replace(/ldquo;/g, "【")
.replace(/rdquo;/g, "】")
.replace(/ /g, "");
}
async parseVodShortListFromDoc($) {
let items = $("#post_container .post_hover");
let vod_list = []
for (const item of items) {
let element = $(item).find("[class=zoom]")[0];
let vodShort = new VodShort()
vodShort.vod_id = element.attribs["href"];
vodShort.vod_name = element.attribs["title"].replaceAll(/<\\?[^>]+>/g, "");
vodShort.vod_pic = $(element).find("img")[0].attribs["src"];
vodShort.vod_remarks = $(item).find("[rel=\"category tag\"]").text().replaceAll("\n", "").replaceAll(" ", "");
vod_list.push(vodShort)
}
return vod_list;
}
async parseVodDetailFromDoc($) {
let sourceList = $("#post_content");
let play_form_list = []
let play_url_list = []
if (!this.catOpenStatus) {
let i = 0
let circuitName = "磁力线路";
for (const source of sourceList) {
let aList = $(source).find("table a")
let vodItems = []
for (const a of aList) {
let episodeUrl = a.attribs["href"]
let episodeName = a.children[0].data
if (!episodeUrl.toLowerCase().startsWith("magnet")) continue;
vodItems.push(episodeName + "$" + episodeUrl);
}
if (vodItems.length > 0) {
i++;
play_form_list.push(circuitName + i)
play_url_list.push(vodItems.join("#"))
}
}
}
let playSourceList = $($(".mainleft")).find("[class=\"widget box row\"]")
for (const source of playSourceList) {
let play_format = $(source).find("h3").text()
let vodItems = []
if (!_.isEmpty(play_format)) {
let urlSourceList = $(source).find("a")
for (const url_source of urlSourceList) {
vodItems.push(url_source.attribs["title"] + "$" + url_source.attribs["href"])
}
play_form_list.push(play_format)
play_url_list.push(vodItems.join("#"))
}
}
let partHTML = $(".context").html();
let vodDetail = new VodDetail();
vodDetail.vod_name = $(".article_container > h1").text();
vodDetail.vod_pic = $("#post_content img").attr("src");
vodDetail.type_name = Utils.getStrByRegex(/◎类  别 (.*?)<br>/, partHTML);
if (_.isEmpty(vodDetail.type_name)) vodDetail.type_name = $("[rel=\"category tag\"]").text();
vodDetail.vod_year = Utils.getStrByRegex(/◎年  代 (.*?)<br>/, partHTML);
if (_.isEmpty(vodDetail.vod_year)) vodDetail.vod_year = Utils.getStrByRegex(/首播:(.*?)<br>"/, partHTML);
vodDetail.vod_area = Utils.getStrByRegex(/◎产  地 (.*?)<br>/, partHTML);
if (_.isEmpty(vodDetail.vod_year)) vodDetail.vod_area = Utils.getStrByRegex(/地区:(.*?)<br>"/, partHTML);
vodDetail.vod_remarks = Utils.getStrByRegex(/◎上映日期 (.*?)<br>/, partHTML);
vodDetail.vod_actor = this.getActorOrDirector(/◎演  员 (.*?)<\/p>/, partHTML);
if (_.isEmpty(vodDetail.vod_actor)) vodDetail.vod_actor = this.getActorOrDirector(/◎主  演 (.*?)<\/p>/, partHTML);
if (_.isEmpty(vodDetail.vod_actor)) vodDetail.vod_actor = this.getActorOrDirector(/主演:(.*?)<br>/, partHTML);
vodDetail.vod_director = this.getActorOrDirector(/◎导  演 (.*?)<br>/, partHTML);
if (_.isEmpty(vodDetail.vod_director)) vodDetail.vod_director = this.getActorOrDirector(/导演:(.*?)<br>/, partHTML);
vodDetail.vod_content = this.getDescription(/◎简  介(.*?)<hr>/gi, partHTML);
if (_.isEmpty(vodDetail.vod_content)) vodDetail.vod_content = this.getDescription(/简介(.*?)<\/p>/gi, partHTML);
if (_.isEmpty(vodDetail.vod_content)) vodDetail.vod_content = this.getDescription(/◎简  介(.*?)<br>/gi, partHTML);
vodDetail.vod_play_from = play_form_list.join("$$$")
vodDetail.vod_play_url = play_url_list.join("$$$")
return vodDetail
}
async parseVodPlayFromDoc(flag, $) {
let play_url = ""
let html = $.html()
switch (flag) {
case "播放地址(无插件 极速播放)":
case "播放地址三":
play_url = $($(".video")).find("iframe")[0].attribs["src"] + "/index.m3u8"
break
case "播放地址(无需安装插件)":
let matchers2 = /url: '(.*?)',/gs.exec(html)
if (matchers2.length > 1) {
play_url = matchers2[1]
}
break
case "播放地址四":
let matchers4 = /source: "(.*?)",/gs.exec(html)
if (matchers4.length > 1) {
play_url = matchers4[1]
}
break
default:
await this.jadeLog.warning(`暂不支持当前格式,当前格式为:${flag}`)
break
}
return play_url
}
async setClasses() {
let html = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html);
let elements = $('#menus > li > a');
for (let i = 0; i < elements.length; i++) {
let element = elements[i]
if (i < 2 || i === elements.length - 1) continue;
let typeName = element.children[0].data;
let typeId = element.attribs["href"];
this.classes.push({"type_name": typeName, "type_id": typeId})
if (typeName === "电视剧") {
let values = [{"n": "不限", "v": ""}]
for (const a of $(element.next).find("a")) {
values.push({"n": a.children[0].data, "v": a.attribs["href"].replaceAll(typeId, "")})
}
this.filterObj[typeId] = [{
"key": "cateId", "name": "类型", "value": values
}]
}
}
}
}
async setHomeVod() {
let html = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html);
this.homeVodList = await this.parseVodShortListFromDoc($)
} else {
await this.jadeLog.info("首页类别解析失败", true)
}
}
async setCategory(tid, pg, filter, extend) {
let cateId = extend["cateId"] ?? "";
let cateUrl = this.siteUrl + tid + cateId;
this.page = parseInt(pg)
this.count = 0
this.limit = 18;
this.total = 0;
if (this.page !== 1) {
cateUrl += "index_" + pg + ".html";
}
let html = await this.fetch(cateUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html)
let href_elements = $(".pagination > a")
if (href_elements.length > 0) {
let href = href_elements.slice(-1)[0].attribs["href"];
let patternPageCount = /index_(.*?).html/
let matches = patternPageCount.exec(href)
this.count = parseInt(matches[1])
let items = $("#post_container .post_hover");
this.total = this.page === this.count ? (this.page - 1) * this.limit + items.length : this.count * this.limit;
}
this.vodList = await this.parseVodShortListFromDoc($)
}
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + "/e/search/index.php";
let params = {
"show": "title", "tempid": "1", "tbname": "article", "mid": "1", "dopost": "search", "keyboard": wd,
}
let html = await this.post(searchUrl, params, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id;
let html = await this.fetch(detailUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html);
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setPlay(flag, id, flags) {
if (id.toLowerCase().startsWith("magnet")) {
this.playUrl = id
} else {
let playUrl = this.siteUrl + id
let html = await this.fetch(playUrl, null, this.getHeader())
let $ = load(html)
this.playUrl = await this.parseVodPlayFromDoc(flag, $)
}
}
}
let spider = new Xb6vSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -1,268 +0,0 @@
/*
* @File : yiqikan.js
* @Author : jade
* @Date : 2024/3/19 18:45
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 一起看 (已失效)
*/
import * as Utils from "../lib/utils.js";
import {_, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
class YiQiKanSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.gquaxhce.com"
this.nextObj = {}
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true;
}
getRequestId() {
let strArr = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
let sb = "";
for (let i = 0; i < 32; i++) {
sb = sb + strArr[_.random(0, strArr.length)];
}
return sb.toString();
}
getName() {
return `🛫┃一起看┃🛫`
}
getAppName() {
return "一起看"
}
getJSName() {
return "yiqikan"
}
getType() {
return 3
}
getHeader() {
let headers = super.getHeader();
headers["Connection"] = "keep-alive"
headers["Host"] = "api.gquaxhce.com"
return headers
}
getParams(ob_params = null) {
let requestId = this.getRequestId()
let appid = "e6ddefe09e0349739874563459f56c54"
let reqDomain = "m.yqktv888.com"
let udid = Utils.getUUID();
let appKey = "3359de478f8d45638125e446a10ec541"
let params = {"appId": appid}
if (!_.isEmpty(ob_params)) {
for (const ob_key of Object.keys(ob_params)) {
if (!_.isEmpty(ob_params[ob_key]) && (ob_key === "epId" || ob_key === "nextCount" || ob_key === "nextVal" || ob_key === "queryValueJson" || ob_key === "keyword")) {
params[ob_key] = ob_params[ob_key]
}
}
}
params["reqDomain"] = reqDomain
params["requestId"] = requestId
params["udid"] = udid
if (!_.isEmpty(ob_params)) {
for (const ob_key of Object.keys(ob_params)) {
if (!_.isEmpty(ob_params[ob_key]) && (ob_key === "vodId" || ob_key === "vodResolution")) {
params[ob_key] = ob_params[ob_key]
}
}
}
params["appKey"] = appKey
params["sign"] = md5X(Utils.objectToStr(params))
delete params["appKey"]
return params
}
async setClasses() {
let response = JSON.parse(await this.post(this.siteUrl + "/v1/api/home/header", this.getParams(), this.getHeader(), "raw"))
for (const data of response["data"]["channelList"]) {
this.classes.push(this.getTypeDic(data["channelName"], data["channelId"]))
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const data of obj) {
let vodShort = new VodShort()
vodShort.vod_id = data["vodId"]
vodShort.vod_name = data["vodName"]
vodShort.vod_remarks = data["watchingCountDesc"]
vodShort.vod_pic = data["coverImg"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail()
vodDetail.vod_name = obj["vodName"]
vodDetail.vod_content = obj["intro"]
vodDetail.vod_area = obj["areaName"]
vodDetail.vod_year = obj["year"]
vodDetail.type_name = obj["channelName"]
vodDetail.vod_remarks = "评分:" + obj["score"].toString()
vodDetail.vod_pic = obj["coverImg"]
vodDetail.vod_actor = Utils.objToList(obj["actorList"], "vodWorkerName")
vodDetail.vod_director = Utils.objToList(obj["directorList"], "vodWorkerName")
let playlist = {}
for (const playDic of obj["playerList"]) {
let vodItems = []
for (const item of playDic["epList"]) {
let playId = item["epId"]
let playName = item["epName"]
vodItems.push(playName + "$" + playId)
}
playlist[playDic["playerName"]] = vodItems.join("#")
}
vodDetail.vod_play_url = _.values(playlist).join('$$$');
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
return vodDetail
}
async setHomeVod() {
let response = await this.post(this.siteUrl + "/v1/api/home/body", this.getParams(), this.getHeader(), "raw")
let resJson = JSON.parse(response)
if (resJson["result"]) {
this.homeVodList = await this.parseVodShortListFromJson(resJson["data"]["hotVodList"])
} else {
await this.jadeLog.error(`获取首页失败,失败原因为:${resJson["msg"]}`)
}
}
async setCategory(tid, pg, filter, extend) {
let url = this.siteUrl + "/v1/api/search/queryNow"
this.limit = 18
let ob_params = {}
if (!_.isEmpty(this.nextObj[tid])) {
ob_params["nextVal"] = this.nextObj[tid]
}
ob_params["nextCount"] = 18
ob_params["queryValueJson"] = JSON.stringify([{
"filerName": "channelId", "filerValue": tid.toString()
}]).replaceAll("\\\\", "")
let response = await this.post(url, this.getParams(ob_params), this.getHeader(), "raw")
let resJson = JSON.parse(response)
if (resJson["result"]) {
if (resJson["data"]["hasNext"]) {
this.nextObj[tid] = resJson["data"]["nextVal"]
}
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["items"])
} else {
await this.jadeLog.error(`获取分类失败,失败原因为:${resJson["msg"]}`)
}
}
async setDetail(id) {
let url = this.siteUrl + "/v1/api/vodInfo/detail"
let ob_params = {"vodId": id}
let response = await this.post(url, this.getParams(ob_params), this.getHeader(), "raw")
let resJson = JSON.parse(response)
if (resJson["result"]) {
this.vodDetail = await this.parseVodDetailfromJson(resJson["data"])
} else {
await this.jadeLog.error(`获取详情失败,失败原因为:${resJson["msg"]}`)
}
}
async setPlay(flag, id, flags) {
let url = this.siteUrl + "/v1/api/vodInfo/getEpDetail"
let ob_params = {"epId": id}
let ep_detail_response = await this.post(url, this.getParams(ob_params), this.getHeader(), "raw")
let ep_detail_resJson = JSON.parse(ep_detail_response)
let vodResolution = "1";
if (ep_detail_resJson["result"]) {
if (ep_detail_resJson["data"]["resolutionItems"].length > 0) {
vodResolution = ep_detail_resJson["data"]["resolutionItems"].slice(-1)[0]["vodResolution"].toString()
let playUrl = this.siteUrl + "/v1/api/vodInfo/getPlayUrl"
let play_params = {"epId": id, "vodResolution": vodResolution}
let play_response = await this.post(playUrl, this.getParams(play_params), this.getHeader(), "raw")
let play_resJson = JSON.parse(play_response)
if (play_resJson["result"]) {
this.playUrl = play_resJson["data"]
}else{
await this.jadeLog.error(`获取播放链接失败,失败原因为:${ep_detail_resJson["msg"]}`)
}
}
} else {
await this.jadeLog.error(`获取播放详情失败,失败原因为:${ep_detail_resJson["msg"]}`)
}
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/v1/api/search/search"
let ob_prams = {"nextCount":15,"nextVal":"","keyword":wd}
let esponse = await this.post(url, this.getParams(ob_prams), this.getHeader(), "raw")
let resJson = JSON.parse(esponse)
if (resJson["result"]) {
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["items"])
} else {
await this.jadeLog.error(`获取详情失败,失败原因为:${resJson["msg"]}`)
}
}
}
let spider = new YiQiKanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -1,14 +0,0 @@
{
"video": {
"sites": [
]
},
"read": {
"sites": [
]
},
"pan": {
"sites": [
]
}
}

View File

@ -1,374 +0,0 @@
{
"sites": [],
"ijk": [
{
"group": "软解码",
"options": [
{
"category": 4,
"name": "opensles",
"value": "0"
},
{
"category": 4,
"name": "overlay-format",
"value": "842225234"
},
{
"category": 4,
"name": "framedrop",
"value": "1"
},
{
"category": 4,
"name": "soundtouch",
"value": "1"
},
{
"category": 4,
"name": "start-on-prepared",
"value": "1"
},
{
"category": 1,
"name": "http-detect-range-support",
"value": "0"
},
{
"category": 1,
"name": "fflags",
"value": "fastseek"
},
{
"category": 2,
"name": "skip_loop_filter",
"value": "48"
},
{
"category": 4,
"name": "reconnect",
"value": "1"
},
{
"category": 4,
"name": "max-buffer-size",
"value": "5242880"
},
{
"category": 4,
"name": "enable-accurate-seek",
"value": "0"
},
{
"category": 4,
"name": "mediacodec",
"value": "0"
},
{
"category": 4,
"name": "mediacodec-auto-rotate",
"value": "0"
},
{
"category": 4,
"name": "mediacodec-handle-resolution-change",
"value": "0"
},
{
"category": 4,
"name": "mediacodec-hevc",
"value": "0"
},
{
"category": 1,
"name": "dns_cache_timeout",
"value": "600000000"
}
]
},
{
"group": "硬解码",
"options": [
{
"category": 4,
"name": "opensles",
"value": "0"
},
{
"category": 4,
"name": "overlay-format",
"value": "842225234"
},
{
"category": 4,
"name": "framedrop",
"value": "1"
},
{
"category": 4,
"name": "soundtouch",
"value": "1"
},
{
"category": 4,
"name": "start-on-prepared",
"value": "1"
},
{
"category": 1,
"name": "http-detect-range-support",
"value": "0"
},
{
"category": 1,
"name": "fflags",
"value": "fastseek"
},
{
"category": 2,
"name": "skip_loop_filter",
"value": "48"
},
{
"category": 4,
"name": "reconnect",
"value": "1"
},
{
"category": 4,
"name": "max-buffer-size",
"value": "5242880"
},
{
"category": 4,
"name": "enable-accurate-seek",
"value": "0"
},
{
"category": 4,
"name": "mediacodec",
"value": "1"
},
{
"category": 4,
"name": "mediacodec-auto-rotate",
"value": "1"
},
{
"category": 4,
"name": "mediacodec-handle-resolution-change",
"value": "1"
},
{
"category": 4,
"name": "mediacodec-hevc",
"value": "1"
},
{
"category": 1,
"name": "dns_cache_timeout",
"value": "600000000"
}
]
}
],
"ads": [
"wan.51img1.com",
"iqiyi.hbuioo.com",
"vip.ffzyad.com",
"https://lf1-cdn-tos.bytegoofy.com/obj/tos-cn-i-dy/455ccf9e8ae744378118e4bd289288dd",
"static-mozai.4gtv.tv",
"s3t3d2y8.afcdn.net",
"4gtvfreepcvod-cds.cdn.hinet.net"
],
"rules": [
{
"name": "星星",
"hosts": [
"aws.ulivetv.net"
],
"regex": [
"#EXT-X-DISCONTINUITY\\r*\\n*#EXTINF:8,[\\s\\S]*?#EXT-X-DISCONTINUITY"
]
},
{
"name": "量子廣告",
"hosts": [
"vip.lz",
"hd.lz"
],
"regex": [
"#EXT-X-DISCONTINUITY\\r*\\n*#EXTINF:6.433333,[\\s\\S]*?#EXT-X-DISCONTINUITY",
"#EXTINF.*?\\s+.*?1o.*?\\.ts\\s+"
]
},
{
"name": "非凡廣告",
"hosts": [
"vip.ffzy",
"hd.ffzy"
],
"regex": [
"#EXT-X-DISCONTINUITY\\r*\\n*#EXTINF:6.666667,[\\s\\S]*?#EXT-X-DISCONTINUITY",
"#EXTINF.*?\\s+.*?1o.*?\\.ts\\s+"
]
},
{
"name": "火山嗅探",
"hosts": [
"huoshan.com"
],
"regex": [
"item_id="
]
},
{
"name": "抖音嗅探",
"hosts": [
"douyin.com"
],
"regex": [
"is_play_url="
]
}
],
"doh": [
{
"name": "Google",
"url": "https://dns.google/dns-query",
"ips": [
"8.8.4.4",
"8.8.8.8"
]
},
{
"name": "Cloudflare",
"url": "https://cloudflare-dns.com/dns-query",
"ips": [
"1.1.1.1",
"1.0.0.1",
"2606:4700:4700::1111",
"2606:4700:4700::1001"
]
},
{
"name": "AdGuard",
"url": "https://dns.adguard.com/dns-query",
"ips": [
"94.140.14.140",
"94.140.14.141"
]
},
{
"name": "DNSWatch",
"url": "https://resolver2.dns.watch/dns-query",
"ips": [
"84.200.69.80",
"84.200.70.40"
]
},
{
"name": "Quad9",
"url": "https://dns.quad9.net/dns-quer",
"ips": [
"9.9.9.9",
"149.112.112.112"
]
}
],
"parses": [
{
"name": "聚合",
"type": 3,
"url": "Demo"
},
{
"name": "线路1",
"type": 0,
"url": "https://jx.xmflv.com/?url=",
"ext": {
"header": {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.57"
}
}
},
{
"name": "线路2",
"type": 0,
"url": "https://jx.quankan.app/?url=",
"ext": {
"header": {
"user-agent": "Mozilla/5.0 (Linux; Android 13; V2049A Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36"
}
}
},
{
"name": "线路3",
"type": 0,
"url": "https://jx.yparse.com/index.php?url=",
"ext": {
"header": {
"user-agent": "Mozilla/5.0 (Linux; Android 13; V2049A Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36"
}
}
},
{
"name": "线路4",
"type": 0,
"url": "https://jx.jsonplayer.com/player/?url=",
"ext": {
"header": {
"user-agent": "Mozilla/5.0 (Linux; Android 13; V2049A Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36"
}
}
},
{
"name": "线路5",
"type": 0,
"url": "https://jx.aidouer.net/?url=",
"ext": {
"header": {
"user-agent": "Mozilla/5.0 (Linux; Android 13; V2049A Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36",
"referer": "https://jiejie.uk/"
}
}
},
{
"name": "线路6",
"type": 0,
"url": "https://jx.777jiexi.com/player/?url="
},
{
"name": "线路7",
"type": 0,
"url": "https://www.8090g.cn/?url="
},
{
"name": "线路8",
"type": 0,
"url": "https://jx.yangtu.top?url="
},
{
"name": "线路9",
"type": 0,
"url": "https://jx.m3u8.tv/jiexi/?url="
},
{
"name": "线路10",
"type": 0,
"url": "https://www.ckplayer.vip/jiexi/?url="
}
],
"lives": [
{
"name": "live",
"type": 0,
"url": "https://gh.con.sh/https://github.com/jadehh/LiveSpider/blob/main/live/live.txt",
"playerType": 1,
"ua": "okhttp/3.15",
"epg": "http://epg.112114.xyz/?ch={name}&date={date}",
"logo": "https://epg.112114.xyz/logo/{name}.png"
}
],
"wallpaper": "https://api.likepoems.com/img/bing"
}

View File

@ -1,190 +0,0 @@
import Stream, { DEFAULT_ENCODING, getEncoding } from './text_decoder_index.js'
import { end_of_stream, finished, codePointsToString } from './text_decoder_utils.js'
import { decoders } from './table.js'
// 8.1 Interface TextDecoder
class TextDecoder {
/**
* @param {string=} label The label of the encoding; defaults to 'utf-8'.
* @param {Object=} options
*/
constructor(label = DEFAULT_ENCODING, options = {}) {
// A TextDecoder object has an associated encoding, decoder,
// stream, ignore BOM flag (initially unset), BOM seen flag
// (initially unset), error mode (initially replacement), and do
// not flush flag (initially unset).
/** @private */
this._encoding = null
/** @private @type {?Decoder} */
this._decoder = null
/** @private @type {boolean} */
this._ignoreBOM = false
/** @private @type {boolean} */
this._BOMseen = false
/** @private @type {string} */
this._error_mode = 'replacement'
/** @private @type {boolean} */
this._do_not_flush = false
// 1. Let encoding be the result of getting an encoding from
// label.
const encoding = getEncoding(label)
// 2. If encoding is failure or replacement, throw a RangeError.
if (encoding === null || encoding.name == 'replacement')
throw RangeError('Unknown encoding: ' + label)
if (!decoders[encoding.name]) {
throw Error('Decoder not present.' +
' Did you forget to include encoding-indexes.js first?')
}
// 4. Set dec's encoding to encoding.
this._encoding = encoding
// 5. If options's fatal member is true, set dec's error mode to
// fatal.
if (options['fatal'])
this._error_mode = 'fatal'
// 6. If options's ignoreBOM member is true, set dec's ignore BOM
// flag.
if (options['ignoreBOM'])
this._ignoreBOM = true
}
get encoding() {
return this._encoding.name.toLowerCase()
}
get fatal() {
return this._error_mode === 'fatal'
}
get ignoreBOM() {
return this._ignoreBOM
}
/**
* @param {BufferSource=} input The buffer of bytes to decode.
* @param {Object=} options
* @return The decoded string.
*/
decode(input, options = {}) {
let bytes
if (typeof input === 'object' && input instanceof ArrayBuffer) {
bytes = new Uint8Array(input)
} else if (typeof input === 'object' && 'buffer' in input &&
input.buffer instanceof ArrayBuffer) {
bytes = new Uint8Array(input.buffer,
input.byteOffset,
input.byteLength)
} else {
bytes = new Uint8Array(0)
}
// 1. If the do not flush flag is unset, set decoder to a new
// encoding's decoder, set stream to a new stream, and unset the
// BOM seen flag.
if (!this._do_not_flush) {
this._decoder = decoders[this._encoding.name]({
fatal: this._error_mode === 'fatal' })
this._BOMseen = false
}
// 2. If options's stream is true, set the do not flush flag, and
// unset the do not flush flag otherwise.
this._do_not_flush = Boolean(options['stream'])
// 3. If input is given, push a copy of input to stream.
// TODO: Align with spec algorithm - maintain stream on instance.
const input_stream = new Stream(bytes)
// 4. Let output be a new stream.
const output = []
/** @type {?(number|!Array.<number>)} */
let result
// 5. While true:
while (true) {
// 1. Let token be the result of reading from stream.
const token = input_stream.read()
// 2. If token is end-of-stream and the do not flush flag is
// set, return output, serialized.
// TODO: Align with spec algorithm.
if (token === end_of_stream)
break
// 3. Otherwise, run these subsubsteps:
// 1. Let result be the result of processing token for decoder,
// stream, output, and error mode.
result = this._decoder.handler(input_stream, token)
// 2. If result is finished, return output, serialized.
if (result === finished)
break
if (result !== null) {
if (Array.isArray(result))
output.push.apply(output, /**@type {!Array.<number>}*/(result))
else
output.push(result)
}
// 3. Otherwise, if result is error, throw a TypeError.
// (Thrown in handler)
// 4. Otherwise, do nothing.
}
// TODO: Align with spec algorithm.
if (!this._do_not_flush) {
do {
result = this._decoder.handler(input_stream, input_stream.read())
if (result === finished)
break
if (result === null)
continue
if (Array.isArray(result))
output.push.apply(output, /**@type {!Array.<number>}*/(result))
else
output.push(result)
} while (!input_stream.endOfStream())
this._decoder = null
}
return this.serializeStream(output)
}
// A TextDecoder object also has an associated serialize stream
// algorithm...
/**
* @param {!Array.<number>} stream
*/
serializeStream(stream) {
// 1. Let token be the result of reading from stream.
// (Done in-place on array, rather than as a stream)
// 2. If encoding is UTF-8, UTF-16BE, or UTF-16LE, and ignore
// BOM flag and BOM seen flag are unset, run these subsubsteps:
if (['UTF-8', 'UTF-16LE', 'UTF-16BE'].includes(this._encoding.name) &&
!this._ignoreBOM && !this._BOMseen) {
if (stream.length > 0 && stream[0] === 0xFEFF) {
// 1. If token is U+FEFF, set BOM seen flag.
this._BOMseen = true
stream.shift()
} else if (stream.length > 0) {
// 2. Otherwise, if token is not end-of-stream, set BOM seen
// flag and append token to stream.
this._BOMseen = true
} else {
// 3. Otherwise, if token is not end-of-stream, append token
// to output.
// (no-op)
}
}
// 4. Otherwise, return output.
return codePointsToString(stream)
}
}
export {TextDecoder}

View File

@ -1,107 +0,0 @@
import Stream, { DEFAULT_ENCODING, getEncoding } from './text_decoder_index.js'
import { end_of_stream, finished, stringToCodePoints } from './text_decoder_utils.js'
import { encoders } from './table.js'
// 8.2 Interface TextEncoder
class TextEncoder {
/**
* @param {string=} label The label of the encoding. NONSTANDARD.
* @param {Object=} [options] NONSTANDARD.
*/
constructor(label, options = {}) {
// A TextEncoder object has an associated encoding and encoder.
/** @private */
this._encoding = null
/** @private @type {?Encoder} */
this._encoder = null
// Non-standard
/** @private @type {boolean} */
this._do_not_flush = false
/** @private @type {string} */
this._fatal = options['fatal'] ? 'fatal' : 'replacement'
// 2. Set enc's encoding to UTF-8's encoder.
if (options['NONSTANDARD_allowLegacyEncoding']) {
// NONSTANDARD behavior.
label = label !== undefined ? String(label) : DEFAULT_ENCODING
var encoding = getEncoding(label)
if (encoding === null || encoding.name === 'replacement')
throw RangeError('Unknown encoding: ' + label)
if (!encoders[encoding.name]) {
throw Error('Encoder not present.' +
' Did you forget to include encoding-indexes.js first?')
}
this._encoding = encoding
} else {
// Standard behavior.
this._encoding = getEncoding('utf-8')
if (label !== undefined && 'console' in global) {
console.warn('TextEncoder constructor called with encoding label, '
+ 'which is ignored.')
}
}
}
get encoding() {
return this._encoding.name.toLowerCase()
}
/**
* @param {string=} opt_string The string to encode.
* @param {Object=} options
*/
encode(opt_string = '', options = {}) {
// NOTE: This option is nonstandard. None of the encodings
// permitted for encoding (i.e. UTF-8, UTF-16) are stateful when
// the input is a USVString so streaming is not necessary.
if (!this._do_not_flush)
this._encoder = encoders[this._encoding.name]({
fatal: this._fatal === 'fatal' })
this._do_not_flush = Boolean(options['stream'])
// 1. Convert input to a stream.
const input = new Stream(stringToCodePoints(opt_string))
// 2. Let output be a new stream
const output = []
/** @type {?(number|!Array.<number>)} */
var result
// 3. While true, run these substeps:
while (true) {
// 1. Let token be the result of reading from input.
var token = input.read()
if (token === end_of_stream)
break
// 2. Let result be the result of processing token for encoder,
// input, output.
result = this._encoder.handler(input, token)
if (result === finished)
break
if (Array.isArray(result))
output.push.apply(output, /**@type {!Array.<number>}*/(result))
else
output.push(result)
}
// TODO: Align with spec algorithm.
if (!this._do_not_flush) {
while (true) {
result = this._encoder.handler(input, input.read())
if (result === finished)
break
if (Array.isArray(result))
output.push.apply(output, /**@type {!Array.<number>}*/(result))
else
output.push(result)
}
this._encoder = null
}
// 3. If result is finished, convert output into a byte sequence,
// and then return a Uint8Array object wrapping an ArrayBuffer
// containing output.
return new Uint8Array(output)
}
}
export {TextEncoder}

View File

@ -1,83 +0,0 @@
/*
* @Author: samples jadehh@live.com
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples jadehh@live.com
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: lib/ali.js
* @Description: 阿里云盘Spider公共
*/
import {
getVod,
initSome,
clearFile,
playerContent,
playerContentByFlag,
setShareId,
setToken,
getFileByShare, getTempFileId
} from './ali_api.js';
import {JadeLogging} from "./log.js";
const JadeLog = new JadeLogging("阿里云盘")
async function initAli(token) {
await initSome();
await setToken(token);
await getTempFileId();
// await clearFile();
await JadeLog.info("阿里云盘初始化完成", true)
}
function getShareId(share_url) {
let patternAli = /https:\/\/www\.alipan\.com\/s\/([^\\/]+)(\/folder\/([^\\/]+))?|https:\/\/www\.aliyundrive\.com\/s\/([^\\/]+)(\/folder\/([^\\/]+))?/
let matches = patternAli.exec(share_url)
const filteredArr = matches.filter(item => item !== undefined);
if (filteredArr.length > 1) {
return filteredArr[1]
} else {
return ""
}
}
async function detailContent(share_url_list, type_name = "电影") {
try {
let video_items = [], sub_items = []
for (const share_url of share_url_list) {
let share_id = getShareId(share_url)
let share_token = await setShareId(share_id)
if (share_token !== undefined) {
await getFileByShare(share_token, share_url, video_items, sub_items)
}
}
if (video_items.length > 0) {
await JadeLog.info(`获取播放链接成功,分享链接为:${share_url_list.join("\t")}`)
} else {
await JadeLog.error(`获取播放链接失败,检查分享链接为:${share_url_list.join("\t")}`)
}
return getVod(video_items, sub_items, type_name)
} catch (e) {
await JadeLog.error('获取阿里视频失败,失败原因为:' + e.message + ' 行数为:' + e.lineNumber);
}
}
async function playContent(flag, id, flags) {
if (flags.length > 0) {
await JadeLog.info(`准备播放,播放类型为:${flag},播放文件Id为:${id},播放所有类型为:${flags.join("")}`)
} else {
await JadeLog.info(`准备播放,播放类型为:${flag},播放文件Id为:${id},播放所有类型为:${flags.join("")}`)
}
let file_id_list = id.split("+")
let share_id = file_id_list[1]
let file_id = file_id_list[0]
let share_token = file_id_list[2]
return flag === "原画" ? await playerContent(file_id, share_id, share_token) : await playerContentByFlag(file_id, flag, share_id, share_token);
}
export {
initAli,
detailContent,
playContent
};

View File

@ -1,711 +0,0 @@
/*
* @Author: samples jadehh@live.com
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples jadehh@live.com
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: /lib/ali_api.js
* @Description: 阿里云盘Api
*/
import {_, jinja2} from "./cat.js";
import * as Utils from "./utils.js";
import {JadeLogging} from "./log.js";
import {
Code, Drive, getHeader, getOAuthCache, getUserCache, Item, OAuth, post, postJson, Sub, User, CLIENT_ID
} from "./ali_object.js";
let quality = {}, tempIds = [], shareToken = "", shareId = "", oauth = new OAuth(), user = new User(),
driveInfo = new Drive(), tmpFolderName = "TV", curTmpFolderFileId = "",
JadeLog = new JadeLogging("阿里云盘", "INFO");
async function initSome() {
let user_cache_str = await getUserCache();
user = User.objectFrom(user_cache_str);
if (!_.isEmpty(user.getRefreshToken())) {
await JadeLog.info("读取用户缓存成功", true);
} else {
await JadeLog.error("读取用户缓存失败", true);
}
let oauth_cache_str = await getOAuthCache();
oauth = OAuth.objectFrom(oauth_cache_str);
if (!_.isEmpty(oauth.getAccessToken())) {
await JadeLog.info("读取授权成功", true)
} else {
await JadeLog.error("读取授权失败", true)
}
// quality = {
// "4K": "UHD", "2k": "QHD", "超清": "FHD", "高清": "HD", "标清": "SD", "流畅": "LD"
// };
quality = {
"4K": "UHD", "2k": "QHD", "超清": "QHD", "高清": "HD", "标清": "SD", "流畅": "LD"
};
await JadeLog.info("阿里Api初始化完成")
}
async function getTempFileId() {
curTmpFolderFileId = await createTmpFolder();
}
async function clearFile() {
try {
await deleteTmpFolderAndRecreate();
} catch (e) {
await JadeLog.error("清空缓存文件失败,失败原因为:{}" + e)
}
await cleanRecord()
}
async function cleanRecord() {
await local.set("file", "file_id", JSON.stringify({}))
}
async function setShareId(share_id) {
getOAuthCache().length === 0 && (await oauth.clean().save());
getUserCache().length === 0 && (await user.clean().save());
shareId = share_id;
return await refreshShareToken();
}
function getHeaderAuth(shareToken) {
const params = {};
params["x-share-token"] = shareToken;
params["X-Canary"] = "client=Android,app=adrive,version=v4.3.1";
if (user.isAuthed()) {
params.authorization = user.getAuthorization();
}
return params;
}
function getHeaderShare() {
const params = getHeader();
params["x-share-token"] = shareToken;
params["X-Canary"] = "client=Android,app=adrive,version=v4.3.1";
return params;
}
function getHeaderOpen() {
const params = {};
params.authorization = oauth.getAuthorization();
return params;
}
function aliExpection(data_str) {
if (data_str.indexOf("TooManyRequests") > -1) {
Utils.sleep(1)
return {code: 429, content: data_str}
} else if (data_str.indexOf("AccessTokenInvalid") > -1) {
return {code: 400, content: data_str}
} else if (data_str.indexOf("AccessTokenExpired") > -1) {
return {code: 401, content: data_str}
} else if (data_str.indexOf("BadRequest") > -1) {
return {code: 402, content: data_str}
} else if (data_str.indexOf("NotFound.File") > -1 || data_str.indexOf("ForbiddenFileInTheRecycleBin") > -1) {
return {code: 403, content: data_str}
} else if (data_str.indexOf("ForbiddenNoPermission.File") > -1) {
return {code: 500, content: data_str}
} else if (data_str.indexOf("InvalidParameter.ToParentFileId") > -1) {
return {code: 501, content: data_str}
} else if (data_str.indexOf("NotFound.ParentFileId") > -1) {
return {code: 502, content: data_str}
} else if (data_str.indexOf("The resource drive has exceeded the limit. File size exceeded drive capacity") > -1) {
return {code: 503, content: data_str}
}
return {code: 200, content: data_str}
}
async function alistManyRequest(data_str) {
if (!(data_str.indexOf("Too Many Requests") > -1)) {
return false;
}
await oauth.clean().save();
return true;
}
// Alist Token获取
async function alist(url_param, params) {
let url = "https://api-cf.nn.ci/alist/ali_open/" + url_param;
let response = await postJson(url, params, getHeader()), response_content = response.content;
if (await alistManyRequest(response_content)) {
await JadeLog.error(`Alist授权Token失败,失败原因为:太多请求,失败详情为:${response_content}`)
return false;
}
oauth = await OAuth.objectFrom(response_content).save();
return true;
}
// 阿里云盘用户Api
async function auth(url, params, shareToken, retry) {
url = url.startsWith("https") ? url : "https://api.aliyundrive.com/" + url;
let response = await postJson(url, params, getHeaderAuth(shareToken));
await JadeLog.debug(`正在请求需要阿里登录的url:${url},参数为:${JSON.stringify(params)}`)
response = aliExpection(response.content)
if (retry && (response.code === 400)) {
await JadeLog.error("登录阿里云盘失败,失败原因为:登录Token无效,准备重新授权,失败详情:" + response.content)
await refreshAccessToken("")
return await auth(url, params, shareToken, false);
}
await JadeLog.debug(`完成请求需要阿里登录的url:${url},参数为:${JSON.stringify(params)},请求结果为${response.content}`)
return response.content;
}
// 需要授权的Api
async function oauthFunc(url, params, retry) {
url = url.startsWith("https") ? url : "https://open.aliyundrive.com/adrive/v1.0/" + url;
await JadeLog.debug(`正在请求需要阿里授权的url:${url},参数为:${JSON.stringify(params)}`)
let open_header = getHeaderOpen();
let response = await postJson(url, params, open_header);
response = aliExpection(response.content)
if (retry && (response.code === 400 || response.code === 401 || response.code === 429 || response.code === 402 || response.code === 403)) {
if (response.code === 400) {
await JadeLog.error("阿里授权失败,失败原因为:授权Token无效,准备重新授权,失败详情:" + response.content)
await activateRefreshOpenToken()
} else if (response.code === 401) {
await JadeLog.error("阿里授权失败,失败原因为:授权Token失效,准备重新授权,失败详情:" + response.content)
await activateRefreshOpenToken()
} else if (response.code === 402) {
await JadeLog.error("阿里授权失败,失败原因为:授权Token失效,准备重新授权,失败详情:" + response.content)
return await oauthFunc(url, params, true)
} else if (response.code === 403) {
await JadeLog.error("阿里授权失败,失败原因为:没有找到缓存文件,失败详情:" + response.content)
await cleanRecord()
return "retry"
} else if (response.code === 429) {
await JadeLog.error(`正在请求需要阿里授权的url:${url},请求过于频繁,稍后重试,10分钟后再重试`)
Utils.sleep(10 * 60)
return await oauthFunc(url, params, true)
}
return await oauthFunc(url, params, false)
}
await JadeLog.debug(`完成请求需要阿里授权的url:${url},参数为:${JSON.stringify(params)},请求结果为:${JSON.stringify(response)}`)
return response.content;
}
async function shareFunc(url, params) {
url = url.startsWith("https") ? url : "https://api.aliyundrive.com/" + url;
let headers = getHeaderShare(), response = await postJson(url, params, headers);
return response.content;
}
//主动刷新授权Token
async function activateRefreshOpenToken() {
await oauth.clean().save()
await refreshOpenToken()
}
async function refreshShareToken() {
try {
let params = {};
params.share_id = shareId;
params.share_pwd = "";
let response_content = await post("v2/share_link/get_share_token", params),
response_json = JSON.parse(response_content);
if (response_json["code"] === "ShareLink.Cancelled") {
await JadeLog.error("分享链接被取消了")
}
shareToken = response_json.share_token;
return shareToken
} catch (e) {
await JadeLog.error("刷新Share Token失败" + e)
}
}
//支持切换Token
async function refreshAccessToken(token) {
try {
if (_.isEmpty(user.getAccessToken()) || user.getRefreshToken() !== token) {
let refresh_token_params = {};
refresh_token_params.refresh_token = user.getRefreshToken();
refresh_token_params.grant_type = "refresh_token";
await JadeLog.info(`准备登录阿里云盘,登录Token为:${user.getRefreshToken()}`)
let response_conetent = await post("https://auth.aliyundrive.com/v2/account/token", refresh_token_params);
if (response_conetent.indexOf("InvalidParameter.RefreshToken") > 1 || _.isEmpty(response_conetent)) {
if (_.isEmpty(response_conetent)) {
await JadeLog.error(`登录阿里云盘失败,登录Token为:${user.getRefreshToken()},失败原因为:检查Token是否正确`)
} else {
await JadeLog.error(`登录阿里云盘失败,登录Token为:${user.getRefreshToken()},失败原因为:检查Token是否正确,返回结果为:${response_conetent}`)
}
} else {
await JadeLog.info(`登录阿里云盘成功,登录Token为:${user.getRefreshToken()}`)
user = await User.objectFrom(response_conetent).save();
}
} else {
await JadeLog.info(`阿里云盘已登录,无需重复登录,登录Token为:${user.getRefreshToken()}`)
}
return true;
} catch (e) {
await JadeLog.error(`登录阿里云盘失败,登录Token为:${user.getRefreshToken()},失败原因为:${e}`)
await user.clean().save();
return true;
}
}
async function oauthRequest() {
try {
let params = {};
params.authorize = 1;
params.scope = "user:base,file:all:read,file:all:write";
let url = "https://open.aliyundrive.com/oauth/users/authorize?client_id=" + CLIENT_ID + "&redirect_uri=https://alist.nn.ci/tool/aliyundrive/callback&scope=user:base,file:all:read,file:all:write&state="
await JadeLog.debug(`正在请求获取阿里授权码的url:${url},参数为:${params}`)
let response_str = await auth(url, params, shareToken, true);
await JadeLog.debug(`完成请求获取阿里授权码的url:${url},参数为:${params},返回值为:${response_str}`)
if (_.isEmpty(response_str) || response_str.indexOf("AccessTokenInvalid") > -1) {
if (_.isEmpty(response_str)) {
await JadeLog.error(`请求获取阿里授权码失败,失败原因为:还未登录`)
} else {
await JadeLog.error(`请求获取阿里授权码失败,失败原因为:还未登录,失败详情为:${response_str}`)
}
} else {
await JadeLog.info(`请求获取阿里授权码成功,返回值为:${response_str}`)
return await oauthRedirect(Code.objectFrom(response_str).getCode());
}
} catch (e) {
await JadeLog.error(`请求获取阿里授权失败,失败原因为:${e}`)
return false;
}
}
async function oauthRedirect(code) {
try {
let params = {};
params.code = code;
params.grant_type = "authorization_code";
return await alist("code", params);
} catch (e) {
// // console.debug(_0x114c46);
await oauth.clean().save();
return false;
}
}
async function refreshOpenToken() {
try {
// 刷新 Refresh Token
if (_.isEmpty(oauth.getRefreshToken())) {
return await oauthRequest();
}
// 刷新Access Token
if (_.isEmpty(oauth.getAccessToken())) {
let params = {};
params.grant_type = "refresh_token";
params.refresh_token = oauth.getRefreshToken();
return await alist("token", params);
}
return true;
} catch (e) {
await JadeLog.error("刷新授权Token失败,失败原因为:" + e);
await oauth.clean().save();
return false;
}
}
async function getFileByShare(share_token, share_url, video_item_list, sub_item_list) {
await JadeLog.info(`正在获取播放链接,分享链接为:${share_url}`)
let params = {};
params.share_id = shareId;
let file_id = share_url.split("folder/").slice(-1)[0]
if (file_id.length !== 40) {
file_id = ""
}
let response_str = await post("adrive/v3/share_link/get_share_by_anonymous", params),
response_json = JSON.parse(response_str), item_file_id = getParentFileId(file_id, response_json),
item = new Item(item_file_id);
await listFiles(item, video_item_list, sub_item_list, share_token);
}
async function getVod(video_item_list, sub_item_list, type_name) {
let play_foramt_list = ["原画", "超清", "高清", "标清"], episode_list = [], episode_str_list = [];
for (const video_item of video_item_list) {
episode_list.push(video_item.getDisplayName(type_name) + "$" + video_item.getFileId() + "+" + video_item.shareId + "+" + video_item.shareToken + findSubs(video_item.getName(), sub_item_list));
}
for (let index = 0; index < play_foramt_list.length; index++) {
episode_str_list.push(episode_list.join("#"));
}
return {
vod_play_url: episode_str_list.join("$$$"), vod_play_from: play_foramt_list.map(item => item).join("$$$"),
};
}
async function listFiles(item, video_item_list, sub_item_list, share_token) {
return await listFilesMarker(item, video_item_list, sub_item_list, "", share_token);
}
async function listFilesMarker(item, video_item_list, sub_item_list, netxt_markers, share_token) {
let new_item = {}, file_list = [];
new_item.limit = 200;
new_item.share_id = shareId;
new_item.share_token = share_token
new_item.parent_file_id = item.getFileId();
new_item.order_by = "name";
new_item.order_direction = "ASC";
if (netxt_markers.length > 0) {
new_item.marker = netxt_markers;
}
let items = Item.objectFrom(await shareFunc("adrive/v2/file/list_by_share", new_item), shareToken);
for (const r_item of items.getItems()) {
if (r_item.getType() === "folder") {
file_list.push(r_item);
} else {
if ((r_item.getCategory() === "video" || r_item.getCategory() === "audio")) {
//判断数组中是否有file_id
//
let is_video_file_exists = false
for (const video_item of video_item_list) {
if (r_item.getFileId() === video_item.getFileId()) {
is_video_file_exists = true
await JadeLog.debug('视频分享文件重复,无需添加')
}
}
if (!is_video_file_exists) {
if (r_item.getCategory() === "video" && r_item.size / 1000000 > 10) {
video_item_list.push(r_item.parentFunc(item.getName()));
}
}
} else {
if (Utils.isSub(r_item.getExt())) {
let is_sub_file_exists = false
for (const sub_item of sub_item_list) {
if (r_item.getFileId() === sub_item.getFileId()) {
is_sub_file_exists = true
await JadeLog.debug('字幕分享文件重复,无需添加')
}
}
if (!is_sub_file_exists) {
sub_item_list.push(r_item);
}
}
}
}
}
items.getNextMarker().length > 0 && (await listFilesMarker(item, video_item_list, sub_item_list, items.getNextMarker()));
for (const file of file_list) {
await listFiles(file, video_item_list, sub_item_list);
}
}
function getParentFileId(file_id, items) {
let file_infos = items.file_infos;
if (!_.isEmpty(file_id)) {
return file_id;
}
if (file_infos.length === 0) {
return "";
}
let item = file_infos[0];
if (item.type === "folder") {
return item.file_id;
}
if (item.type === "file" && item.category === "video") {
return "root";
}
return "";
}
//字幕匹配
function pair(name, item_list, sub_item_list) {
for (const item of item_list) {
const sub_name = Utils.removeExt(item.getName()).toLowerCase();
if (name.indexOf(sub_name) > -1 || sub_name.indexOf(name) > -1) {
sub_item_list.push(item);
}
}
}
//找出所有字幕
function findSubs(name, item_list) {
let sub_item_list = [];
pair(Utils.removeExt(name).toLowerCase(), item_list, sub_item_list);
if (sub_item_list.length === 0) {
for (const item of item_list) {
sub_item_list.push(item);
}
}
let sub_str = "";
for (const item of sub_item_list) {
sub_str += "+" + Utils.removeExt(item.getName()) + "@@@" + item.getExt() + "@@@" + item.getFileId();
}
return sub_str;
}
async function getSubs(sub_list, share_id) {
let sub_url_list = [];
for (const sub_str of sub_list) {
if (!(sub_str.indexOf("@@@") > -1)) {
continue;
}
let sub_split_list = sub_str.split("@@@"), sub_name = sub_split_list[0], sub_ext = sub_split_list[1],
sub_file_id = sub_split_list[2], sub_url = await getDownloadUrl(sub_file_id, share_id);
sub_url_list.push(Sub.create().setName(sub_name).setExt(sub_ext).setUrl(sub_url));
}
return sub_url_list;
}
async function getDriveInfo() {
if (!_.isEmpty(driveInfo) && !_.isEmpty(driveInfo.default_drive_id)) {
return driveInfo;
}
let _0x3740f3 = await oauthFunc("user/getDriveInfo", {}, true), _0x56fde5 = JSON.parse(_0x3740f3);
driveInfo = {
default_drive_id: _0x56fde5.default_drive_id,
resource_drive_id: _0x56fde5.resource_drive_id,
backup_drive_id: _0x56fde5.backup_drive_id
};
return driveInfo;
}
async function getDriveId() {
if (_.isEmpty(user.getDriveId())) {
let drive = await getDriveInfo();
return drive.resource_drive_id;
}
return user.getDriveId();
}
async function getDownloadUrl(file_id, share_id, share_token) {
let drive_id = await getDriveId();
tempIds.unshift(await copy(file_id, share_id, share_token));
let params = {};
params.file_id = tempIds[0];
params.drive_id = drive_id;
if (tempIds[0] !== null) {
let response_str = await oauthFunc("openFile/getDownloadUrl", params, true);
if (response_str === "retry") {
await JadeLog.info("尝试重新获取下载链接");
return await getDownloadUrl(file_id, share_id)
} else {
await JadeLog.info("获取下载链接成功:返回结果为:" + response_str + "请求参数为:" + JSON.stringify(params));
return JSON.parse(response_str).url;
}
} else {
await JadeLog.error("获取下载链接失败:失败原因:请检查转存文件失败原因")
return null;
}
}
async function getVideoPreviewPlayInfo(file_id, share_id, shareToken) {
let drive_id = await getDriveId();
tempIds.unshift(await copy(file_id, share_id, shareToken));
let params = {};
params.file_id = tempIds[0];
params.drive_id = drive_id;
params.category = "live_transcoding";
params.url_expire_sec = "14400";
let response_str = await oauthFunc("openFile/getVideoPreviewPlayInfo", params, true);
return JSON.parse(response_str).video_preview_play_info;
}
async function playerContent(file_id, share_id, share_token) {
try {
await JadeLog.info("正在获取原画的播放地址和字幕下载链接", true)
let download_url = await getDownloadUrl(file_id, share_id, share_token);
// let sub_list = await getSubs(file_id_list,share_id);
await JadeLog.info("获取原画的播放地址和字幕下载链接成功", true)
await JadeLog.info(`下载地址为:${download_url}`)
return JSON.stringify({
parse: 0, url: download_url, header: getHeader(), format: "application/octet-stream", subs: []
});
} catch (e) {
await JadeLog.error("获取原画的播放地址和字幕下载链接失败:失败原因为:" + e);
}
}
// 转码头的Url和字幕
async function playerContentByFlag(file_id, flag, share_id, shareToken) {
try {
await JadeLog.info("正在获取转码后的播放地址和字幕下载链接", true)
let video_preview_play_info = await getVideoPreviewPlayInfo(file_id, share_id, shareToken),
video_preview_url = getPreviewUrl(video_preview_play_info, flag);
// let sub_list = await getSubs(file_id_list,share_id),
// sub_p_list = getSubsByPlayInfo(video_preview_play_info);
// for (const sub_p of sub_p_list) {
// sub_list.push(sub_p);
// }
await JadeLog.info("获取转码后的播放地址和字幕下载链接成功", true)
await JadeLog.info(`下载地址为:${video_preview_url}`)
return JSON.stringify({
parse: 0, url: video_preview_url, header: getHeader(), format: "application/x-mpegURL", subs: []
});
} catch (e) {
await JadeLog.error(`获取转码后的播放地址和字幕下载链接失败,失败原因为:${e}`)
}
}
function getPreviewUrl(video_preview_play_info, flag) {
if (!video_preview_play_info.hasOwnProperty("live_transcoding_task_list")) {
return "";
}
let live_transcoding_task_list = video_preview_play_info.live_transcoding_task_list;
for (let index = 0; index < live_transcoding_task_list.length; ++index) {
let live_transcoding_task = live_transcoding_task_list[index];
if (live_transcoding_task.template_id === quality[flag]) {
return live_transcoding_task.url;
}
}
return live_transcoding_task_list[0].url;
}
function getSubsByPlayInfo(video_preview_play_info) {
if (!video_preview_play_info.hasOwnProperty("live_transcoding_subtitle_task_list")) {
return [];
}
let live_transcoding_subtitle_task_list = video_preview_play_info.live_transcoding_subtitle_task_list,
sub_p_list = [];
for (let index = 0; index < live_transcoding_subtitle_task_list.length; ++index) {
let live_transcoding_subtitle_task = live_transcoding_subtitle_task_list[index],
language = live_transcoding_subtitle_task.language, url = live_transcoding_subtitle_task.url;
sub_p_list.push(Sub.create().setUrl(url).setName(language).setLang(language).setExt("vtt"));
}
return sub_p_list;
}
async function copy(file_id, shareId, shareToken) {
let copy_file_id
let cache_dic = {}
try {
cache_dic = JSON.parse(await local.get("file", "file_id"))
} catch (e) {
}
copy_file_id = cache_dic[file_id]
if (typeof (copy_file_id) == "string") {
await JadeLog.info(`file id为:${file_id},已经缓存过,copy file id为:${copy_file_id}`)
} else {
let params_str = "{\"requests\":[{\"body\":{\"file_id\":\"{{data.fileId}}\",\"share_id\":\"{{data.shareId}}\",\"auto_rename\":true,\"to_parent_file_id\":\"{{data.tmpFolderFileId}}\",\"to_drive_id\":\"{{data.driveId}}\"},\"headers\":{\"Content-Type\":\"application/json\"},\"id\":\"0\",\"method\":\"POST\",\"url\":\"/file/copy\"}],\"resource\":\"file\"}",
drive_id = await getDriveId(), params = {
fileId: file_id, shareId: shareId, driveId: drive_id, tmpFolderFileId: curTmpFolderFileId
};
params_str = jinja2(params_str, {
data: params
});
await JadeLog.debug(`正在转存文件,文件id为:${file_id}`, true)
let response_str = await auth("adrive/v2/batch", JSON.parse(params_str), shareToken, true);
let response = aliExpection(response_str)
if (response.code === 500 || response.code === 501 || response.code === 502 || response.code === 503 || response.code === 403) {
if (response.code === 500) {
await JadeLog.error("转存文件失败,失败详情:" + response.content)
return copy(file_id);
} else if (response.code === 501) {
await JadeLog.error("转存文件失败,失败详情:" + response.content)
return copy(file_id)
} else if (response.code === 502) {
await JadeLog.error("转存文件失败,失败原因为:转存文件夹不存在,失败详情:" + response.content)
return null;
} else if (response.code === 503) {
await JadeLog.error("转存文件失败,失败原因为:转存文件夹大小被限制" + response.content)
await clearFile()
return copy(file_id)
} else if (response.code === 403) {
await JadeLog.error("转存文件失败,失败原因为:没有找到File Id,失败详情:" + response.content)
return null;
}
}
await JadeLog.debug(`转存文件成功,文件id为:${file_id},请求结果为:${response_str}`)
copy_file_id = JSON.parse(response_str).responses[0].body.file_id;
let file_dic = {}
try {
JSON.parse(await local.get("file", "file_id"))
} catch (e) {
}
file_dic[file_id] = copy_file_id
await local.set("file", "file_id", JSON.stringify(file_dic))
}
return copy_file_id;
}
async function deleteTmpFolderAndRecreate() {
// 删除缓存文件夹
let file_id = await tmpFolderExistsFunc();
file_id && (await trashFile(file_id), await recyclebinClear());
await getTempFileId();
}
//放入回车站
async function trashFile(file_id) {
let params_str = "{\"requests\":[{\"body\":{\"file_id\":\"{{data.fileId}}\",\"drive_id\":\"{{data.driveId}}\"},\"headers\":{\"Content-Type\":\"application/json\"},\"id\":\"0\",\"method\":\"POST\",\"url\":\"/recyclebin/trash\"}],\"resource\":\"file\"}",
drive_id = await getDriveId(), params = {
fileId: file_id, driveId: drive_id
};
params_str = jinja2(params_str, {
data: params
});
await JadeLog.debug(`正在准备删除文件,文件id为:${file_id}`, true)
let response = await auth("v2/batch", JSON.parse(params_str), shareToken, true);
await JadeLog.debug(`删除文件成功,文件id为:${file_id},请求结果为:${response}`)
return true;
}
//清空回车站
async function recyclebinClear() {
let drive_id = await getDriveId(), params = {
drive_id: drive_id
};
await auth("v2/recyclebin/clear", params, shareToken, true);
await JadeLog.info("清空回车站成功", true)
return true;
}
async function createTmpFolder() {
//创建文件夹
let file_id = await tmpFolderExistsFunc();
if (file_id) {
await JadeLog.info("文件夹存在,无需重新创建")
return file_id;
}
await JadeLog.debug("文件夹不存在,重新创建文件夹")
let drive_id = await getDriveId(), params = {
check_name_mode: "refuse", drive_id: drive_id, name: tmpFolderName, parent_file_id: "root", type: "folder"
}, response_str = await oauthFunc("openFile/create", params, true);
let response_json = JSON.parse(response_str);
if (_.isEmpty(response_json.drive_id)) {
await JadeLog.error(`创建文件夹失败,失败原因为:${response_str}`)
return null;
}
await JadeLog.info(`创建文件夹成功`, true)
return response_json.file_id;
}
async function tmpFolderExistsFunc() {
let drive_id = await getDriveId(), params = {
drive_id: drive_id, parent_file_id: "root", limit: 100, order_by: "updated_at", order_direction: "DESC"
}, response_str = await oauthFunc("openFile/list", params, true);
let response_json = JSON.parse(response_str);
if (_.isEmpty(response_json.items)) {
return false;
}
for (const item of response_json.items) {
if (item.name === tmpFolderName) {
return item.file_id;
}
}
return false;
}
async function setToken(token) {
// Token设置
user.setRefreshToken(token);
await refreshAccessToken(token);
await refreshOpenToken();
}
export {
initSome, setToken, clearFile, setShareId, getFileByShare, getVod, playerContent, playerContentByFlag, getTempFileId
};

View File

@ -1,510 +0,0 @@
/*
* @Author: samples jadehh@live.com
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples jadehh@live.com
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: /lib/ali_object.js
* @Description: 阿里云盘基础类
*/
import {_} from "./cat.js";
const UA = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"
const CLIENT_ID = "76917ccccd4441c39457a04f6084fb2f";
import * as Utils from "./utils.js";
// 引用会导致出错
// import qs from "qs";
// import axios from "axios";
// import https from "https";
function getHeader() {
const params = {};
params["User-Agent"] = UA;
params.Referer = "https://www.aliyundrive.com/";
return params;
}
class User {
constructor() {
this.driveId = "";
this.userId = "";
this.tokenType = "";
this.accessToken = "";
this.refreshToken = "";
}
static objectFrom(json_str) {
if (_.isEmpty(json_str)) {
return new User();
}
let resonse = JSON.parse(json_str), user = new User();
user.driveId = resonse.default_drive_id;
user.userId = resonse.user_id;
user.tokenType = resonse.token_type;
user.accessToken = resonse.access_token;
user.refreshToken = resonse.refresh_token; // 刷新Token记录原有的Token
return user;
}
getDriveId() {
return _.isEmpty(this.driveId) ? "" : this.driveId;
}
getUserId() {
return _.isEmpty(this.userId) ? "" : this.userId;
}
getTokenType() {
return _.isEmpty(this.tokenType) ? "" : this.tokenType;
}
getAccessToken() {
return _.isEmpty(this.accessToken) ? "" : this.accessToken;
}
getRefreshToken() {
return _.isEmpty(this.refreshToken) ? "" : this.refreshToken;
}
setRefreshToken(refresh_token) {
this.refreshToken = refresh_token
}
getAuthorization() {
return this.getTokenType() + " " + this.getAccessToken();
}
isAuthed() {
return this.getTokenType().length > 0 && this.getAccessToken().length > 0;
}
clean() {
this.refreshToken = "";
this.accessToken = "";
return this;
}
async save() {
await local.set("ali", "aliyundrive_user", this.toString());
return this;
}
toString() {
return JSON.stringify(this.toDict());
}
toDict() {
return {
default_drive_id: this.getDriveId(),
user_id: this.getUserId(),
token_type: this.getTokenType(),
access_token: this.getAccessToken(),
refresh_token: this.getRefreshToken()
};
}
}
class OAuth {
constructor() {
this.tokenType = "";
this.accessToken = "";
this.refreshToken = "";
}
static objectFrom(json_str) {
if (_.isEmpty(json_str)) {
return new OAuth();
}
let oauth_json = JSON.parse(json_str), oAuth = new OAuth();
oAuth.tokenType = oauth_json.token_type;
oAuth.accessToken = oauth_json.access_token;
oAuth.refreshToken = oauth_json.refresh_token;
return oAuth;
}
getTokenType() {
return _.isEmpty(this.tokenType) ? "" : this.tokenType;
}
getAccessToken() {
return _.isEmpty(this.accessToken) ? "" : this.accessToken;
}
getRefreshToken() {
return _.isEmpty(this.refreshToken) ? "" : this.refreshToken;
}
getAuthorization() {
return this.getTokenType() + " " + this.getAccessToken();
}
clean() {
this.refreshToken = "";
this.accessToken = "";
return this;
}
async save() {
await local.set("ali", "aliyundrive_oauth", this.toString());
return this;
}
toString() {
return JSON.stringify(this.toDict());
}
toDict() {
return {
token_type: this.getTokenType(), access_token: this.getAccessToken(), refresh_token: this.getRefreshToken()
};
}
}
class Drive {
constructor() {
this.defaultDriveId = "";
this.resourceDriveId = "";
this.backupDriveId = "";
}
static objectFrom(json_str) {
if (_.isEmpty(json_str)) {
return new Drive();
}
let obj = JSON.parse(json_str), drive = new Drive();
drive.defaultDriveId = obj.default_drive_id;
drive.resourceDriveId = obj.resource_drive_id;
drive.backupDriveId = obj.backup_drive_id;
return drive;
}
getDefaultDriveId() {
return _.isEmpty(this.defaultDriveId) ? "" : this.defaultDriveId;
}
getResourceDriveId() {
return _.isEmpty(this.resourceDriveId) ? "" : this.resourceDriveId;
}
getBackupDriveId() {
return _.isEmpty(this.backupDriveId) ? "" : this.backupDriveId;
}
clean() {
this.defaultDriveId = "";
this.backupDriveId = "";
this.resourceDriveId = "";
return this;
}
async save() {
await local.set("ali", "aliyundrive_drive", this.toString());
return this;
}
toString() {
const params = {
default_drive_id: this.getDefaultDriveId(),
resource_drive_id: this.getResourceDriveId(),
backup_drive_id: this.getBackupDriveId()
};
return JSON.stringify(params);
}
}
class Code {
constructor() {
this.redirectUri = "";
}
static objectFrom(json_str) {
if (_.isEmpty(json_str)) {
return new Code();
}
let code_json = JSON.parse(json_str), code = new Code();
code.redirectUri = code_json.redirectUri;
return code;
}
getRedirectUri() {
return _.isEmpty(this.redirectUri) ? "" : this.redirectUri;
}
getCode() {
return this.getRedirectUri().split("code=")[1];
}
}
class Item {
constructor(file_id) {
this.items = [];
this.nextMarker = "";
this.fileId = file_id;
this.shareId = "";
this.name = "";
this.type = "";
this.fileExtension = "";
this.category = "";
this.size = "";
this.parent = "";
this.shareToken = ""
}
static objectFrom(json_str, shareToken) {
if (_.isEmpty(json_str)) {
return new Item();
}
let item_json = JSON.parse(json_str), item = new Item();
item.nextMarker = typeof item_json.next_marker == "undefined" ? "" : item_json.next_marker;
item.fileId = typeof item_json.file_id == "undefined" ? "" : item_json.file_id;
item.shareId = typeof item_json.share_id == "undefined" ? "" : item_json.share_id;
item.shareToken = shareToken
item.name = typeof item_json.name == "undefined" ? "" : item_json.name;
item.type = typeof item_json.type == "undefined" ? "" : item_json.type;
item.fileExtension = typeof item_json.file_extension == "undefined" ? "" : item_json.file_extension;
item.category = typeof item_json.category == "undefined" ? "" : item_json.category;
item.size = typeof item_json.size == "undefined" ? "" : item_json.size;
item.parent = typeof item_json.parent_file_id == "undefined" ? "" : item_json.parent_file_id;
typeof item.items != "undefined" && Array.isArray(item_json.items) && !_.isEmpty(item_json.items) && item_json.items.forEach(function (x) {
let new_item = Item.objectFrom(JSON.stringify((x)), shareToken)
item.items.push(new_item);
});
return item;
}
getItems() {
return _.isEmpty(this.items) ? [] : this.items;
}
getNextMarker() {
return _.isEmpty(this.nextMarker) ? "" : this.nextMarker;
}
getFileId() {
return _.isEmpty(this.fileId) ? "" : this.fileId;
}
getShareId() {
return _.isEmpty(this.shareId) ? "" : this.shareId;
}
getFileExtension() {
return _.isEmpty(this.fileExtension) ? "" : this.fileExtension;
}
getName() {
return _.isEmpty(this.name) ? "" : this.name;
}
getType() {
return _.isEmpty(this.type) ? "" : this.type;
}
getExt() {
return _.isEmpty(this.fileExtension) ? "" : this.fileExtension;
}
getCategory() {
return _.isEmpty(this.category) ? "" : this.category;
}
getSize() {
return this.size === 0 ? "" : "[" + Utils.getSize(this.size) + "]";
}
getParent() {
return _.isEmpty(this.parent) ? "" : "[" + this.parent + "]";
}
parentFunc(item) {
this.parent = item;
return this;
}
// getDisplayName() {
// return this.getParent() + " " + this.getName() + " " + this.getSize();
// }
getDisplayName(type_name) {
let name = this.getName();
name = name.replaceAll("玩偶哥 q 频道:【神秘的哥哥们】", "")
if (type_name === "电视剧") {
let replaceNameList = ["4k", "4K"]
name = name.replaceAll("." + this.getFileExtension(), "")
name = name.replaceAll(" ", "").replaceAll(" ", "")
for (const replaceName of replaceNameList) {
name = name.replaceAll(replaceName, "")
}
name = Utils.getStrByRegexDefault(/\.S01E(.*?)\./, name)
const numbers = name.match(/\d+/g);
if (numbers.length > 0) {
name = numbers[0]
}
}
return name + " " + this.getParent() + " " + this.getSize();
}
}
class Sub {
constructor() {
this.url = "";
this.name = "";
this.lang = "";
this.format = "";
}
static create() {
return new Sub();
}
setName(name) {
this.name = name;
return this;
}
setUrl(url) {
this.url = url;
return this;
}
setLang(lang) {
this.lang = lang;
return this;
}
setFormat(format) {
this.format = format;
return this;
}
setExt(ext) {
switch (ext) {
case "vtt":
return this.setFormat("text/vtt");
case "ass":
case "ssa":
return this.setFormat("text/x-ssa");
default:
return this.setFormat("application/x-subrip");
}
}
}
async function getUserCache() {
return await local.get("ali", "aliyundrive_user");
}
async function getOAuthCache() {
return await local.get("ali", "aliyundrive_oauth");
}
function getShareId(share_url) {
let patternAli = /https:\/\/www\.alipan\.com\/s\/([^\\/]+)(\/folder\/([^\\/]+))?|https:\/\/www\.aliyundrive\.com\/s\/([^\\/]+)(\/folder\/([^\\/]+))?/
let matches = patternAli.exec(share_url)
const filteredArr = matches.filter(item => item !== undefined);
if (filteredArr.length > 1) {
return matches[1]
} else {
return ""
}
}
async function ali_request(url, opt) {
let resp;
let data;
try {
data = opt ? opt.data || null : null;
const postType = opt ? opt.postType || null : null;
const returnBuffer = opt ? opt.buffer || 0 : 0;
const timeout = opt ? opt.timeout || 5000 : 5000;
const headers = opt ? opt.headers || {} : {};
if (postType === 'form') {
headers['Content-Type'] = 'application/x-www-form-urlencoded';
if (data != null) {
data = qs.stringify(data, {encode: false});
}
}
let respType = returnBuffer === 1 || returnBuffer === 2 ? 'arraybuffer' : undefined;
resp = await axios(url, {
responseType: respType,
method: opt ? opt.method || 'get' : 'get',
headers: headers,
data: data,
timeout: timeout,
httpsAgent: https.Agent({
rejectUnauthorized: false,
}),
});
data = resp.data;
const resHeader = {};
for (const hks of resp.headers) {
const v = hks[1];
resHeader[hks[0]] = Array.isArray(v) ? (v.length === 1 ? v[0] : v) : v;
}
if (!returnBuffer) {
if (typeof data === 'object') {
data = JSON.stringify(data);
}
} else if (returnBuffer === 1) {
return {code: resp.status, headers: resHeader, content: data};
} else if (returnBuffer === 2) {
return {code: resp.status, headers: resHeader, content: data.toString('base64')};
}
return {code: resp.status, headers: resHeader, content: data};
} catch (error) {
// await Utils.log(`请求失败,URL为:${url},失败原因为:${error}`)
resp = error.response
try {
return {code: resp.status, headers: resp.headers, content: JSON.stringify(resp.data)};
} catch (err) {
return {headers: {}, content: ''};
}
}
}
async function post(url, params) {
url = url.startsWith("https") ? url : "https://api.aliyundrive.com/" + url;
let response = await postJson(url, params, getHeader());
return response.content;
}
async function postJson(url, params, headers) {
params["Content-Type"] = "application/json";
return await req(url, {
headers: headers, method: "post", data: params
});
}
export {
UA,
CLIENT_ID,
OAuth,
Code,
Sub,
User,
Item,
Drive,
getHeader,
getShareId,
getOAuthCache,
getUserCache,
post,
postJson
};

View File

@ -1,154 +0,0 @@
import { inRange, decoderError, encoderError, isASCIICodePoint,
end_of_stream, finished, isASCIIByte, floor } from './text_decoder_utils.js'
import index, { indexBig5PointerFor, indexCodePointFor } from './text_decoder_indexes.js'
//
// 12. Legacy multi-byte Chinese (traditional) encodings
//
// 12.1 Big5
// 12.1.1 Big5 decoder
/**
* @implements {Decoder}
*/
export class Big5Decoder {
constructor(options) {
const { fatal } = options
this.fatal = fatal
// Big5's decoder has an associated Big5 lead (initially 0x00).
this.Big5_lead = 0x00
}
/**
* @param {Stream} stream The stream of bytes being decoded.
* @param {number} bite The next byte read from the stream.
*/
handler(stream, bite) {
// 1. If byte is end-of-stream and Big5 lead is not 0x00, set
// Big5 lead to 0x00 and return error.
if (bite === end_of_stream && this.Big5_lead !== 0x00) {
this.Big5_lead = 0x00
return decoderError(this.fatal)
}
// 2. If byte is end-of-stream and Big5 lead is 0x00, return
// finished.
if (bite === end_of_stream && this.Big5_lead === 0x00)
return finished
// 3. If Big5 lead is not 0x00, let lead be Big5 lead, let
// pointer be null, set Big5 lead to 0x00, and then run these
// substeps:
if (this.Big5_lead !== 0x00) {
const lead = this.Big5_lead
let pointer = null
this.Big5_lead = 0x00
// 1. Let offset be 0x40 if byte is less than 0x7F and 0x62
// otherwise.
const offset = bite < 0x7F ? 0x40 : 0x62
// 2. If byte is in the range 0x40 to 0x7E, inclusive, or 0xA1
// to 0xFE, inclusive, set pointer to (lead 0x81) × 157 +
// (byte offset).
if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0xA1, 0xFE))
pointer = (lead - 0x81) * 157 + (bite - offset)
// 3. If there is a row in the table below whose first column
// is pointer, return the two code points listed in its second
// column
// Pointer | Code points
// --------+--------------
// 1133 | U+00CA U+0304
// 1135 | U+00CA U+030C
// 1164 | U+00EA U+0304
// 1166 | U+00EA U+030C
switch (pointer) {
case 1133: return [0x00CA, 0x0304]
case 1135: return [0x00CA, 0x030C]
case 1164: return [0x00EA, 0x0304]
case 1166: return [0x00EA, 0x030C]
}
// 4. Let code point be null if pointer is null and the index
// code point for pointer in index Big5 otherwise.
const code_point = (pointer === null) ? null :
indexCodePointFor(pointer, index('big5'))
// 5. If code point is null and byte is an ASCII byte, prepend
// byte to stream.
if (code_point === null && isASCIIByte(bite))
stream.prepend(bite)
// 6. If code point is null, return error.
if (code_point === null)
return decoderError(this.fatal)
// 7. Return a code point whose value is code point.
return code_point
}
// 4. If byte is an ASCII byte, return a code point whose value
// is byte.
if (isASCIIByte(bite))
return bite
// 5. If byte is in the range 0x81 to 0xFE, inclusive, set Big5
// lead to byte and return continue.
if (inRange(bite, 0x81, 0xFE)) {
this.Big5_lead = bite
return null
}
// 6. Return error.
return decoderError(this.fatal)
}
}
// 12.1.2 Big5 encoder
/**
* @implements {Encoder}
*/
export class Big5Encoder {
constructor() {
/**
* @param {Stream} stream Input stream.
* @param {number} code_point Next code point read from the stream.
*/
this.handler = function(stream, code_point) {
// 1. If code point is end-of-stream, return finished.
if (code_point === end_of_stream)
return finished
// 2. If code point is an ASCII code point, return a byte whose
// value is code point.
if (isASCIICodePoint(code_point))
return code_point
// 3. Let pointer be the index Big5 pointer for code point.
const pointer = indexBig5PointerFor(code_point)
// 4. If pointer is null, return error with code point.
if (pointer === null)
return encoderError(code_point)
// 5. Let lead be floor(pointer / 157) + 0x81.
const lead = floor(pointer / 157) + 0x81
// 6. If lead is less than 0xA1, return error with code point.
if (lead < 0xA1)
return encoderError(code_point)
// 7. Let trail be pointer % 157.
const trail = pointer % 157
// 8. Let offset be 0x40 if trail is less than 0x3F and 0x62
// otherwise.
const offset = trail < 0x3F ? 0x40 : 0x62
// Return two bytes whose values are lead and trail + offset.
return [lead, trail + offset]
}
}
}

View File

@ -1,31 +0,0 @@
/*
* @File : bilibili_ASS_Danmaku_Downloader.js
* @Author : jade
* @Date : 2024/3/14 13:19
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
function parseXML(json) {
let list = [];
/**
* <d p="{time},{type},{size},{color},{timestamp},{pool},{uid_crc32},{row_id}">
*
* {Text}
* time为弹幕在视频里的时间 -->
* type为弹幕类型 -->
* size为字体大小 -->
* color为十进制的RGB颜色16进制转10进制 -->
* timestamp为弹幕发送时间戳unix时间戳 -->
* pool为弹幕池 -->
* uid_crc32为发送者uid的crc32 -->
*/
Array.from(json.danmuku).forEach(x => {
let start = Number(x[0]);
let content = x[4];
list.push(`<d p="${start},1,25,16777215,1659282294,0,8b53b65c,1108899274487246080"><![CDATA[${content}]]></d>`)
});
return String.raw`<?xml version="1.0" encoding="UTF-8"?><i><chatserver>chat.bilibili.com</chatserver><chatid>52175602</chatid><mission>0</mission><maxlimit>1000</maxlimit><state>0</state><real_name>0</real_name><source>k-v</source>` + list.join('') + "</i>"
}
export {parseXML}

View File

@ -1,76 +0,0 @@
/*
* @File : book.js
* @Author : jade
* @Date : 2024/1/30 17:01
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
export class BookShort {
constructor() {
this.book_id = "" //id
this.book_name = "" //名称
this.book_pic = "" //图片
this.book_remarks = "" //备注
}
to_dict() {
return JSON.stringify(this);
}
load_dic(json_str) {
let obj = JSON.parse(json_str)
for (let propName in obj) {
this[propName] = obj[propName];
}
}
}
export class BookDetail extends BookShort {
/**
* let book = {
* book_name: $('[property$=book_name]')[0].attribs.content,
* book_year: $('[property$=update_time]')[0].attribs.content,
* book_director: $('[property$=author]')[0].attribs.content,
* book_content: $('[property$=description]')[0].attribs.content,
* };
* $ = await this.getHtml(this.siteUrl + id + `list.html`);
* let urls = [];
* const links = $('dl>dd>a[href*="/html/"]');
* for (const l of links) {
* const name = $(l).text().trim();
* const link = l.attribs.href;
* urls.push(name + '$' + link);
* }
* book.volumes = '全卷';
* book.urls = urls.join('#');
* return book
* */
constructor() {
super();
this.book_year = ""
this.book_director = ""
this.book_content = ""
this.volumes = ""
this.urls = ""
}
to_short() {
let bookShort = new BookShort()
bookShort.load_dic(this.to_dict())
return bookShort.to_dict()
}
load_dic(json_str) {
let obj = JSON.parse(json_str)
for (let propName in obj) {
this[propName] = obj[propName];
console.log(propName);//打印👉属性名-->name age gender address
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,188 +0,0 @@
/*
* @File : danmuSpider.js
* @Author : jade
* @Date : 2024/3/13 13:39
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load, Uri} from "./cat.js";
import * as Utils from "./utils.js";
import {JadeLogging} from "./log.js";
import {VodDetail, VodShort} from "./vod.js";
import {parseXML} from "./bilibili_ASS_Danmaku_Downloader.js";
class DanmuSpider {
constructor() {
this.siteUrl = "https://search.youku.com"
this.reconnectTimes = 0
this.maxReconnectTimes = 5
this.jadeLog = new JadeLogging(this.getAppName(), "DEBUG")
}
getAppName() {
return "弹幕"
}
getHeader() {
return {"User-Agent": Utils.CHROME, "Referer": this.siteUrl + "/"};
}
async reconnnect(reqUrl, params, headers, redirect_url, return_cookie, buffer) {
await this.jadeLog.error("请求失败,请检查url:" + reqUrl + ",两秒后重试")
Utils.sleep(2)
if (this.reconnectTimes < this.maxReconnectTimes) {
this.reconnectTimes = this.reconnectTimes + 1
return await this.fetch(reqUrl, params, headers, redirect_url, return_cookie, buffer)
} else {
await this.jadeLog.error("请求失败,重连失败")
return null
}
}
async getResponse(reqUrl, params, headers, redirect_url, return_cookie, buffer, response) {
{
if (response.headers["location"] !== undefined) {
if (redirect_url) {
await this.jadeLog.debug(`返回重定向连接:${response.headers["location"]}`)
return response.headers["location"]
} else {
return this.fetch(response.headers["location"], params, headers, redirect_url, return_cookie, buffer)
}
} else if (response.content.length > 0) {
this.reconnectTimes = 0
if (return_cookie) {
return {"cookie": response.headers["set-cookie"], "content": response.content}
} else {
return response.content
}
} else if (buffer === 1) {
this.reconnectTimes = 0
return response.content
} else {
await this.jadeLog.error(`请求失败,请求url为:${reqUrl},回复内容为:${JSON.stringify(response)}`)
return await this.reconnnect(reqUrl, params, headers, redirect_url, return_cookie, buffer)
}
}
}
async fetch(reqUrl, params, headers, redirect_url = false, return_cookie = false, buffer = 0) {
let data = Utils.objectToStr(params)
let url = reqUrl
if (!_.isEmpty(data)) {
url = reqUrl + "?" + data
}
let uri = new Uri(url);
let response;
response = await req(uri.toString(), {method: "get", headers: headers, buffer: buffer, data: null})
if (response.code === 201 || response.code === 200 || response.code === 302 || response.code === 301 || return_cookie) {
return await this.getResponse(reqUrl, params, headers, redirect_url, return_cookie, buffer, response)
} else {
await this.jadeLog.error(`请求失败,失败原因为:状态码出错,请求url为:${uri},回复内容为:${JSON.stringify(response)}`)
return await this.reconnnect(reqUrl, params, headers, redirect_url, return_cookie, buffer)
}
}
async getHtml(url = this.siteUrl, headers = this.getHeader()) {
let html = await this.fetch(url, null, headers)
if (!_.isEmpty(html)) {
return load(html)
} else {
await this.jadeLog.error(`html获取失败`, true)
}
}
async parseVodShortListFromJson(obj, vodDetail) {
for (const componentObj of obj["pageComponentList"]) {
if (componentObj["commonData"] !== undefined) {
let searchVodDetail = new VodDetail()
let commonData = componentObj["commonData"]
searchVodDetail.type_name = commonData["feature"]
if (commonData["notice"] !== undefined) {
searchVodDetail.vod_actor = commonData["notice"].replaceAll("演员:", "").replaceAll(" ", "")
}
if (commonData["director"] !== undefined) {
searchVodDetail.vod_director = commonData["director"].replaceAll("导演:", "").replaceAll(" ", "")
}
if (vodDetail.type_name === "电影") {
searchVodDetail.vod_id = commonData["leftButtonDTO"]["action"]["value"]
} else {
searchVodDetail.vod_id = commonData["showId"]
}
searchVodDetail.vod_name = commonData["titleDTO"]["displayName"]
if ( searchVodDetail.vod_name === vodDetail.vod_name || searchVodDetail.type_name.indexOf(vodDetail.vod_year) > -1 || searchVodDetail.type_name.indexOf(vodDetail.type_name) > -1 || searchVodDetail.vod_director === vodDetail.vod_director) {
await this.jadeLog.debug(`匹配视频网站成功,名称为:${searchVodDetail.vod_name},类型为:${searchVodDetail.type_name},导演为:${searchVodDetail.vod_director}`, true)
return searchVodDetail
}
}
}
await this.jadeLog.warning("没有匹配到弹幕网站")
return null
}
async parseVodUrlFromJsonByEpisodeId(obj, episodeId) {
for (const serises of obj["serisesList"]) {
if (Utils.isNumeric(episodeId["episodeId"])) {
if (parseInt(episodeId["episodeId"]).toString() === serises["displayName"]) {
return serises["action"]["value"]
}
}
}
await this.jadeLog.error("没有找到匹配的集数")
return ""
}
async downloadDanmu(url) {
// 如果没有找到弹幕的话,容易导致卡在这一步,从而导致结果加载不出来
let response = await req(url,{headers:this.getHeader()})
if (response.code === 200){
let xml = parseXML(JSON.parse(response.content))
let params = {"do": "set", "key": "danmu", "value": xml}
await req("http://127.0.0.1:9978/cache", {method: "post", data: params, postType: "form-data"});
return "http://127.0.0.1:9978/cache?do=get&key=danmu"
}
else{
this.jadeLog.error(`弹幕请求失败,返回结果为:${JSON.stringify(response)}`)
return ""
}
}
async search(vodDetail, episodeId) {
let params = {"pg": "1", "keyword": vodDetail.vod_name}
let searchObj = JSON.parse(await this.fetch(this.siteUrl + "/api/search", params, this.getHeader()))
let searchDetail = await this.parseVodShortListFromJson(searchObj, vodDetail)
if (!_.isEmpty(searchDetail)){
return await this.getVideoUrl(searchDetail.vod_id, episodeId)
}else{
return ""
}
}
async getVideoUrl(showId, episodeId) {
let url = "";
if (!_.isEmpty(showId)) {
if (showId.startsWith("http")) {
url = showId
} else {
let params = {"appScene": "show_episode", "showIds": showId}
let matchObj = JSON.parse(await this.fetch(this.siteUrl + "/api/search", params, this.getHeader()))
url = await this.parseVodUrlFromJsonByEpisodeId(matchObj, episodeId)
}
if (!_.isEmpty(url)) {
await this.jadeLog.debug(`弹幕视频播放连接为:${url}`)
return await this.downloadDanmu("https://dmku.thefilehosting.com/?ac=dm&url=" + url)
}
}
return url
}
async getDammu(voddetail, episodeId) {
return await this.search(voddetail, episodeId)
}
}
export {DanmuSpider}

File diff suppressed because one or more lines are too long

View File

@ -1,460 +0,0 @@
/**
* Encodings table: https://encoding.spec.whatwg.org/encodings.json
*/
const encodings = [
{
encodings: [
{
labels: [
"unicode-1-1-utf-8",
"utf-8",
"utf8",
],
name: "UTF-8",
},
],
heading: "The Encoding",
},
{
encodings: [
{
labels: [
"866",
"cp866",
"csibm866",
"ibm866",
],
name: "IBM866",
},
{
labels: [
"csisolatin2",
"iso-8859-2",
"iso-ir-101",
"iso8859-2",
"iso88592",
"iso_8859-2",
"iso_8859-2:1987",
"l2",
"latin2",
],
name: "ISO-8859-2",
},
{
labels: [
"csisolatin3",
"iso-8859-3",
"iso-ir-109",
"iso8859-3",
"iso88593",
"iso_8859-3",
"iso_8859-3:1988",
"l3",
"latin3",
],
name: "ISO-8859-3",
},
{
labels: [
"csisolatin4",
"iso-8859-4",
"iso-ir-110",
"iso8859-4",
"iso88594",
"iso_8859-4",
"iso_8859-4:1988",
"l4",
"latin4",
],
name: "ISO-8859-4",
},
{
labels: [
"csisolatincyrillic",
"cyrillic",
"iso-8859-5",
"iso-ir-144",
"iso8859-5",
"iso88595",
"iso_8859-5",
"iso_8859-5:1988",
],
name: "ISO-8859-5",
},
{
labels: [
"arabic",
"asmo-708",
"csiso88596e",
"csiso88596i",
"csisolatinarabic",
"ecma-114",
"iso-8859-6",
"iso-8859-6-e",
"iso-8859-6-i",
"iso-ir-127",
"iso8859-6",
"iso88596",
"iso_8859-6",
"iso_8859-6:1987",
],
name: "ISO-8859-6",
},
{
labels: [
"csisolatingreek",
"ecma-118",
"elot_928",
"greek",
"greek8",
"iso-8859-7",
"iso-ir-126",
"iso8859-7",
"iso88597",
"iso_8859-7",
"iso_8859-7:1987",
"sun_eu_greek",
],
name: "ISO-8859-7",
},
{
labels: [
"csiso88598e",
"csisolatinhebrew",
"hebrew",
"iso-8859-8",
"iso-8859-8-e",
"iso-ir-138",
"iso8859-8",
"iso88598",
"iso_8859-8",
"iso_8859-8:1988",
"visual",
],
name: "ISO-8859-8",
},
{
labels: [
"csiso88598i",
"iso-8859-8-i",
"logical",
],
name: "ISO-8859-8-I",
},
{
labels: [
"csisolatin6",
"iso-8859-10",
"iso-ir-157",
"iso8859-10",
"iso885910",
"l6",
"latin6",
],
name: "ISO-8859-10",
},
{
labels: [
"iso-8859-13",
"iso8859-13",
"iso885913",
],
name: "ISO-8859-13",
},
{
labels: [
"iso-8859-14",
"iso8859-14",
"iso885914",
],
name: "ISO-8859-14",
},
{
labels: [
"csisolatin9",
"iso-8859-15",
"iso8859-15",
"iso885915",
"iso_8859-15",
"l9",
],
name: "ISO-8859-15",
},
{
labels: [
"iso-8859-16",
],
name: "ISO-8859-16",
},
{
labels: [
"cskoi8r",
"koi",
"koi8",
"koi8-r",
"koi8_r",
],
name: "KOI8-R",
},
{
labels: [
"koi8-ru",
"koi8-u",
],
name: "KOI8-U",
},
{
labels: [
"csmacintosh",
"mac",
"macintosh",
"x-mac-roman",
],
name: "macintosh",
},
{
labels: [
"dos-874",
"iso-8859-11",
"iso8859-11",
"iso885911",
"tis-620",
"windows-874",
],
name: "windows-874",
},
{
labels: [
"cp1250",
"windows-1250",
"x-cp1250",
],
name: "windows-1250",
},
{
labels: [
"cp1251",
"windows-1251",
"x-cp1251",
],
name: "windows-1251",
},
{
labels: [
"ansi_x3.4-1968",
"ascii",
"cp1252",
"cp819",
"csisolatin1",
"ibm819",
"iso-8859-1",
"iso-ir-100",
"iso8859-1",
"iso88591",
"iso_8859-1",
"iso_8859-1:1987",
"l1",
"latin1",
"us-ascii",
"windows-1252",
"x-cp1252",
],
name: "windows-1252",
},
{
labels: [
"cp1253",
"windows-1253",
"x-cp1253",
],
name: "windows-1253",
},
{
labels: [
"cp1254",
"csisolatin5",
"iso-8859-9",
"iso-ir-148",
"iso8859-9",
"iso88599",
"iso_8859-9",
"iso_8859-9:1989",
"l5",
"latin5",
"windows-1254",
"x-cp1254",
],
name: "windows-1254",
},
{
labels: [
"cp1255",
"windows-1255",
"x-cp1255",
],
name: "windows-1255",
},
{
labels: [
"cp1256",
"windows-1256",
"x-cp1256",
],
name: "windows-1256",
},
{
labels: [
"cp1257",
"windows-1257",
"x-cp1257",
],
name: "windows-1257",
},
{
labels: [
"cp1258",
"windows-1258",
"x-cp1258",
],
name: "windows-1258",
},
{
labels: [
"x-mac-cyrillic",
"x-mac-ukrainian",
],
name: "x-mac-cyrillic",
},
],
heading: "Legacy single-byte encodings",
},
{
encodings: [
{
labels: [
"chinese",
"csgb2312",
"csiso58gb231280",
"gb2312",
"gb_2312",
"gb_2312-80",
"gbk",
"iso-ir-58",
"x-gbk",
],
name: "GBK",
},
{
labels: [
"gb18030",
],
name: "gb18030",
},
],
heading: "Legacy multi-byte Chinese (simplified) encodings",
},
{
encodings: [
{
labels: [
"big5",
"big5-hkscs",
"cn-big5",
"csbig5",
"x-x-big5",
],
name: "Big5",
},
],
heading: "Legacy multi-byte Chinese (traditional) encodings",
},
{
encodings: [
{
labels: [
"cseucpkdfmtjapanese",
"euc-jp",
"x-euc-jp",
],
name: "EUC-JP",
},
{
labels: [
"csiso2022jp",
"iso-2022-jp",
],
name: "ISO-2022-JP",
},
{
labels: [
"csshiftjis",
"ms932",
"ms_kanji",
"shift-jis",
"shift_jis",
"sjis",
"windows-31j",
"x-sjis",
],
name: "Shift_JIS",
},
],
heading: "Legacy multi-byte Japanese encodings",
},
{
encodings: [
{
labels: [
"cseuckr",
"csksc56011987",
"euc-kr",
"iso-ir-149",
"korean",
"ks_c_5601-1987",
"ks_c_5601-1989",
"ksc5601",
"ksc_5601",
"windows-949",
],
name: "EUC-KR",
},
],
heading: "Legacy multi-byte Korean encodings",
},
{
encodings: [
{
labels: [
"csiso2022kr",
"hz-gb-2312",
"iso-2022-cn",
"iso-2022-cn-ext",
"iso-2022-kr",
],
name: "replacement",
},
{
labels: [
"utf-16be",
],
name: "UTF-16BE",
},
{
labels: [
"utf-16",
"utf-16le",
],
name: "UTF-16LE",
},
{
labels: [
"x-user-defined",
],
name: "x-user-defined",
},
],
heading: "Legacy miscellaneous encodings",
},
]
export default encodings

View File

@ -1,166 +0,0 @@
import { inRange, decoderError, encoderError, isASCIICodePoint,
end_of_stream, finished, isASCIIByte, floor } from './text_decoder_utils.js'
import index, { indexCodePointFor, indexPointerFor } from './text_decoder_indexes.js'
//
// 13. Legacy multi-byte Japanese encodings
//
// 13.1 euc-jp
// 13.1.1 euc-jp decoder
/**
* @implements {Decoder}
*/
export class EUCJPDecoder {
constructor(options) {
const { fatal } = options
this.fatal = fatal
// euc-jp's decoder has an associated euc-jp jis0212 flag
// (initially unset) and euc-jp lead (initially 0x00).
this.eucjp_jis0212_flag = false
this.eucjp_lead = 0x00
}
/**
* @param {Stream} stream The stream of bytes being decoded.
* @param {number} bite The next byte read from the stream.
*/
handler(stream, bite) {
// 1. If byte is end-of-stream and euc-jp lead is not 0x00, set
// euc-jp lead to 0x00, and return error.
if (bite === end_of_stream && this.eucjp_lead !== 0x00) {
this.eucjp_lead = 0x00
return decoderError(this.fatal)
}
// 2. If byte is end-of-stream and euc-jp lead is 0x00, return
// finished.
if (bite === end_of_stream && this.eucjp_lead === 0x00)
return finished
// 3. If euc-jp lead is 0x8E and byte is in the range 0xA1 to
// 0xDF, inclusive, set euc-jp lead to 0x00 and return a code
// point whose value is 0xFF61 0xA1 + byte.
if (this.eucjp_lead === 0x8E && inRange(bite, 0xA1, 0xDF)) {
this.eucjp_lead = 0x00
return 0xFF61 - 0xA1 + bite
}
// 4. If euc-jp lead is 0x8F and byte is in the range 0xA1 to
// 0xFE, inclusive, set the euc-jp jis0212 flag, set euc-jp lead
// to byte, and return continue.
if (this.eucjp_lead === 0x8F && inRange(bite, 0xA1, 0xFE)) {
this.eucjp_jis0212_flag = true
this.eucjp_lead = bite
return null
}
// 5. If euc-jp lead is not 0x00, let lead be euc-jp lead, set
// euc-jp lead to 0x00, and run these substeps:
if (this.eucjp_lead !== 0x00) {
const lead = this.eucjp_lead
this.eucjp_lead = 0x00
// 1. Let code point be null.
let code_point = null
// 2. If lead and byte are both in the range 0xA1 to 0xFE,
// inclusive, set code point to the index code point for (lead
// 0xA1) × 94 + byte 0xA1 in index jis0208 if the euc-jp
// jis0212 flag is unset and in index jis0212 otherwise.
if (inRange(lead, 0xA1, 0xFE) && inRange(bite, 0xA1, 0xFE)) {
code_point = indexCodePointFor(
(lead - 0xA1) * 94 + (bite - 0xA1),
index(!this.eucjp_jis0212_flag ? 'jis0208' : 'jis0212'))
}
// 3. Unset the euc-jp jis0212 flag.
this.eucjp_jis0212_flag = false
// 4. If byte is not in the range 0xA1 to 0xFE, inclusive,
// prepend byte to stream.
if (!inRange(bite, 0xA1, 0xFE))
stream.prepend(bite)
// 5. If code point is null, return error.
if (code_point === null)
return decoderError(this.fatal)
// 6. Return a code point whose value is code point.
return code_point
}
// 6. If byte is an ASCII byte, return a code point whose value
// is byte.
if (isASCIIByte(bite))
return bite
// 7. If byte is 0x8E, 0x8F, or in the range 0xA1 to 0xFE,
// inclusive, set euc-jp lead to byte and return continue.
if (bite === 0x8E || bite === 0x8F || inRange(bite, 0xA1, 0xFE)) {
this.eucjp_lead = bite
return null
}
// 8. Return error.
return decoderError(this.fatal)
}
}
// 13.1.2 euc-jp encoder
/**
* @implements {Encoder}
*/
export class EUCJPEncoder {
/**
* @param {Stream} stream Input stream.
* @param {number} code_point Next code point read from the stream.
*/
handler(stream, code_point) {
// 1. If code point is end-of-stream, return finished.
if (code_point === end_of_stream)
return finished
// 2. If code point is an ASCII code point, return a byte whose
// value is code point.
if (isASCIICodePoint(code_point))
return code_point
// 3. If code point is U+00A5, return byte 0x5C.
if (code_point === 0x00A5)
return 0x5C
// 4. If code point is U+203E, return byte 0x7E.
if (code_point === 0x203E)
return 0x7E
// 5. If code point is in the range U+FF61 to U+FF9F, inclusive,
// return two bytes whose values are 0x8E and code point
// 0xFF61 + 0xA1.
if (inRange(code_point, 0xFF61, 0xFF9F))
return [0x8E, code_point - 0xFF61 + 0xA1]
// 6. If code point is U+2212, set it to U+FF0D.
if (code_point === 0x2212)
code_point = 0xFF0D
// 7. Let pointer be the index pointer for code point in index
// jis0208.
const pointer = indexPointerFor(code_point, index('jis0208'))
// 8. If pointer is null, return error with code point.
if (pointer === null)
return encoderError(code_point)
// 9. Let lead be floor(pointer / 94) + 0xA1.
const lead = floor(pointer / 94) + 0xA1
// 10. Let trail be pointer % 94 + 0xA1.
const trail = pointer % 94 + 0xA1
// 11. Return two bytes whose values are lead and trail.
return [lead, trail]
}
}

View File

@ -1,124 +0,0 @@
import { inRange, decoderError, encoderError, isASCIICodePoint,
end_of_stream, finished, isASCIIByte, floor } from './text_decoder_utils.js'
import index, { indexCodePointFor, indexPointerFor } from './text_decoder_indexes.js'
//
// 14. Legacy multi-byte Korean encodings
//
// 14.1 euc-kr
// 14.1.1 euc-kr decoder
/**
* @implements {Decoder}
*/
export class EUCKRDecoder {
constructor(options) {
const { fatal } = options
this.fatal = fatal
// euc-kr's decoder has an associated euc-kr lead (initially 0x00).
this.euckr_lead = 0x00
}
/**
* @param {Stream} stream The stream of bytes being decoded.
* @param {number} bite The next byte read from the stream.
*/
handler(stream, bite) {
// 1. If byte is end-of-stream and euc-kr lead is not 0x00, set
// euc-kr lead to 0x00 and return error.
if (bite === end_of_stream && this.euckr_lead !== 0) {
this.euckr_lead = 0x00
return decoderError(this.fatal)
}
// 2. If byte is end-of-stream and euc-kr lead is 0x00, return
// finished.
if (bite === end_of_stream && this.euckr_lead === 0)
return finished
// 3. If euc-kr lead is not 0x00, let lead be euc-kr lead, let
// pointer be null, set euc-kr lead to 0x00, and then run these
// substeps:
if (this.euckr_lead !== 0x00) {
const lead = this.euckr_lead
let pointer = null
this.euckr_lead = 0x00
// 1. If byte is in the range 0x41 to 0xFE, inclusive, set
// pointer to (lead 0x81) × 190 + (byte 0x41).
if (inRange(bite, 0x41, 0xFE))
pointer = (lead - 0x81) * 190 + (bite - 0x41)
// 2. Let code point be null, if pointer is null, and the
// index code point for pointer in index euc-kr otherwise.
const code_point = (pointer === null)
? null : indexCodePointFor(pointer, index('euc-kr'))
// 3. If code point is null and byte is an ASCII byte, prepend
// byte to stream.
if (pointer === null && isASCIIByte(bite))
stream.prepend(bite)
// 4. If code point is null, return error.
if (code_point === null)
return decoderError(this.fatal)
// 5. Return a code point whose value is code point.
return code_point
}
// 4. If byte is an ASCII byte, return a code point whose value
// is byte.
if (isASCIIByte(bite))
return bite
// 5. If byte is in the range 0x81 to 0xFE, inclusive, set
// euc-kr lead to byte and return continue.
if (inRange(bite, 0x81, 0xFE)) {
this.euckr_lead = bite
return null
}
// 6. Return error.
return decoderError(this.fatal)
}
}
// 14.1.2 euc-kr encoder
/**
* @implements {Encoder}
*/
export class EUCKREncoder {
/**
* @param {Stream} stream Input stream.
* @param {number} code_point Next code point read from the stream.
* @return {(number|!Array.<number>)} Byte(s) to emit.
*/
handler(stream, code_point) {
// 1. If code point is end-of-stream, return finished.
if (code_point === end_of_stream)
return finished
// 2. If code point is an ASCII code point, return a byte whose
// value is code point.
if (isASCIICodePoint(code_point))
return code_point
// 3. Let pointer be the index pointer for code point in index
// euc-kr.
const pointer = indexPointerFor(code_point, index('euc-kr'))
// 4. If pointer is null, return error with code point.
if (pointer === null)
return encoderError(code_point)
// 5. Let lead be floor(pointer / 190) + 0x81.
const lead = floor(pointer / 190) + 0x81
// 6. Let trail be pointer % 190 + 0x41.
const trail = (pointer % 190) + 0x41
// 7. Return two bytes whose values are lead and trail.
return [lead, trail]
}
}

View File

@ -1,480 +0,0 @@
/*
* @File : ffm3u8_open.js.js
* @Author : jade
* @Date : 2024/2/5 16:06
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import { _ } from './cat.js';
import * as HLS from './hls.js';
let key = 'ffm3u8';
let url = '';
let categories = [];
let siteKey = '';
let siteType = 0;
async function request(reqUrl, agentSp) {
let res = await req(reqUrl, {
method: 'get',
});
return JSON.parse(res.content);
}
async function init(cfg) {
siteKey = cfg.skey;
siteType = cfg.stype;
url = cfg.ext.url;
categories = cfg.ext.categories;
}
async function home(filter) {
const data = await request(url);
let classes = [];
for (const cls of data.class) {
const n = cls.type_name.toString().trim();
if (categories && categories.length > 0) {
if (categories.indexOf(n) < 0) continue;
}
classes.push({
type_id: cls.type_id.toString(),
type_name: n,
});
}
if (categories && categories.length > 0) {
classes = _.sortBy(classes, (p) => {
return categories.indexOf(p.type_name);
});
}
return {
class: classes,
};
}
async function homeVod() {
return '{}';
}
async function category(tid, pg, filter, extend) {
let page = pg || 1;
if (page == 0) page = 1;
const data = await request(url + `?ac=detail&t=${tid}&pg=${page}`);
let videos = [];
for (const vod of data.list) {
videos.push({
vod_id: vod.vod_id.toString(),
vod_name: vod.vod_name.toString(),
vod_pic: vod.vod_pic,
vod_remarks: vod.vod_remarks,
});
}
return {
page: parseInt(data.page),
pagecount: data.pagecount,
total: data.total,
list: videos,
};
}
async function detail(id) {
const data = (await request(url + `?ac=detail&ids=${id}`)).list[0];
let vod = {
vod_id: data.vod_id,
vod_name: data.vod_name,
vod_pic: data.vod_pic,
type_name: data.type_name,
vod_year: data.vod_year,
vod_area: data.vod_area,
vod_remarks: data.vod_remarks,
vod_actor: data.vod_actor,
vod_director: data.vod_director,
vod_content: data.vod_content.trim(),
vod_play_from: data.vod_play_from,
vod_play_url: data.vod_play_url,
};
return {
list: [vod],
};
}
async function proxy(segments, headers, reqHeaders) {
let what = segments[0];
let segs = decodeURIComponent(segments[1]);
if (what == 'hls') {
function hlsHeader(data, hls) {
let hlsHeaders = {};
if (data.headers['content-length']) {
Object.assign(hlsHeaders, data.headers, { 'content-length': hls.length.toString() });
} else {
Object.assign(hlsHeaders, data.headers);
}
delete hlsHeaders['transfer-encoding'];
if (hlsHeaders['content-encoding'] == 'gzip') {
delete hlsHeaders['content-encoding'];
}
return hlsHeaders;
}
const hlsData = await hlsCache(segs, headers);
if (hlsData.variants) {
// variants -> variants -> .... ignore
const hls = HLS.stringify(hlsData.plist);
return {
code: hlsData.code,
content: hls,
headers: hlsHeader(hlsData, hls),
};
} else {
const hls = HLS.stringify(hlsData.plist, (segment) => {
return js2Proxy(false, siteType, siteKey, 'ts/' + encodeURIComponent(hlsData.key + '/' + segment.mediaSequenceNumber.toString()), headers);
});
return {
code: hlsData.code,
content: hls,
headers: hlsHeader(hlsData, hls),
};
}
} else if (what == 'ts') {
const info = segs.split('/');
const hlsKey = info[0];
const segIdx = parseInt(info[1]);
return await tsCache(hlsKey, segIdx, headers);
}
return '{}';
}
async function play(flag, id, flags) {
try {
const pUrls = await hls2Urls(id, {});
for (let index = 1; index < pUrls.length; index += 2) {
pUrls[index] = js2Proxy(false, siteType, siteKey, 'hls/' + encodeURIComponent(pUrls[index]), {});
}
pUrls.push('original');
pUrls.push(id);
return {
parse: 0,
url: pUrls,
};
} catch (e) {
return {
parse: 0,
url: id,
};
}
}
async function search(wd, quick, pg) {
let page = pg || 1;
if (page == 0) page = 1;
const data = await request(url + `?ac=detail&wd=${wd}`);
let videos = [];
for (const vod of data.list) {
videos.push({
vod_id: vod.vod_id.toString(),
vod_name: vod.vod_name.toString(),
vod_pic: vod.vod_pic,
vod_remarks: vod.vod_remarks,
});
}
return {
page: parseInt(data.page),
pagecount: data.pagecount,
total: data.total,
list: videos,
};
}
const cacheRoot = 'hls_cache';
const hlsKeys = [];
const hlsPlistCaches = {};
const interrupts = {};
const downloadTask = {};
let currentDownloadHlsKey = '';
function hlsCacheInsert(key, data) {
hlsKeys.push(key);
hlsPlistCaches[key] = data;
if (hlsKeys.length > 5) {
const rmKey = hlsKeys.shift();
hlsCacheRemove(rmKey);
}
}
function hlsCacheRemove(key) {
delete hlsPlistCaches[key];
delete hlsKeys[key];
new JSFile(cacheRoot + '/' + key).delete();
}
function plistUriResolve(baseUrl, plist) {
if (plist.variants) {
for (const v of plist.variants) {
if (!v.uri.startsWith('http')) {
v.uri = relative2Absolute(baseUrl, v.uri);
}
}
}
if (plist.segments) {
for (const s of plist.segments) {
if (!s.uri.startsWith('http')) {
s.uri = relative2Absolute(baseUrl, s.uri);
}
if (s.key && s.key.uri && !s.key.uri.startsWith('http')) {
s.key.uri = relative2Absolute(baseUrl, s.key.uri);
}
}
}
return plist;
}
async function hls2Urls(url, headers) {
let urls = [];
let resp = {};
let tmpUrl = url;
while (true) {
resp = await req(tmpUrl, {
headers: headers,
redirect: 0,
});
if (resp.headers['location']) {
tmpUrl = resp.headers['location'];
} else {
break;
}
}
if (resp.code == 200) {
var hls = resp.content;
const plist = plistUriResolve(tmpUrl, HLS.parse(hls));
if (plist.variants) {
for (const vari of _.sortBy(plist.variants, (v) => -1 * v.bandwidth)) {
urls.push(`proxy_${vari.resolution.width}x${vari.resolution.height}`);
urls.push(vari.uri);
}
} else {
urls.push('proxy');
urls.push(url);
const hlsKey = md5X(url);
hlsCacheInsert(hlsKey, {
code: resp.code,
plist: plist,
key: hlsKey,
headers: resp.headers,
});
}
}
return urls;
}
async function hlsCache(url, headers) {
const hlsKey = md5X(url);
if (hlsPlistCaches[hlsKey]) {
return hlsPlistCaches[hlsKey];
}
let resp = {};
let tmpUrl = url;
while (true) {
resp = await req(tmpUrl, {
headers: headers,
redirect: 0,
});
if (resp.headers['location']) {
tmpUrl = resp.headers['location'];
} else {
break;
}
}
if (resp.code == 200) {
var hls = resp.content;
const plist = plistUriResolve(tmpUrl, HLS.parse(hls));
hlsCacheInsert(hlsKey, {
code: resp.code,
plist: plist,
key: hlsKey,
headers: resp.headers,
});
return hlsPlistCaches[hlsKey];
}
return {};
}
async function tsCache(hlsKey, segmentIndex, headers) {
if (!hlsPlistCaches[hlsKey]) {
return {};
}
const plist = hlsPlistCaches[hlsKey].plist;
const segments = plist.segments;
let startFirst = !downloadTask[hlsKey];
if (startFirst) {
downloadTask[hlsKey] = {};
for (const seg of segments) {
const tk = md5X(seg.uri + seg.mediaSequenceNumber.toString());
downloadTask[hlsKey][tk] = {
file: cacheRoot + '/' + hlsKey + '/' + tk,
uri: seg.uri,
key: tk,
index: seg.mediaSequenceNumber,
order: seg.mediaSequenceNumber,
state: -1,
read: false,
};
}
}
// sort task
for (const tk in downloadTask[hlsKey]) {
const task = downloadTask[hlsKey][tk];
if (task.index >= segmentIndex) {
task.order = task.index - segmentIndex;
} else {
task.order = segments.length - segmentIndex + task.index;
}
}
if (startFirst) {
fixedCachePool(hlsKey, 5, headers);
}
const segment = segments[segmentIndex];
const tsKey = md5X(segment.uri + segment.mediaSequenceNumber.toString());
const task = downloadTask[hlsKey][tsKey];
if (task.state == 1 || task.state == -1) {
const file = new JSFile(task.file);
if (await file.exist()) {
task.state = 1;
// download finish
return {
buffer: 3,
code: 200,
headers: {
connection: 'close',
'content-type': 'video/mp2t',
},
content: file,
};
} else {
// file miss?? retry
task.state = -1;
}
}
if (task.state == -1) {
// start download
startTsTask(hlsKey, task, headers);
}
// wait read dwonload
if (task.state == 0) {
var stream = new JSProxyStream();
stream.head(200, {
connection: 'close',
'content-type': 'video/mp2t',
});
let downloaded = 0;
task.read = true;
new Promise(async function (resolve, reject) {
const f = new JSFile(task.file + '.dl');
await f.open('r');
(async function waitReadFile() {
const s = await f.size();
if (s > downloaded) {
var downloadBuf = await f.read(s - downloaded, downloaded);
await stream.write(downloadBuf);
downloaded = s;
}
if (task.state == 1 || task.state < 0) {
// finish error or done
stream.done();
await f.close();
await f.delete();
task.read = false;
resolve();
return;
}
setTimeout(waitReadFile, 5);
})();
});
return {
buffer: 3,
content: stream,
};
}
}
async function startTsTask(hlsKey, task, headers) {
if (task.state >= 0) return;
if (!interrupts[hlsKey]) {
return;
}
task.state = 0;
if (await new JSFile(task.file).exist()) {
task.state = 1;
return;
}
const file = new JSFile(task.file + '.dl');
await file.open('w');
const resp = await req(task.uri, {
buffer: 3,
headers: headers,
stream: file,
timeout: [5000, 10000],
});
if (resp.error || resp.code >= 300) {
await file.close();
if (!task.read) {
await file.delete();
}
task.state = -1;
return;
}
await file.close();
if (task.read) {
await file.copy(task.file);
} else {
await file.move(task.file);
}
task.state = 1;
}
async function fixedCachePool(hlsKey, limit, headers) {
// keep last cache task only
if (currentDownloadHlsKey && currentDownloadHlsKey != hlsKey) {
delete interrupts[currentDownloadHlsKey];
}
currentDownloadHlsKey = hlsKey;
interrupts[hlsKey] = true;
for (let index = 0; index < limit; index++) {
if (!interrupts[hlsKey]) break;
new Promise(function (resolve, reject) {
(async function doTask() {
if (!interrupts[hlsKey]) {
resolve();
return;
}
const tasks = _.pickBy(downloadTask[hlsKey], function (o) {
return o.state == -1;
});
const task = _.minBy(Object.values(tasks), function (o) {
return o.order;
});
if (!task) {
resolve();
return;
}
await startTsTask(hlsKey, task, headers);
setTimeout(doTask, 5);
})();
});
}
}
function relative2Absolute(base, relative) {
var stack = base.split('/'),
parts = relative.split('/');
stack.pop();
for (var i = 0; i < parts.length; i++) {
if (parts[i] == '.') continue;
if (parts[i] == '..') stack.pop();
else stack.push(parts[i]);
}
return stack.join('/');
}
export {hls2Urls,hlsCache,tsCache}

View File

@ -1,251 +0,0 @@
import { inRange, decoderError, encoderError, isASCIICodePoint,
end_of_stream, finished, isASCIIByte, floor } from './text_decoder_utils.js'
import index, {
indexGB18030RangesCodePointFor, indexGB18030RangesPointerFor,
indexCodePointFor, indexPointerFor } from './text_decoder_indexes.js'
// 11.2 gb18030
// 11.2.1 gb18030 decoder
/**
* @constructor
* @implements {Decoder}
* @param {{fatal: boolean}} options
*/
export class GB18030Decoder {
constructor(options) {
const { fatal } = options
this.fatal = fatal
// gb18030's decoder has an associated gb18030 first, gb18030
// second, and gb18030 third (all initially 0x00).
this.gb18030_first = 0x00
this.gb18030_second = 0x00,
this.gb18030_third = 0x00
}
/**
* @param {Stream} stream The stream of bytes being decoded.
* @param {number} bite The next byte read from the stream.
* @return The next code point(s) decoded, or null if not enough data exists in the input stream to decode a complete code point.
*/
handler(stream, bite) {
// 1. If byte is end-of-stream and gb18030 first, gb18030
// second, and gb18030 third are 0x00, return finished.
if (bite === end_of_stream && this.gb18030_first === 0x00 &&
this.gb18030_second === 0x00 && this.gb18030_third === 0x00) {
return finished
}
// 2. If byte is end-of-stream, and gb18030 first, gb18030
// second, or gb18030 third is not 0x00, set gb18030 first,
// gb18030 second, and gb18030 third to 0x00, and return error.
if (bite === end_of_stream &&
(this.gb18030_first !== 0x00 || this.gb18030_second !== 0x00 ||
this.gb18030_third !== 0x00)) {
this.gb18030_first = 0x00
this.gb18030_second = 0x00
this.gb18030_third = 0x00
decoderError(this.fatal)
}
var code_point
// 3. If gb18030 third is not 0x00, run these substeps:
if (this.gb18030_third !== 0x00) {
// 1. Let code point be null.
code_point = null
// 2. If byte is in the range 0x30 to 0x39, inclusive, set
// code point to the index gb18030 ranges code point for
// (((gb18030 first 0x81) × 10 + gb18030 second 0x30) ×
// 126 + gb18030 third 0x81) × 10 + byte 0x30.
if (inRange(bite, 0x30, 0x39)) {
code_point = indexGB18030RangesCodePointFor(
(((this.gb18030_first - 0x81) * 10 + this.gb18030_second - 0x30) * 126 +
this.gb18030_third - 0x81) * 10 + bite - 0x30)
}
// 3. Let buffer be a byte sequence consisting of gb18030
// second, gb18030 third, and byte, in order.
var buffer = [this.gb18030_second, this.gb18030_third, bite]
// 4. Set gb18030 first, gb18030 second, and gb18030 third to
// 0x00.
this.gb18030_first = 0x00
this.gb18030_second = 0x00
this.gb18030_third = 0x00
// 5. If code point is null, prepend buffer to stream and
// return error.
if (code_point === null) {
stream.prepend(buffer)
return decoderError(this.fatal)
}
// 6. Return a code point whose value is code point.
return code_point
}
// 4. If gb18030 second is not 0x00, run these substeps:
if (this.gb18030_second !== 0x00) {
// 1. If byte is in the range 0x81 to 0xFE, inclusive, set
// gb18030 third to byte and return continue.
if (inRange(bite, 0x81, 0xFE)) {
this.gb18030_third = bite
return null
}
// 2. Prepend gb18030 second followed by byte to stream, set
// gb18030 first and gb18030 second to 0x00, and return error.
stream.prepend([this.gb18030_second, bite])
this.gb18030_first = 0x00
this.gb18030_second = 0x00
return decoderError(this.fatal)
}
// 5. If gb18030 first is not 0x00, run these substeps:
if (this.gb18030_first !== 0x00) {
// 1. If byte is in the range 0x30 to 0x39, inclusive, set
// gb18030 second to byte and return continue.
if (inRange(bite, 0x30, 0x39)) {
this.gb18030_second = bite
return null
}
// 2. Let lead be gb18030 first, let pointer be null, and set
// gb18030 first to 0x00.
var lead = this.gb18030_first
var pointer = null
this.gb18030_first = 0x00
// 3. Let offset be 0x40 if byte is less than 0x7F and 0x41
// otherwise.
var offset = bite < 0x7F ? 0x40 : 0x41
// 4. If byte is in the range 0x40 to 0x7E, inclusive, or 0x80
// to 0xFE, inclusive, set pointer to (lead 0x81) × 190 +
// (byte offset).
if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0x80, 0xFE))
pointer = (lead - 0x81) * 190 + (bite - offset)
// 5. Let code point be null if pointer is null and the index
// code point for pointer in index gb18030 otherwise.
code_point = pointer === null ? null :
indexCodePointFor(pointer, index('gb18030'))
// 6. If code point is null and byte is an ASCII byte, prepend
// byte to stream.
if (code_point === null && isASCIIByte(bite))
stream.prepend(bite)
// 7. If code point is null, return error.
if (code_point === null)
return decoderError(this.fatal)
// 8. Return a code point whose value is code point.
return code_point
}
// 6. If byte is an ASCII byte, return a code point whose value
// is byte.
if (isASCIIByte(bite))
return bite
// 7. If byte is 0x80, return code point U+20AC.
if (bite === 0x80)
return 0x20AC
// 8. If byte is in the range 0x81 to 0xFE, inclusive, set
// gb18030 first to byte and return continue.
if (inRange(bite, 0x81, 0xFE)) {
this.gb18030_first = bite
return null
}
// 9. Return error.
return decoderError(this.fatal)
}
}
// 11.2.2 gb18030 encoder
/**
* @implements {Encoder}
*/
export class GB18030Encoder {
/**
* @param {Stream} stream Input stream.
* @param {number} code_point Next code point read from the stream.
* @return Byte(s) to emit.
*/
handler(stream, code_point) {
// 1. If code point is end-of-stream, return finished.
if (code_point === end_of_stream)
return finished
// 2. If code point is an ASCII code point, return a byte whose
// value is code point.
if (isASCIICodePoint(code_point))
return code_point
// 3. If code point is U+E5E5, return error with code point.
if (code_point === 0xE5E5)
return encoderError(code_point)
// 4. If the gbk flag is set and code point is U+20AC, return
// byte 0x80.
if (this.gbk_flag && code_point === 0x20AC)
return 0x80
// 5. Let pointer be the index pointer for code point in index
// gb18030.
var pointer = indexPointerFor(code_point, index('gb18030'))
// 6. If pointer is not null, run these substeps:
if (pointer !== null) {
// 1. Let lead be floor(pointer / 190) + 0x81.
var lead = floor(pointer / 190) + 0x81
// 2. Let trail be pointer % 190.
var trail = pointer % 190
// 3. Let offset be 0x40 if trail is less than 0x3F and 0x41 otherwise.
var offset = trail < 0x3F ? 0x40 : 0x41
// 4. Return two bytes whose values are lead and trail + offset.
return [lead, trail + offset]
}
// 7. If gbk flag is set, return error with code point.
if (this.gbk_flag)
return encoderError(code_point)
// 8. Set pointer to the index gb18030 ranges pointer for code
// point.
pointer = indexGB18030RangesPointerFor(code_point)
// 9. Let byte1 be floor(pointer / 10 / 126 / 10).
var byte1 = floor(pointer / 10 / 126 / 10)
// 10. Set pointer to pointer byte1 × 10 × 126 × 10.
pointer = pointer - byte1 * 10 * 126 * 10
// 11. Let byte2 be floor(pointer / 10 / 126).
var byte2 = floor(pointer / 10 / 126)
// 12. Set pointer to pointer byte2 × 10 × 126.
pointer = pointer - byte2 * 10 * 126
// 13. Let byte3 be floor(pointer / 10).
var byte3 = floor(pointer / 10)
// 14. Let byte4 be pointer byte3 × 10.
var byte4 = pointer - byte3 * 10
// 15. Return four bytes whose values are byte1 + 0x81, byte2 +
// 0x30, byte3 + 0x81, byte4 + 0x30.
return [byte1 + 0x81,
byte2 + 0x30,
byte3 + 0x81,
byte4 + 0x30]
}
constructor(options = {}, gbk_flag = false) {
// gb18030's decoder has an associated gbk flag (initially unset).
this.gbk_flag = gbk_flag
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,940 +0,0 @@
/*
* @File : hls.js.js
* @Author : jade
* @Date : 2024/2/5 16:07
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
let t = {};
function e(e) {
if (t.strictMode) throw e;
t.silent || console.error(e.message)
}
function s(t, ...s) {
for (const [i, n] of s.entries()) n || e(new Error(`${t} : Failed at [${i}]`))
}
function i(...t) {
for (const [s, [i, n]] of t.entries()) i && (n || e(new Error(`Conditional Assert : Failed at [${s}]`)))
}
function n(...t) {
for (const [s, i] of t.entries()) void 0 === i && e(new Error(`Param Check : Failed at [${s}]`))
}
function a(...t) {
for (const [s, [i, n]] of t.entries()) i && void 0 === n && e(new Error(`Conditional Param Check : Failed at [${s}]`))
}
function r(t) {
e(new Error(`Invalid Playlist : ${t}`))
}
function o(t, e = 10) {
if ("number" == typeof t) return t;
const s = 10 === e ? Number.parseFloat(t) : Number.parseInt(t, e);
return Number.isNaN(s) ? 0 : s
}
function E(t) {
(t.startsWith("0x") || t.startsWith("0X")) && (t = t.slice(2));
const e = new Uint8Array(t.length / 2);
for (let s = 0; s < t.length; s += 2) e[s / 2] = o(t.slice(s, s + 2), 16);
return e
}
function T(t, s = 0, i = t.length) {
i <= s && e(new Error(`end must be larger than start : start=${s}, end=${i}`));
const n = [];
for (let e = s; e < i; e++) n.push(`0${(255 & t[e]).toString(16).toUpperCase()}`.slice(-2));
return `0x${n.join("")}`
}
function u(t, e, s = 0) {
let i = -1;
for (let n = 0, a = 0; n < t.length; n++) if (t[n] === e) {
if (a++ === s) return [t.slice(0, n), t.slice(n + 1)];
i = n
}
return -1 !== i ? [t.slice(0, i), t.slice(i + 1)] : [t]
}
function c(t) {
const e = [];
let s = !1;
for (const i of t) "-" !== i && "_" !== i ? s ? (e.push(i.toUpperCase()), s = !1) : e.push(i.toLowerCase()) : s = !0;
return e.join("")
}
function l(t) {
return `${t.getUTCFullYear()}-${("0" + (t.getUTCMonth() + 1)).slice(-2)}-${("0" + t.getUTCDate()).slice(-2)}T${("0" + t.getUTCHours()).slice(-2)}:${("0" + t.getUTCMinutes()).slice(-2)}:${("0" + t.getUTCSeconds()).slice(-2)}.${("00" + t.getUTCMilliseconds()).slice(-3)}Z`
}
function h(e = {}) {
t = Object.assign(t, e)
}
function X() {
return Object.assign({}, t)
}
function p(t, e) {
e = Math.trunc(e) || 0;
const s = t.length >>> 0;
if (e < 0 && (e = s + e), !(e < 0 || e >= s)) return t[e]
}
class I {
constructor({
type: t,
uri: e,
groupId: s,
language: a,
assocLanguage: r,
name: o,
isDefault: E,
autoselect: T,
forced: u,
instreamId: c,
characteristics: l,
channels: h
}) {
n(t, s, o), i(["SUBTITLES" === t, e], ["CLOSED-CAPTIONS" === t, c], ["CLOSED-CAPTIONS" === t, !e], [u, "SUBTITLES" === t]), this.type = t, this.uri = e, this.groupId = s, this.language = a, this.assocLanguage = r, this.name = o, this.isDefault = E, this.autoselect = T, this.forced = u, this.instreamId = c, this.characteristics = l, this.channels = h
}
}
class N {
constructor({
uri: t,
isIFrameOnly: e = !1,
bandwidth: s,
averageBandwidth: i,
score: a,
codecs: r,
resolution: o,
frameRate: E,
hdcpLevel: T,
allowedCpc: u,
videoRange: c,
stableVariantId: l,
programId: h,
audio: X = [],
video: p = [],
subtitles: I = [],
closedCaptions: N = [],
currentRenditions: d = {audio: 0, video: 0, subtitles: 0, closedCaptions: 0}
}) {
n(t, s), this.uri = t, this.isIFrameOnly = e, this.bandwidth = s, this.averageBandwidth = i, this.score = a, this.codecs = r, this.resolution = o, this.frameRate = E, this.hdcpLevel = T, this.allowedCpc = u, this.videoRange = c, this.stableVariantId = l, this.programId = h, this.audio = X, this.video = p, this.subtitles = I, this.closedCaptions = N, this.currentRenditions = d
}
}
class d {
constructor({id: t, value: e, uri: i, language: a}) {
n(t, e || i), s("SessionData cannot have both value and uri, shoud be either.", !(e && i)), this.id = t, this.value = e, this.uri = i, this.language = a
}
}
class A {
constructor({method: t, uri: e, iv: s, format: r, formatVersion: o}) {
n(t), a(["NONE" !== t, e]), i(["NONE" === t, !(e || s || r || o)]), this.method = t, this.uri = e, this.iv = s, this.format = r, this.formatVersion = o
}
}
class f {
constructor({hint: t = !1, uri: e, mimeType: s, byterange: i}) {
n(e), this.hint = t, this.uri = e, this.mimeType = s, this.byterange = i
}
}
class S {
constructor({
id: t,
classId: e,
start: s,
end: r,
duration: o,
plannedDuration: E,
endOnNext: T,
attributes: u = {}
}) {
n(t), a([!0 === T, e]), i([r, s], [r, s <= r], [o, o >= 0], [E, E >= 0]), this.id = t, this.classId = e, this.start = s, this.end = r, this.duration = o, this.plannedDuration = E, this.endOnNext = T, this.attributes = u
}
}
class R {
constructor({type: t, duration: e, tagName: s, value: i}) {
n(t), a(["OUT" === t, e]), a(["RAW" === t, s]), this.type = t, this.duration = e, this.tagName = s, this.value = i
}
}
class m {
constructor(t) {
n(t), this.type = t
}
}
class g extends m {
constructor({isMasterPlaylist: t, uri: e, version: s, independentSegments: i = !1, start: a, source: r}) {
super("playlist"), n(t), this.isMasterPlaylist = t, this.uri = e, this.version = s, this.independentSegments = i, this.start = a, this.source = r
}
}
class O extends g {
constructor(t = {}) {
super(Object.assign(Object.assign({}, t), {isMasterPlaylist: !0}));
const {variants: e = [], currentVariant: s, sessionDataList: i = [], sessionKeyList: n = []} = t;
this.variants = e, this.currentVariant = s, this.sessionDataList = i, this.sessionKeyList = n
}
}
class D extends g {
constructor(t = {}) {
super(Object.assign(Object.assign({}, t), {isMasterPlaylist: !1}));
const {
targetDuration: e,
mediaSequenceBase: s = 0,
discontinuitySequenceBase: i = 0,
endlist: n = !1,
playlistType: a,
isIFrame: r,
segments: o = [],
prefetchSegments: E = [],
lowLatencyCompatibility: T,
partTargetDuration: u,
renditionReports: c = [],
skip: l = 0,
hash: h
} = t;
this.targetDuration = e, this.mediaSequenceBase = s, this.discontinuitySequenceBase = i, this.endlist = n, this.playlistType = a, this.isIFrame = r, this.segments = o, this.prefetchSegments = E, this.lowLatencyCompatibility = T, this.partTargetDuration = u, this.renditionReports = c, this.skip = l, this.hash = h
}
}
class P extends m {
constructor({
uri: t,
mimeType: e,
data: s,
duration: i,
title: n,
byterange: a,
discontinuity: r,
mediaSequenceNumber: o = 0,
discontinuitySequence: E = 0,
key: T,
map: u,
programDateTime: c,
dateRange: l,
markers: h = [],
parts: X = []
}) {
super("segment"), this.uri = t, this.mimeType = e, this.data = s, this.duration = i, this.title = n, this.byterange = a, this.discontinuity = r, this.mediaSequenceNumber = o, this.discontinuitySequence = E, this.key = T, this.map = u, this.programDateTime = c, this.dateRange = l, this.markers = h, this.parts = X
}
}
class y extends m {
constructor({hint: t = !1, uri: e, duration: s, independent: i, byterange: a, gap: r}) {
super("part"), n(e), this.hint = t, this.uri = e, this.duration = s, this.independent = i, this.duration = s, this.byterange = a, this.gap = r
}
}
class C extends m {
constructor({uri: t, discontinuity: e, mediaSequenceNumber: s = 0, discontinuitySequence: i = 0, key: a}) {
super("prefetch"), n(t), this.uri = t, this.discontinuity = e, this.mediaSequenceNumber = s, this.discontinuitySequence = i, this.key = a
}
}
class U {
constructor({uri: t, lastMSN: e, lastPart: s}) {
n(t), this.uri = t, this.lastMSN = e, this.lastPart = s
}
}
var M = Object.freeze({
__proto__: null,
Rendition: I,
Variant: N,
SessionData: d,
Key: A,
MediaInitializationSection: f,
DateRange: S,
SpliceInfo: R,
Playlist: g,
MasterPlaylist: O,
MediaPlaylist: D,
Segment: P,
PartialSegment: y,
PrefetchSegment: C,
RenditionReport: U
});
function b(t) {
return function (t, e = " ") {
return t ? (t = t.trim(), " " === e || (t.startsWith(e) && (t = t.slice(1)), t.endsWith(e) && (t = t.slice(0, -1))), t) : t
}(t, '"')
}
function L(t) {
const e = u(t, ",");
return {duration: o(e[0]), title: decodeURIComponent(escape(e[1]))}
}
function v(t) {
const e = u(t, "@");
return {length: o(e[0]), offset: e[1] ? o(e[1]) : -1}
}
function $(t) {
const e = u(t, "x");
return {width: o(e[0]), height: o(e[1])}
}
function Y(t) {
const e = "ALLOWED-CPC: Each entry must consit of KEYFORMAT and Content Protection Configuration", s = t.split(",");
0 === s.length && r(e);
const i = [];
for (const t of s) {
const [s, n] = u(t, ":");
s && n ? i.push({format: s, cpcList: n.split("/")}) : r(e)
}
return i
}
function F(t) {
const e = E(t);
return 16 !== e.length && r("IV must be a 128-bit unsigned integer"), e
}
function G(t, e) {
e.IV && t.compatibleVersion < 2 && (t.compatibleVersion = 2), (e.KEYFORMAT || e.KEYFORMATVERSIONS) && t.compatibleVersion < 5 && (t.compatibleVersion = 5)
}
function V(t) {
const e = {};
for (const i of function (t) {
const e = [];
let s = !0, i = 0;
const n = [];
for (let a = 0; a < t.length; a++) {
const r = t[a];
s && "," === r ? (e.push(t.slice(i, a).trim()), i = a + 1) : '"' !== r && "'" !== r || (s ? (n.push(r), s = !1) : r === p(n, -1) ? (n.pop(), s = !0) : n.push(r))
}
return e.push(t.slice(i).trim()), e
}(t)) {
const [t, n] = u(i, "="), a = b(n);
switch (t) {
case"URI":
e[t] = a;
break;
case"START-DATE":
case"END-DATE":
e[t] = new Date(a);
break;
case"IV":
e[t] = F(a);
break;
case"BYTERANGE":
e[t] = v(a);
break;
case"RESOLUTION":
e[t] = $(a);
break;
case"ALLOWED-CPC":
e[t] = Y(a);
break;
case"END-ON-NEXT":
case"DEFAULT":
case"AUTOSELECT":
case"FORCED":
case"PRECISE":
case"CAN-BLOCK-RELOAD":
case"INDEPENDENT":
case"GAP":
e[t] = "YES" === a;
break;
case"DURATION":
case"PLANNED-DURATION":
case"BANDWIDTH":
case"AVERAGE-BANDWIDTH":
case"FRAME-RATE":
case"TIME-OFFSET":
case"CAN-SKIP-UNTIL":
case"HOLD-BACK":
case"PART-HOLD-BACK":
case"PART-TARGET":
case"BYTERANGE-START":
case"BYTERANGE-LENGTH":
case"LAST-MSN":
case"LAST-PART":
case"SKIPPED-SEGMENTS":
case"SCORE":
case"PROGRAM-ID":
e[t] = o(a);
break;
default:
t.startsWith("SCTE35-") ? e[t] = E(a) : t.startsWith("X-") ? e[t] = (s = n).startsWith('"') ? b(s) : s.startsWith("0x") || s.startsWith("0X") ? E(s) : o(s) : ("VIDEO-RANGE" === t && "SDR" !== a && "HLG" !== a && "PQ" !== a && r(`VIDEO-RANGE: unknown value "${a}"`), e[t] = a)
}
}
var s;
return e
}
function w() {
r("The file contains both media and master playlist tags.")
}
function B(t, e, s) {
const i = function ({attributes: t}) {
return new I({
type: t.TYPE,
uri: t.URI,
groupId: t["GROUP-ID"],
language: t.LANGUAGE,
assocLanguage: t["ASSOC-LANGUAGE"],
name: t.NAME,
isDefault: t.DEFAULT,
autoselect: t.AUTOSELECT,
forced: t.FORCED,
instreamId: t["INSTREAM-ID"],
characteristics: t.CHARACTERISTICS,
channels: t.CHANNELS
})
}(e), n = t[c(s)], a = function (t, e) {
let s = !1;
for (const i of t) {
if (i.name === e.name) return "All EXT-X-MEDIA tags in the same Group MUST have different NAME attributes.";
i.isDefault && (s = !0)
}
return s && e.isDefault ? "EXT-X-MEDIA A Group MUST NOT have more than one member with a DEFAULT attribute of YES." : ""
}(n, i);
a && r(a), n.push(i), i.isDefault && (t.currentRenditions[c(s)] = n.length - 1)
}
function H(t, e, s, i, n) {
const a = new N({
uri: s,
bandwidth: e.BANDWIDTH,
averageBandwidth: e["AVERAGE-BANDWIDTH"],
score: e.SCORE,
codecs: e.CODECS,
resolution: e.RESOLUTION,
frameRate: e["FRAME-RATE"],
hdcpLevel: e["HDCP-LEVEL"],
allowedCpc: e["ALLOWED-CPC"],
videoRange: e["VIDEO-RANGE"],
stableVariantId: e["STABLE-VARIANT-ID"],
programId: e["PROGRAM-ID"]
});
for (const s of t) if ("EXT-X-MEDIA" === s.name) {
const t = s.attributes, i = t.TYPE;
if (i && t["GROUP-ID"] || r("EXT-X-MEDIA TYPE attribute is REQUIRED."), e[i] === t["GROUP-ID"] && (B(a, s, i), "CLOSED-CAPTIONS" === i)) for (const {instreamId: t} of a.closedCaptions) if (t && t.startsWith("SERVICE") && n.compatibleVersion < 7) {
n.compatibleVersion = 7;
break
}
}
return function (t, e, s) {
for (const i of ["AUDIO", "VIDEO", "SUBTITLES", "CLOSED-CAPTIONS"]) "CLOSED-CAPTIONS" === i && "NONE" === t[i] ? (s.isClosedCaptionsNone = !0, e.closedCaptions = []) : t[i] && !e[c(i)].some((e => e.groupId === t[i])) && r(`${i} attribute MUST match the value of the GROUP-ID attribute of an EXT-X-MEDIA tag whose TYPE attribute is ${i}.`)
}(e, a, n), a.isIFrameOnly = i, a
}
function K(t, e) {
if (t.method !== e.method) return !1;
if (t.uri !== e.uri) return !1;
if (t.iv) {
if (!e.iv) return !1;
if (t.iv.length !== e.iv.length) return !1;
for (let s = 0; s < t.iv.length; s++) if (t.iv[s] !== e.iv[s]) return !1
} else if (e.iv) return !1;
return t.format === e.format && t.formatVersion === e.formatVersion
}
function k(t, e, s, i, n, a, o) {
const E = new P({uri: e, mediaSequenceNumber: n, discontinuitySequence: a});
let T = !1, u = !1;
for (let e = s; e <= i; e++) {
const {name: s, value: i, attributes: n} = t[e];
if ("EXTINF" === s) !Number.isInteger(i.duration) && o.compatibleVersion < 3 && (o.compatibleVersion = 3), Math.round(i.duration) > o.targetDuration && r("EXTINF duration, when rounded to the nearest integer, MUST be less than or equal to the target duration"), E.duration = i.duration, E.title = i.title; else if ("EXT-X-BYTERANGE" === s) o.compatibleVersion < 4 && (o.compatibleVersion = 4), E.byterange = i; else if ("EXT-X-DISCONTINUITY" === s) E.parts.length > 0 && r("EXT-X-DISCONTINUITY must appear before the first EXT-X-PART tag of the Parent Segment."), E.discontinuity = !0; else if ("EXT-X-KEY" === s) E.parts.length > 0 && r("EXT-X-KEY must appear before the first EXT-X-PART tag of the Parent Segment."), G(o, n), E.key = new A({
method: n.METHOD,
uri: n.URI,
iv: n.IV,
format: n.KEYFORMAT,
formatVersion: n.KEYFORMATVERSIONS
}); else if ("EXT-X-MAP" === s) E.parts.length > 0 && r("EXT-X-MAP must appear before the first EXT-X-PART tag of the Parent Segment."), o.compatibleVersion < 5 && (o.compatibleVersion = 5), o.hasMap = !0, E.map = new f({
uri: n.URI,
byterange: n.BYTERANGE
}); else if ("EXT-X-PROGRAM-DATE-TIME" === s) E.programDateTime = i; else if ("EXT-X-DATERANGE" === s) {
const t = {};
for (const e of Object.keys(n)) (e.startsWith("SCTE35-") || e.startsWith("X-")) && (t[e] = n[e]);
E.dateRange = new S({
id: n.ID,
classId: n.CLASS,
start: n["START-DATE"],
end: n["END-DATE"],
duration: n.DURATION,
plannedDuration: n["PLANNED-DURATION"],
endOnNext: n["END-ON-NEXT"],
attributes: t
})
} else if ("EXT-X-CUE-OUT" === s) E.markers.push(new R({
type: "OUT",
duration: n && n.DURATION || i
})); else if ("EXT-X-CUE-IN" === s) E.markers.push(new R({type: "IN"})); else if ("EXT-X-CUE-OUT-CONT" === s || "EXT-X-CUE" === s || "EXT-OATCLS-SCTE35" === s || "EXT-X-ASSET" === s || "EXT-X-SCTE35" === s) E.markers.push(new R({
type: "RAW",
tagName: s,
value: i
})); else if ("EXT-X-PRELOAD-HINT" !== s || n.TYPE) if ("EXT-X-PRELOAD-HINT" === s && "PART" === n.TYPE && u) r("Servers should not add more than one EXT-X-PRELOAD-HINT tag with the same TYPE attribute to a Playlist."); else if ("EXT-X-PART" !== s && "EXT-X-PRELOAD-HINT" !== s || n.URI) {
if ("EXT-X-PRELOAD-HINT" === s && "MAP" === n.TYPE) T && r("Servers should not add more than one EXT-X-PRELOAD-HINT tag with the same TYPE attribute to a Playlist."), T = !0, o.hasMap = !0, E.map = new f({
hint: !0,
uri: n.URI,
byterange: {length: n["BYTERANGE-LENGTH"], offset: n["BYTERANGE-START"] || 0}
}); else if ("EXT-X-PART" === s || "EXT-X-PRELOAD-HINT" === s && "PART" === n.TYPE) {
"EXT-X-PART" !== s || n.DURATION || r("EXT-X-PART: DURATION attribute is mandatory"), "EXT-X-PRELOAD-HINT" === s && (u = !0);
const t = new y({
hint: "EXT-X-PRELOAD-HINT" === s,
uri: n.URI,
byterange: "EXT-X-PART" === s ? n.BYTERANGE : {
length: n["BYTERANGE-LENGTH"],
offset: n["BYTERANGE-START"] || 0
},
duration: n.DURATION,
independent: n.INDEPENDENT,
gap: n.GAP
});
E.parts.push(t)
}
} else r("EXT-X-PART / EXT-X-PRELOAD-HINT: URI attribute is mandatory"); else r("EXT-X-PRELOAD-HINT: TYPE attribute is mandatory")
}
return E
}
function W(t, e, s, i, n, a, o) {
const E = new C({uri: e, mediaSequenceNumber: n, discontinuitySequence: a});
for (let e = s; e <= i; e++) {
const {name: s, attributes: i} = t[e];
"EXTINF" === s ? r("A prefetch segment must not be advertised with an EXTINF tag.") : "EXT-X-DISCONTINUITY" === s ? r("A prefetch segment must not be advertised with an EXT-X-DISCONTINUITY tag.") : "EXT-X-PREFETCH-DISCONTINUITY" === s ? E.discontinuity = !0 : "EXT-X-KEY" === s ? (G(o, i), E.key = new A({
method: i.METHOD,
uri: i.URI,
iv: i.IV,
format: i.KEYFORMAT,
formatVersion: i.KEYFORMATVERSIONS
})) : "EXT-X-MAP" === s && r("Prefetch segments must not be advertised with an EXT-X-MAP tag.")
}
return E
}
function q(t, e) {
var s;
const i = new D;
let n = -1, a = 0, o = !1, E = !1, T = 0, u = null, c = null, l = !1;
for (const [s, h] of t.entries()) {
const {name: X, value: p, attributes: I, category: N} = h;
if ("Segment" !== N) {
if ("EXT-X-VERSION" === X) void 0 === i.version ? i.version = p : r("A Playlist file MUST NOT contain more than one EXT-X-VERSION tag."); else if ("EXT-X-TARGETDURATION" === X) i.targetDuration = e.targetDuration = p; else if ("EXT-X-MEDIA-SEQUENCE" === X) i.segments.length > 0 && r("The EXT-X-MEDIA-SEQUENCE tag MUST appear before the first Media Segment in the Playlist."), i.mediaSequenceBase = a = p; else if ("EXT-X-DISCONTINUITY-SEQUENCE" === X) i.segments.length > 0 && r("The EXT-X-DISCONTINUITY-SEQUENCE tag MUST appear before the first Media Segment in the Playlist."), o && r("The EXT-X-DISCONTINUITY-SEQUENCE tag MUST appear before any EXT-X-DISCONTINUITY tag."), i.discontinuitySequenceBase = T = p; else if ("EXT-X-ENDLIST" === X) i.endlist = !0; else if ("EXT-X-PLAYLIST-TYPE" === X) i.playlistType = p; else if ("EXT-X-I-FRAMES-ONLY" === X) e.compatibleVersion < 4 && (e.compatibleVersion = 4), i.isIFrame = !0; else if ("EXT-X-INDEPENDENT-SEGMENTS" === X) i.independentSegments && r("EXT-X-INDEPENDENT-SEGMENTS tag MUST NOT appear more than once in a Playlist"), i.independentSegments = !0; else if ("EXT-X-START" === X) i.start && r("EXT-X-START tag MUST NOT appear more than once in a Playlist"), "number" != typeof I["TIME-OFFSET"] && r("EXT-X-START: TIME-OFFSET attribute is REQUIRED"), i.start = {
offset: I["TIME-OFFSET"],
precise: I.PRECISE || !1
}; else if ("EXT-X-SERVER-CONTROL" === X) I["CAN-BLOCK-RELOAD"] || r("EXT-X-SERVER-CONTROL: CAN-BLOCK-RELOAD=YES is mandatory for Low-Latency HLS"), i.lowLatencyCompatibility = {
canBlockReload: I["CAN-BLOCK-RELOAD"],
canSkipUntil: I["CAN-SKIP-UNTIL"],
holdBack: I["HOLD-BACK"],
partHoldBack: I["PART-HOLD-BACK"]
}; else if ("EXT-X-PART-INF" === X) I["PART-TARGET"] || r("EXT-X-PART-INF: PART-TARGET attribute is mandatory"), i.partTargetDuration = I["PART-TARGET"]; else if ("EXT-X-RENDITION-REPORT" === X) I.URI || r("EXT-X-RENDITION-REPORT: URI attribute is mandatory"), 0 === I.URI.search(/^[a-z]+:/) && r("EXT-X-RENDITION-REPORT: URI must be relative to the playlist uri"), i.renditionReports.push(new U({
uri: I.URI,
lastMSN: I["LAST-MSN"],
lastPart: I["LAST-PART"]
})); else if ("EXT-X-SKIP" === X) I["SKIPPED-SEGMENTS"] || r("EXT-X-SKIP: SKIPPED-SEGMENTS attribute is mandatory"), e.compatibleVersion < 9 && (e.compatibleVersion = 9), i.skip = I["SKIPPED-SEGMENTS"], a += i.skip; else if ("EXT-X-PREFETCH" === X) {
const r = W(t, p, -1 === n ? s : n, s - 1, a++, T, e);
r && (r.discontinuity && (r.discontinuitySequence++, T = r.discontinuitySequence), r.key ? u = r.key : r.key = u, i.prefetchSegments.push(r)), E = !0, n = -1
} else if ("string" == typeof h) {
-1 === n && r("A URI line is not preceded by any segment tags"), i.targetDuration || r("The EXT-X-TARGETDURATION tag is REQUIRED"), E && r("These segments must appear after all complete segments.");
const o = k(t, h, n, s - 1, a++, T, e);
o && ([T, u, c] = x(i, o, T, u, c), !l && o.parts.length > 0 && (l = !0)), n = -1
}
} else -1 === n && (n = s), "EXT-X-DISCONTINUITY" === X && (o = !0)
}
if (-1 !== n) {
const o = k(t, "", n, t.length - 1, a++, T, e);
if (o) {
const {parts: t} = o;
t.length > 0 && !i.endlist && !(null === (s = p(t, -1)) || void 0 === s ? void 0 : s.hint) && r("If the Playlist contains EXT-X-PART tags and does not contain an EXT-X-ENDLIST tag, the Playlist must contain an EXT-X-PRELOAD-HINT tag with a TYPE=PART attribute"), x(i, o, u, c), !l && o.parts.length > 0 && (l = !0)
}
}
return function (t) {
const e = new Map, s = new Map;
let i = !1, n = !1;
for (let a = t.length - 1; a >= 0; a--) {
const {programDateTime: o, dateRange: E} = t[a];
if (o && (n = !0), E && E.start) {
i = !0, E.endOnNext && (E.end || E.duration) && r("An EXT-X-DATERANGE tag with an END-ON-NEXT=YES attribute MUST NOT contain DURATION or END-DATE attributes.");
const t = E.start.getTime(), n = E.duration || 0;
E.end && E.duration && t + 1e3 * n !== E.end.getTime() && r("END-DATE MUST be equal to the value of the START-DATE attribute plus the value of the DURATION"), E.endOnNext && (E.end = e.get(E.classId)), e.set(E.classId, E.start);
const a = E.end ? E.end.getTime() : E.start.getTime() + 1e3 * (E.duration || 0), o = s.get(E.classId);
if (o) {
for (const e of o) (e.start <= t && e.end > t || e.start >= t && e.start < a) && r("DATERANGE tags with the same CLASS should not overlap");
o.push({start: t, end: a})
} else E.classId && s.set(E.classId, [{start: t, end: a}])
}
}
i && !n && r("If a Playlist contains an EXT-X-DATERANGE tag, it MUST also contain at least one EXT-X-PROGRAM-DATE-TIME tag.")
}(i.segments), i.lowLatencyCompatibility && function ({
lowLatencyCompatibility: t,
targetDuration: e,
partTargetDuration: s,
segments: i,
renditionReports: n
}, a) {
const {canSkipUntil: o, holdBack: E, partHoldBack: T} = t;
o < 6 * e && r("The Skip Boundary must be at least six times the EXT-X-TARGETDURATION.");
E < 3 * e && r("HOLD-BACK must be at least three times the EXT-X-TARGETDURATION.");
if (a) {
void 0 === s && r("EXT-X-PART-INF is required if a Playlist contains one or more EXT-X-PART tags"), void 0 === T && r("EXT-X-PART: PART-HOLD-BACK attribute is mandatory"), T < s && r("PART-HOLD-BACK must be at least PART-TARGET");
for (const [t, {parts: e}] of i.entries()) {
e.length > 0 && t < i.length - 3 && r("Remove EXT-X-PART tags from the Playlist after they are greater than three target durations from the end of the Playlist.");
for (const [t, {duration: i}] of e.entries()) void 0 !== i && (i > s && r("PART-TARGET is the maximum duration of any Partial Segment"), t < e.length - 1 && i < .85 * s && r("All Partial Segments except the last part of a segment must have a duration of at least 85% of PART-TARGET"))
}
}
for (const t of n) {
const e = i.at(-1);
null !== t.lastMSN && void 0 !== t.lastMSN || (t.lastMSN = e.mediaSequenceNumber), (null === t.lastPart || void 0 === t.lastPart) && e.parts.length > 0 && (t.lastPart = e.parts.length - 1)
}
}(i, l), i
}
function x(t, e, s, i, n) {
const {discontinuity: a, key: o, map: E, byterange: T, uri: u} = e;
if (a && (e.discontinuitySequence = s + 1), o || (e.key = i), E || (e.map = n), T && -1 === T.offset) {
const {segments: e} = t;
if (e.length > 0) {
const t = p(e, -1);
t.byterange && t.uri === u ? T.offset = t.byterange.offset + t.byterange.length : r("If offset of EXT-X-BYTERANGE is not present, a previous Media Segment MUST be a sub-range of the same media resource")
} else r("If offset of EXT-X-BYTERANGE is not present, a previous Media Segment MUST appear in the Playlist file")
}
return t.segments.push(e), [e.discontinuitySequence, e.key, e.map]
}
function j(t, e) {
const [s, i] = function (t) {
const e = t.indexOf(":");
return -1 === e ? [t.slice(1).trim(), null] : [t.slice(1, e).trim(), t.slice(e + 1).trim()]
}(t), n = function (t) {
switch (t) {
case"EXTM3U":
case"EXT-X-VERSION":
return "Basic";
case"EXTINF":
case"EXT-X-BYTERANGE":
case"EXT-X-DISCONTINUITY":
case"EXT-X-PREFETCH-DISCONTINUITY":
case"EXT-X-KEY":
case"EXT-X-MAP":
case"EXT-X-PROGRAM-DATE-TIME":
case"EXT-X-DATERANGE":
case"EXT-X-CUE-OUT":
case"EXT-X-CUE-IN":
case"EXT-X-CUE-OUT-CONT":
case"EXT-X-CUE":
case"EXT-OATCLS-SCTE35":
case"EXT-X-ASSET":
case"EXT-X-SCTE35":
case"EXT-X-PART":
case"EXT-X-PRELOAD-HINT":
return "Segment";
case"EXT-X-TARGETDURATION":
case"EXT-X-MEDIA-SEQUENCE":
case"EXT-X-DISCONTINUITY-SEQUENCE":
case"EXT-X-ENDLIST":
case"EXT-X-PLAYLIST-TYPE":
case"EXT-X-I-FRAMES-ONLY":
case"EXT-X-SERVER-CONTROL":
case"EXT-X-PART-INF":
case"EXT-X-PREFETCH":
case"EXT-X-RENDITION-REPORT":
case"EXT-X-SKIP":
return "MediaPlaylist";
case"EXT-X-MEDIA":
case"EXT-X-STREAM-INF":
case"EXT-X-I-FRAME-STREAM-INF":
case"EXT-X-SESSION-DATA":
case"EXT-X-SESSION-KEY":
return "MasterPlaylist";
case"EXT-X-INDEPENDENT-SEGMENTS":
case"EXT-X-START":
return "MediaorMasterPlaylist";
default:
return "Unknown"
}
}(s);
if (function (t, e) {
if ("Segment" === t || "MediaPlaylist" === t) return void 0 === e.isMasterPlaylist ? void (e.isMasterPlaylist = !1) : void (e.isMasterPlaylist && w());
if ("MasterPlaylist" === t) {
if (void 0 === e.isMasterPlaylist) return void (e.isMasterPlaylist = !0);
!1 === e.isMasterPlaylist && w()
}
}(n, e), "Unknown" === n) return null;
"MediaPlaylist" === n && "EXT-X-RENDITION-REPORT" !== s && "EXT-X-PREFETCH" !== s && (e.hash[s] && r("There MUST NOT be more than one Media Playlist tag of each type in any Media Playlist"), e.hash[s] = !0);
const [a, E] = function (t, e) {
switch (t) {
case"EXTM3U":
case"EXT-X-DISCONTINUITY":
case"EXT-X-ENDLIST":
case"EXT-X-I-FRAMES-ONLY":
case"EXT-X-INDEPENDENT-SEGMENTS":
case"EXT-X-CUE-IN":
return [null, null];
case"EXT-X-VERSION":
case"EXT-X-TARGETDURATION":
case"EXT-X-MEDIA-SEQUENCE":
case"EXT-X-DISCONTINUITY-SEQUENCE":
return [o(e), null];
case"EXT-X-CUE-OUT":
return Number.isNaN(Number(e)) ? [null, V(e)] : [o(e), null];
case"EXT-X-KEY":
case"EXT-X-MAP":
case"EXT-X-DATERANGE":
case"EXT-X-MEDIA":
case"EXT-X-STREAM-INF":
case"EXT-X-I-FRAME-STREAM-INF":
case"EXT-X-SESSION-DATA":
case"EXT-X-SESSION-KEY":
case"EXT-X-START":
case"EXT-X-SERVER-CONTROL":
case"EXT-X-PART-INF":
case"EXT-X-PART":
case"EXT-X-PRELOAD-HINT":
case"EXT-X-RENDITION-REPORT":
case"EXT-X-SKIP":
return [null, V(e)];
case"EXTINF":
return [L(e), null];
case"EXT-X-BYTERANGE":
return [v(e), null];
case"EXT-X-PROGRAM-DATE-TIME":
return [new Date(e), null];
default:
return [e, null]
}
}(s, i);
return {name: s, category: n, value: a, attributes: E}
}
function Q(t, e) {
let s;
return e.isMasterPlaylist ? s = function (t, e) {
const s = new O;
let i = !1;
for (const [n, {
name: a,
value: o,
attributes: E
}] of t.entries()) if ("EXT-X-VERSION" === a) s.version = o; else if ("EXT-X-STREAM-INF" === a) {
const a = t[n + 1];
("string" != typeof a || a.startsWith("#EXT")) && r("EXT-X-STREAM-INF must be followed by a URI line");
const o = H(t, E, a, !1, e);
o && ("number" == typeof o.score && (i = !0, o.score < 0 && r("SCORE attribute on EXT-X-STREAM-INF must be positive decimal-floating-point number.")), s.variants.push(o))
} else if ("EXT-X-I-FRAME-STREAM-INF" === a) {
const i = H(t, E, E.URI, !0, e);
i && s.variants.push(i)
} else if ("EXT-X-SESSION-DATA" === a) {
const t = new d({id: E["DATA-ID"], value: E.VALUE, uri: E.URI, language: E.LANGUAGE});
s.sessionDataList.some((e => e.id === t.id && e.language === t.language)) && r("A Playlist MUST NOT contain more than one EXT-X-SESSION-DATA tag with the same DATA-ID attribute and the same LANGUAGE attribute."), s.sessionDataList.push(t)
} else if ("EXT-X-SESSION-KEY" === a) {
"NONE" === E.METHOD && r("EXT-X-SESSION-KEY: The value of the METHOD attribute MUST NOT be NONE");
const t = new A({
method: E.METHOD,
uri: E.URI,
iv: E.IV,
format: E.KEYFORMAT,
formatVersion: E.KEYFORMATVERSIONS
});
s.sessionKeyList.some((e => K(e, t))) && r("A Master Playlist MUST NOT contain more than one EXT-X-SESSION-KEY tag with the same METHOD, URI, IV, KEYFORMAT, and KEYFORMATVERSIONS attribute values."), G(e, E), s.sessionKeyList.push(t)
} else "EXT-X-INDEPENDENT-SEGMENTS" === a ? (s.independentSegments && r("EXT-X-INDEPENDENT-SEGMENTS tag MUST NOT appear more than once in a Playlist"), s.independentSegments = !0) : "EXT-X-START" === a && (s.start && r("EXT-X-START tag MUST NOT appear more than once in a Playlist"), "number" != typeof E["TIME-OFFSET"] && r("EXT-X-START: TIME-OFFSET attribute is REQUIRED"), s.start = {
offset: E["TIME-OFFSET"],
precise: E.PRECISE || !1
});
if (i) for (const t of s.variants) "number" != typeof t.score && r("If any Variant Stream contains the SCORE attribute, then all Variant Streams in the Master Playlist SHOULD have a SCORE attribute");
if (e.isClosedCaptionsNone) for (const t of s.variants) t.closedCaptions.length > 0 && r("If there is a variant with CLOSED-CAPTIONS attribute of NONE, all EXT-X-STREAM-INF tags MUST have this attribute with a value of NONE");
return s
}(t, e) : (s = q(t, e), !s.isIFrame && e.hasMap && e.compatibleVersion < 6 && (e.compatibleVersion = 6)), e.compatibleVersion > 1 && (!s.version || s.version < e.compatibleVersion) && r(`EXT-X-VERSION needs to be ${e.compatibleVersion} or higher.`), s
}
function _(t) {
const e = {
version: void 0,
isMasterPlaylist: void 0,
hasMap: !1,
targetDuration: 0,
compatibleVersion: 1,
isClosedCaptionsNone: !1,
hash: {}
}, s = function (t, e) {
const s = [];
for (const i of t.split("\n")) {
const t = i.trim();
if (t) if (t.startsWith("#")) {
if (t.startsWith("#EXT")) {
const i = j(t, e);
i && s.push(i)
}
} else s.push(t)
}
return 0 !== s.length && "EXTM3U" === s[0].name || r("The EXTM3U tag MUST be the first line."), s
}(t, e), i = Q(s, e);
return i.source = t, i
}
const z = ["#EXTINF", "#EXT-X-BYTERANGE", "#EXT-X-DISCONTINUITY", "#EXT-X-STREAM-INF", "#EXT-X-CUE-OUT", "#EXT-X-CUE-IN", "#EXT-X-KEY", "#EXT-X-MAP"],
Z = ["#EXT-X-MEDIA"];
class J extends Array {
constructor(t) {
super(), this.baseUri = t
}
push(...t) {
for (const e of t) if (e.startsWith("#")) if (z.some((t => e.startsWith(t)))) super.push(e); else {
if (this.includes(e)) {
if (Z.some((t => e.startsWith(t)))) continue;
r(`Redundant item (${e})`)
}
super.push(e)
} else super.push(e);
return this.length
}
}
function tt(t, e) {
let s = 1e3;
e && (s = Math.pow(10, e));
const i = Math.round(t * s) / s;
return e ? i.toFixed(e) : i
}
function et(t) {
const e = [`DATA-ID="${t.id}"`];
return t.language && e.push(`LANGUAGE="${t.language}"`), t.value ? e.push(`VALUE="${t.value}"`) : t.uri && e.push(`URI="${t.uri}"`), `#EXT-X-SESSION-DATA:${e.join(",")}`
}
function st(t, e) {
const s = e ? "#EXT-X-SESSION-KEY" : "#EXT-X-KEY", i = [`METHOD=${t.method}`];
return t.uri && i.push(`URI="${t.uri}"`), t.iv && (16 !== t.iv.length && r("IV must be a 128-bit unsigned integer"), i.push(`IV=${T(t.iv)}`)), t.format && i.push(`KEYFORMAT="${t.format}"`), t.formatVersion && i.push(`KEYFORMATVERSIONS="${t.formatVersion}"`), `${s}:${i.join(",")}`
}
function it(t, e) {
const s = e.isIFrameOnly ? "#EXT-X-I-FRAME-STREAM-INF" : "#EXT-X-STREAM-INF", i = [`BANDWIDTH=${e.bandwidth}`];
if (e.averageBandwidth && i.push(`AVERAGE-BANDWIDTH=${e.averageBandwidth}`), e.isIFrameOnly && i.push(`URI="${e.uri}"`), e.codecs && i.push(`CODECS="${e.codecs}"`), e.resolution && i.push(`RESOLUTION=${e.resolution.width}x${e.resolution.height}`), e.frameRate && i.push(`FRAME-RATE=${tt(e.frameRate, 3)}`), e.hdcpLevel && i.push(`HDCP-LEVEL=${e.hdcpLevel}`), e.audio.length > 0) {
i.push(`AUDIO="${e.audio[0].groupId}"`);
for (const s of e.audio) t.push(nt(s))
}
if (e.video.length > 0) {
i.push(`VIDEO="${e.video[0].groupId}"`);
for (const s of e.video) t.push(nt(s))
}
if (e.subtitles.length > 0) {
i.push(`SUBTITLES="${e.subtitles[0].groupId}"`);
for (const s of e.subtitles) t.push(nt(s))
}
if (X().allowClosedCaptionsNone && 0 === e.closedCaptions.length) i.push("CLOSED-CAPTIONS=NONE"); else if (e.closedCaptions.length > 0) {
i.push(`CLOSED-CAPTIONS="${e.closedCaptions[0].groupId}"`);
for (const s of e.closedCaptions) t.push(nt(s))
}
if (e.score && i.push(`SCORE=${e.score}`), e.allowedCpc) {
const t = [];
for (const {format: s, cpcList: i} of e.allowedCpc) t.push(`${s}:${i.join("/")}`);
i.push(`ALLOWED-CPC="${t.join(",")}"`)
}
e.videoRange && i.push(`VIDEO-RANGE=${e.videoRange}`), e.stableVariantId && i.push(`STABLE-VARIANT-ID="${e.stableVariantId}"`), e.programId && i.push(`PROGRAM-ID=${e.programId}`), t.push(`${s}:${i.join(",")}`), e.isIFrameOnly || t.push(`${e.uri}`)
}
function nt(t) {
const e = [`TYPE=${t.type}`, `GROUP-ID="${t.groupId}"`, `NAME="${t.name}"`];
return void 0 !== t.isDefault && e.push("DEFAULT=" + (t.isDefault ? "YES" : "NO")), void 0 !== t.autoselect && e.push("AUTOSELECT=" + (t.autoselect ? "YES" : "NO")), void 0 !== t.forced && e.push("FORCED=" + (t.forced ? "YES" : "NO")), t.language && e.push(`LANGUAGE="${t.language}"`), t.assocLanguage && e.push(`ASSOC-LANGUAGE="${t.assocLanguage}"`), t.instreamId && e.push(`INSTREAM-ID="${t.instreamId}"`), t.characteristics && e.push(`CHARACTERISTICS="${t.characteristics}"`), t.channels && e.push(`CHANNELS="${t.channels}"`), t.uri && e.push(`URI="${t.uri}"`), `#EXT-X-MEDIA:${e.join(",")}`
}
function at(t, e, s, i, n = 1, a = null) {
let r = !1, o = "";
if (e.discontinuity && t.push("#EXT-X-DISCONTINUITY"), e.key) {
const i = st(e.key);
i !== s && (t.push(i), s = i)
}
if (e.map) {
const s = function (t) {
const e = [`URI="${t.uri}"`];
t.byterange && e.push(`BYTERANGE="${rt(t.byterange)}"`);
return `#EXT-X-MAP:${e.join(",")}`
}(e.map);
s !== i && (t.push(s), i = s)
}
if (e.programDateTime && t.push(`#EXT-X-PROGRAM-DATE-TIME:${l(e.programDateTime)}`), e.dateRange && t.push(function (t) {
const e = [`ID="${t.id}"`];
t.start && e.push(`START-DATE="${l(t.start)}"`);
t.end && e.push(`END-DATE="${l(t.end)}"`);
t.duration && e.push(`DURATION=${t.duration}`);
t.plannedDuration && e.push(`PLANNED-DURATION=${t.plannedDuration}`);
t.classId && e.push(`CLASS="${t.classId}"`);
t.endOnNext && e.push("END-ON-NEXT=YES");
for (const s of Object.keys(t.attributes)) s.startsWith("X-") ? "number" == typeof t.attributes[s] ? e.push(`${s}=${t.attributes[s]}`) : e.push(`${s}="${t.attributes[s]}"`) : s.startsWith("SCTE35-") && e.push(`${s}=${T(t.attributes[s])}`);
return `#EXT-X-DATERANGE:${e.join(",")}`
}(e.dateRange)), e.markers.length > 0 && (o = function (t, e) {
let s = "";
for (const i of e) if ("OUT" === i.type) s = "OUT", t.push(`#EXT-X-CUE-OUT:DURATION=${i.duration}`); else if ("IN" === i.type) s = "IN", t.push("#EXT-X-CUE-IN"); else if ("RAW" === i.type) {
const e = i.value ? `:${i.value}` : "";
t.push(`#${i.tagName}${e}`)
}
return s
}(t, e.markers)), e.parts.length > 0 && (r = function (t, e) {
let s = !1;
for (const i of e) if (i.hint) {
const e = [];
if (e.push("TYPE=PART", `URI="${i.uri}"`), i.byterange) {
const {offset: t, length: s} = i.byterange;
e.push(`BYTERANGE-START=${t}`), s && e.push(`BYTERANGE-LENGTH=${s}`)
}
t.push(`#EXT-X-PRELOAD-HINT:${e.join(",")}`), s = !0
} else {
const e = [];
e.push(`DURATION=${i.duration}`, `URI="${i.uri}"`), i.byterange && e.push(`BYTERANGE=${rt(i.byterange)}`), i.independent && e.push("INDEPENDENT=YES"), i.gap && e.push("GAP=YES"), t.push(`#EXT-X-PART:${e.join(",")}`)
}
return s
}(t, e.parts)), r) return [s, i];
const E = n < 3 ? Math.round(e.duration) : tt(e.duration, function (t) {
const e = t.toString(10), s = e.indexOf(".");
return -1 === s ? 0 : e.length - s - 1
}(e.duration));
return t.push(`#EXTINF:${E},${unescape(encodeURIComponent(e.title || ""))}`), e.byterange && t.push(`#EXT-X-BYTERANGE:${rt(e.byterange)}`), null != a ? Array.prototype.push.call(t, a(e)) : Array.prototype.push.call(t, `${e.uri}`), [s, i, o]
}
function rt({offset: t, length: e}) {
return `${e}@${t}`
}
function ot(t, e = null) {
n(t), s("Not a playlist", "playlist" === t.type);
const i = new J(t.uri);
return i.push("#EXTM3U"), t.version && i.push(`#EXT-X-VERSION:${t.version}`), t.independentSegments && i.push("#EXT-X-INDEPENDENT-SEGMENTS"), t.start && i.push(`#EXT-X-START:TIME-OFFSET=${tt(t.start.offset)}${t.start.precise ? ",PRECISE=YES" : ""}`), t.isMasterPlaylist ? function (t, e) {
for (const s of e.sessionDataList) t.push(et(s));
for (const s of e.sessionKeyList) t.push(st(s, !0));
for (const s of e.variants) it(t, s)
}(i, t) : function (t, e, s = null) {
let i = "", n = "", a = !1;
if (e.targetDuration && t.push(`#EXT-X-TARGETDURATION:${e.targetDuration}`), e.lowLatencyCompatibility) {
const {canBlockReload: s, canSkipUntil: i, holdBack: n, partHoldBack: a} = e.lowLatencyCompatibility,
r = [];
r.push("CAN-BLOCK-RELOAD=" + (s ? "YES" : "NO")), void 0 !== i && r.push(`CAN-SKIP-UNTIL=${i}`), void 0 !== n && r.push(`HOLD-BACK=${n}`), void 0 !== a && r.push(`PART-HOLD-BACK=${a}`), t.push(`#EXT-X-SERVER-CONTROL:${r.join(",")}`)
}
e.partTargetDuration && t.push(`#EXT-X-PART-INF:PART-TARGET=${e.partTargetDuration}`), e.mediaSequenceBase && t.push(`#EXT-X-MEDIA-SEQUENCE:${e.mediaSequenceBase}`), e.discontinuitySequenceBase && t.push(`#EXT-X-DISCONTINUITY-SEQUENCE:${e.discontinuitySequenceBase}`), e.playlistType && t.push(`#EXT-X-PLAYLIST-TYPE:${e.playlistType}`), e.isIFrame && t.push("#EXT-X-I-FRAMES-ONLY"), e.skip > 0 && t.push(`#EXT-X-SKIP:SKIPPED-SEGMENTS=${e.skip}`);
for (const r of e.segments) {
let o = "";
[i, n, o] = at(t, r, i, n, e.version, s), "OUT" === o ? a = !0 : "IN" === o && a && (a = !1)
}
"VOD" === e.playlistType && a && t.push("#EXT-X-CUE-IN"), e.prefetchSegments.length > 2 && r("The server must deliver no more than two prefetch segments");
for (const s of e.prefetchSegments) s.discontinuity && t.push("#EXT-X-PREFETCH-DISCONTINUITY"), t.push(`#EXT-X-PREFETCH:${s.uri}`);
e.endlist && t.push("#EXT-X-ENDLIST");
for (const s of e.renditionReports) {
const e = [];
e.push(`URI="${s.uri}"`, `LAST-MSN=${s.lastMSN}`), void 0 !== s.lastPart && e.push(`LAST-PART=${s.lastPart}`), t.push(`#EXT-X-RENDITION-REPORT:${e.join(",")}`)
}
}(i, t, e), i.join("\n")
}
export {X as getOptions, _ as parse, h as setOptions, ot as stringify, M as types};

View File

@ -1,441 +0,0 @@
import { inRange, decoderError, encoderError, isASCIICodePoint,
end_of_stream, finished, floor } from './text_decoder_utils.js'
import index, { indexCodePointFor, indexPointerFor } from './text_decoder_indexes.js'
// 13.2 iso-2022-jp
// 13.2.1 iso-2022-jp decoder
/**
* @implements {Decoder}
*/
export class ISO2022JPDecoder {
constructor(options) {
const { fatal } = options
this.fatal = fatal
/** @enum */
this.states = {
ASCII: 0,
Roman: 1,
Katakana: 2,
LeadByte: 3,
TrailByte: 4,
EscapeStart: 5,
Escape: 6,
}
// iso-2022-jp's decoder has an associated iso-2022-jp decoder
// state (initially ASCII), iso-2022-jp decoder output state
// (initially ASCII), iso-2022-jp lead (initially 0x00), and
// iso-2022-jp output flag (initially unset).
this.iso2022jp_decoder_state = this.states.ASCII
this.iso2022jp_decoder_output_state = this.states.ASCII,
this.iso2022jp_lead = 0x00
this.iso2022jp_output_flag = false
}
/**
* @param {Stream} stream The stream of bytes being decoded.
* @param {number} bite The next byte read from the stream.
*/
handler(stream, bite) {
// switching on iso-2022-jp decoder state:
switch (this.iso2022jp_decoder_state) {
default:
case this.states.ASCII:
// ASCII
// Based on byte:
// 0x1B
if (bite === 0x1B) {
// Set iso-2022-jp decoder state to escape start and return
// continue.
this.iso2022jp_decoder_state = this.states.EscapeStart
return null
}
// 0x00 to 0x7F, excluding 0x0E, 0x0F, and 0x1B
if (inRange(bite, 0x00, 0x7F) && bite !== 0x0E
&& bite !== 0x0F && bite !== 0x1B) {
// Unset the iso-2022-jp output flag and return a code point
// whose value is byte.
this.iso2022jp_output_flag = false
return bite
}
// end-of-stream
if (bite === end_of_stream) {
// Return finished.
return finished
}
// Otherwise
// Unset the iso-2022-jp output flag and return error.
this.iso2022jp_output_flag = false
return decoderError(this.fatal)
case this.states.Roman:
// Roman
// Based on byte:
// 0x1B
if (bite === 0x1B) {
// Set iso-2022-jp decoder state to escape start and return
// continue.
this.iso2022jp_decoder_state = this.states.EscapeStart
return null
}
// 0x5C
if (bite === 0x5C) {
// Unset the iso-2022-jp output flag and return code point
// U+00A5.
this.iso2022jp_output_flag = false
return 0x00A5
}
// 0x7E
if (bite === 0x7E) {
// Unset the iso-2022-jp output flag and return code point
// U+203E.
this.iso2022jp_output_flag = false
return 0x203E
}
// 0x00 to 0x7F, excluding 0x0E, 0x0F, 0x1B, 0x5C, and 0x7E
if (inRange(bite, 0x00, 0x7F) && bite !== 0x0E && bite !== 0x0F
&& bite !== 0x1B && bite !== 0x5C && bite !== 0x7E) {
// Unset the iso-2022-jp output flag and return a code point
// whose value is byte.
this.iso2022jp_output_flag = false
return bite
}
// end-of-stream
if (bite === end_of_stream) {
// Return finished.
return finished
}
// Otherwise
// Unset the iso-2022-jp output flag and return error.
this.iso2022jp_output_flag = false
return decoderError(this.fatal)
case this.states.Katakana:
// Katakana
// Based on byte:
// 0x1B
if (bite === 0x1B) {
// Set iso-2022-jp decoder state to escape start and return
// continue.
this.iso2022jp_decoder_state = this.states.EscapeStart
return null
}
// 0x21 to 0x5F
if (inRange(bite, 0x21, 0x5F)) {
// Unset the iso-2022-jp output flag and return a code point
// whose value is 0xFF61 0x21 + byte.
this.iso2022jp_output_flag = false
return 0xFF61 - 0x21 + bite
}
// end-of-stream
if (bite === end_of_stream) {
// Return finished.
return finished
}
// Otherwise
// Unset the iso-2022-jp output flag and return error.
this.iso2022jp_output_flag = false
return decoderError(this.fatal)
case this.states.LeadByte:
// Lead byte
// Based on byte:
// 0x1B
if (bite === 0x1B) {
// Set iso-2022-jp decoder state to escape start and return
// continue.
this.iso2022jp_decoder_state = this.states.EscapeStart
return null
}
// 0x21 to 0x7E
if (inRange(bite, 0x21, 0x7E)) {
// Unset the iso-2022-jp output flag, set iso-2022-jp lead
// to byte, iso-2022-jp decoder state to trail byte, and
// return continue.
this.iso2022jp_output_flag = false
this.iso2022jp_lead = bite
this.iso2022jp_decoder_state = this.states.TrailByte
return null
}
// end-of-stream
if (bite === end_of_stream) {
// Return finished.
return finished
}
// Otherwise
// Unset the iso-2022-jp output flag and return error.
this.iso2022jp_output_flag = false
return decoderError(this.fatal)
case this.states.TrailByte:
// Trail byte
// Based on byte:
// 0x1B
if (bite === 0x1B) {
// Set iso-2022-jp decoder state to escape start and return
// continue.
this.iso2022jp_decoder_state = this.states.EscapeStart
return decoderError(this.fatal)
}
// 0x21 to 0x7E
if (inRange(bite, 0x21, 0x7E)) {
// 1. Set the iso-2022-jp decoder state to lead byte.
this.iso2022jp_decoder_state = this.states.LeadByte
// 2. Let pointer be (iso-2022-jp lead 0x21) × 94 + byte 0x21.
const pointer = (this.iso2022jp_lead - 0x21) * 94 + bite - 0x21
// 3. Let code point be the index code point for pointer in
// index jis0208.
const code_point = indexCodePointFor(pointer, index('jis0208'))
// 4. If code point is null, return error.
if (code_point === null)
return decoderError(this.fatal)
// 5. Return a code point whose value is code point.
return code_point
}
// end-of-stream
if (bite === end_of_stream) {
// Set the iso-2022-jp decoder state to lead byte, prepend
// byte to stream, and return error.
this.iso2022jp_decoder_state = this.states.LeadByte
stream.prepend(bite)
return decoderError(this.fatal)
}
// Otherwise
// Set iso-2022-jp decoder state to lead byte and return
// error.
this.iso2022jp_decoder_state = this.states.LeadByte
return decoderError(this.fatal)
case this.states.EscapeStart:
// Escape start
// 1. If byte is either 0x24 or 0x28, set iso-2022-jp lead to
// byte, iso-2022-jp decoder state to escape, and return
// continue.
if (bite === 0x24 || bite === 0x28) {
this.iso2022jp_lead = bite
this.iso2022jp_decoder_state = this.states.Escape
return null
}
// 2. Prepend byte to stream.
stream.prepend(bite)
// 3. Unset the iso-2022-jp output flag, set iso-2022-jp
// decoder state to iso-2022-jp decoder output state, and
// return error.
this.iso2022jp_output_flag = false
this.iso2022jp_decoder_state = this.iso2022jp_decoder_output_state
return decoderError(this.fatal)
case this.states.Escape: {
// Escape
// 1. Let lead be iso-2022-jp lead and set iso-2022-jp lead to
// 0x00.
const lead = this.iso2022jp_lead
this.iso2022jp_lead = 0x00
// 2. Let state be null.
let state = null
// 3. If lead is 0x28 and byte is 0x42, set state to ASCII.
if (lead === 0x28 && bite === 0x42)
state = this.states.ASCII
// 4. If lead is 0x28 and byte is 0x4A, set state to Roman.
if (lead === 0x28 && bite === 0x4A)
state = this.states.Roman
// 5. If lead is 0x28 and byte is 0x49, set state to Katakana.
if (lead === 0x28 && bite === 0x49)
state = this.states.Katakana
// 6. If lead is 0x24 and byte is either 0x40 or 0x42, set
// state to lead byte.
if (lead === 0x24 && (bite === 0x40 || bite === 0x42))
state = this.states.LeadByte
// 7. If state is non-null, run these substeps:
if (state !== null) {
// 1. Set iso-2022-jp decoder state and iso-2022-jp decoder
// output state to this.states.
this.iso2022jp_decoder_state = this.iso2022jp_decoder_state = state
// 2. Let output flag be the iso-2022-jp output flag.
const output_flag = this.iso2022jp_output_flag
// 3. Set the iso-2022-jp output flag.
this.iso2022jp_output_flag = true
// 4. Return continue, if output flag is unset, and error
// otherwise.
return !output_flag ? null : decoderError(this.fatal)
}
// 8. Prepend lead and byte to stream.
stream.prepend([lead, bite])
// 9. Unset the iso-2022-jp output flag, set iso-2022-jp
// decoder state to iso-2022-jp decoder output state and
// return error.
this.iso2022jp_output_flag = false
this.iso2022jp_decoder_state = this.iso2022jp_decoder_output_state
return decoderError(this.fatal)
}
}
}
}
// 13.2.2 iso-2022-jp encoder
/**
* @implements {Encoder}
*/
export class ISO2022JPEncoder {
constructor() {
// iso-2022-jp's encoder has an associated iso-2022-jp encoder
// state which is one of ASCII, Roman, and jis0208 (initially
// ASCII).
/** @enum */
this.states = {
ASCII: 0,
Roman: 1,
jis0208: 2,
}
this.iso2022jp_state = this.states.ASCII
}
/**
* @param {Stream} stream Input stream.
* @param {number} code_point Next code point read from the stream.
*/
handler(stream, code_point) {
// 1. If code point is end-of-stream and iso-2022-jp encoder
// state is not ASCII, prepend code point to stream, set
// iso-2022-jp encoder state to ASCII, and return three bytes
// 0x1B 0x28 0x42.
if (code_point === end_of_stream &&
this.iso2022jp_state !== this.states.ASCII) {
stream.prepend(code_point)
this.iso2022jp_state = this.states.ASCII
return [0x1B, 0x28, 0x42]
}
// 2. If code point is end-of-stream and iso-2022-jp encoder
// state is ASCII, return finished.
if (code_point === end_of_stream && this.iso2022jp_state === this.states.ASCII)
return finished
// 3. If ISO-2022-JP encoder state is ASCII or Roman, and code
// point is U+000E, U+000F, or U+001B, return error with U+FFFD.
if ((this.iso2022jp_state === this.states.ASCII ||
this.iso2022jp_state === this.states.Roman) &&
(code_point === 0x000E || code_point === 0x000F ||
code_point === 0x001B)) {
return encoderError(0xFFFD)
}
// 4. If iso-2022-jp encoder state is ASCII and code point is an
// ASCII code point, return a byte whose value is code point.
if (this.iso2022jp_state === this.states.ASCII &&
isASCIICodePoint(code_point))
return code_point
// 5. If iso-2022-jp encoder state is Roman and code point is an
// ASCII code point, excluding U+005C and U+007E, or is U+00A5
// or U+203E, run these substeps:
if (this.iso2022jp_state === this.states.Roman &&
((isASCIICodePoint(code_point) &&
code_point !== 0x005C && code_point !== 0x007E) ||
(code_point == 0x00A5 || code_point == 0x203E))) {
// 1. If code point is an ASCII code point, return a byte
// whose value is code point.
if (isASCIICodePoint(code_point))
return code_point
// 2. If code point is U+00A5, return byte 0x5C.
if (code_point === 0x00A5)
return 0x5C
// 3. If code point is U+203E, return byte 0x7E.
if (code_point === 0x203E)
return 0x7E
}
// 6. If code point is an ASCII code point, and iso-2022-jp
// encoder state is not ASCII, prepend code point to stream, set
// iso-2022-jp encoder state to ASCII, and return three bytes
// 0x1B 0x28 0x42.
if (isASCIICodePoint(code_point) &&
this.iso2022jp_state !== this.states.ASCII) {
stream.prepend(code_point)
this.iso2022jp_state = this.states.ASCII
return [0x1B, 0x28, 0x42]
}
// 7. If code point is either U+00A5 or U+203E, and iso-2022-jp
// encoder state is not Roman, prepend code point to stream, set
// iso-2022-jp encoder state to Roman, and return three bytes
// 0x1B 0x28 0x4A.
if ((code_point === 0x00A5 || code_point === 0x203E) &&
this.iso2022jp_state !== this.states.Roman) {
stream.prepend(code_point)
this.iso2022jp_state = this.states.Roman
return [0x1B, 0x28, 0x4A]
}
// 8. If code point is U+2212, set it to U+FF0D.
if (code_point === 0x2212)
code_point = 0xFF0D
// 9. Let pointer be the index pointer for code point in index
// jis0208.
const pointer = indexPointerFor(code_point, index('jis0208'))
// 10. If pointer is null, return error with code point.
if (pointer === null)
return encoderError(code_point)
// 11. If iso-2022-jp encoder state is not jis0208, prepend code
// point to stream, set iso-2022-jp encoder state to jis0208,
// and return three bytes 0x1B 0x24 0x42.
if (this.iso2022jp_state !== this.states.jis0208) {
stream.prepend(code_point)
this.iso2022jp_state = this.states.jis0208
return [0x1B, 0x24, 0x42]
}
// 12. Let lead be floor(pointer / 94) + 0x21.
const lead = floor(pointer / 94) + 0x21
// 13. Let trail be pointer % 94 + 0x21.
const trail = pointer % 94 + 0x21
// 14. Return two bytes whose values are lead and trail.
return [lead, trail]
}
}

View File

@ -1,86 +0,0 @@
const level_list = ["DEBUG", "INFO", "WARNING", "ERROR"];
const file_path = "log"
class JadeLogging {
constructor(app_name, level = "DEBUG") {
this.app_name = app_name
this.level = level
this.level_index = level_list.indexOf(level)
}
format(level, message) {
let max_format = 80
switch (level) {
case "INFO":
max_format = max_format + 1
break
case "WARNING":
max_format = max_format - 2
break
default :
break
}
if (message.length < max_format) {
if ((max_format - message.length) % 2 === 0) {
message = "#".repeat(Math.floor((max_format - message.length) / 2)) + message + "#".repeat(Math.floor((max_format - message.length) / 2))
} else {
message = "#".repeat(Math.floor((max_format - message.length) / 2)) + message + "#".repeat(Math.floor((max_format - message.length) / 2) + 1)
}
}
return message
}
getTime() {
const timestamp = new Date();
// 获取当前时间戳
return timestamp.toLocaleDateString().replace(/\//g, "-") + " " + timestamp.toTimeString().substr(0, 8) + "," + timestamp.getMilliseconds().toString()
}
formatMessage(log_level, message, is_format) {
// 获取北京时间
// 格式化消息
//2023-12-13 15:15:21,409 - 阿里玩偶 -
//2023-12-14T01:43:31.278Z
//2023-12-13 15:15:21,409 - 阿里玩偶 - INFO:
//2023-12-13 15:15:21,409 - 阿里玩偶 - ERROR:
if (is_format) {
message = this.format(log_level, message)
}
return `${this.getTime()} - ${this.app_name} - ${log_level}: ${message}`
}
async log(message) {
console.debug(message)
await local.set(file_path,this.getTime(), message);
}
async info(message, is_format=false) {
if (this.level_index <= 1) {
await this.log(this.formatMessage("INFO", message, is_format))
}
}
async warning(message, is_format=false) {
if (this.level_index <= 2) {
await this.log(this.formatMessage("WARNING", message, is_format))
}
}
async error(message, is_format=false) {
if (this.level_index <= 3) {
await this.log(this.formatMessage("ERROR", message, is_format))
}
}
async debug(message, is_format=false) {
if (this.level_index <= 0) {
await this.log(this.formatMessage("DEBUG", message, is_format))
}
}
}
// 测试日志记录函数
export {JadeLogging}

View File

@ -1,129 +0,0 @@
var charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789';
export function rand(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
export function randStr(len, withNum, onlyNum) {
var _str = '';
let containsNum = withNum === undefined ? true : withNum;
for (var i = 0; i < len; i++) {
let idx = onlyNum ? rand(charStr.length - 10, charStr.length - 1) : rand(0, containsNum ? charStr.length - 1 : charStr.length - 11);
_str += charStr[idx];
}
return _str;
}
export function randUUID() {
return randStr(8).toLowerCase() + '-' + randStr(4).toLowerCase() + '-' + randStr(4).toLowerCase() + '-' + randStr(4).toLowerCase() + '-' + randStr(12).toLowerCase();
}
export function randMAC() {
return randStr(2).toUpperCase() + ':' + randStr(2).toUpperCase() + ':' + randStr(2).toUpperCase() + ':' + randStr(2).toUpperCase() + ':' + randStr(2).toUpperCase() + ':' + randStr(2).toUpperCase();
}
const deviceBrands = ['Huawei', 'Xiaomi'];
const deviceModels = [
['MHA-AL00', 'HUAWEI Mate 9', 'MHA-TL00', 'HUAWEI Mate 9', 'LON-AL00', 'HUAWEI Mate 9 Pro', 'ALP-AL00', 'HUAWEI Mate 10', 'ALP-TL00', 'HUAWEI Mate 10', 'BLA-AL00', 'HUAWEI Mate 10 Pro', 'BLA-TL00', 'HUAWEI Mate 10 Pro', 'HMA-AL00', 'HUAWEI Mate 20', 'HMA-TL00', 'HUAWEI Mate 20', 'LYA-AL00', 'HUAWEI Mate 20 Pro', 'LYA-AL10', 'HUAWEI Mate 20 Pro', 'LYA-TL00', 'HUAWEI Mate 20 Pro', 'EVR-AL00', 'HUAWEI Mate 20 X', 'EVR-TL00', 'HUAWEI Mate 20 X', 'EVR-AN00', 'HUAWEI Mate 20 X', 'TAS-AL00', 'HUAWEI Mate 30', 'TAS-TL00', 'HUAWEI Mate 30', 'TAS-AN00', 'HUAWEI Mate 30', 'TAS-TN00', 'HUAWEI Mate 30', 'LIO-AL00', 'HUAWEI Mate 30 Pro', 'LIO-TL00', 'HUAWEI Mate 30 Pro', 'LIO-AN00', 'HUAWEI Mate 30 Pro', 'LIO-TN00', 'HUAWEI Mate 30 Pro', 'LIO-AN00m', 'HUAWEI Mate 30E Pro', 'OCE-AN10', 'HUAWEI Mate 40', 'OCE-AN50', 'HUAWEI Mate 40E', 'OCE-AL50', 'HUAWEI Mate 40E', 'NOH-AN00', 'HUAWEI Mate 40 Pro', 'NOH-AN01', 'HUAWEI Mate 40 Pro', 'NOH-AL00', 'HUAWEI Mate 40 Pro', 'NOH-AL10', 'HUAWEI Mate 40 Pro', 'NOH-AN50', 'HUAWEI Mate 40E Pro', 'NOP-AN00', 'HUAWEI Mate 40 Pro', 'CET-AL00', 'HUAWEI Mate 50', 'CET-AL60', 'HUAWEI Mate 50E', 'DCO-AL00', 'HUAWEI Mate 50 Pro', 'TAH-AN00', 'HUAWEI Mate X', 'TAH-AN00m', 'HUAWEI Mate Xs', 'TET-AN00', 'HUAWEI Mate X2', 'TET-AN10', 'HUAWEI Mate X2', 'TET-AN50', 'HUAWEI Mate X2', 'TET-AL00', 'HUAWEI Mate X2', 'PAL-AL00', 'HUAWEI Mate Xs 2', 'PAL-AL10', 'HUAWEI Mate Xs 2', 'EVA-AL00', 'HUAWEI P9', 'EVA-AL10', 'HUAWEI P9', 'EVA-TL00', 'HUAWEI P9', 'EVA-DL00', 'HUAWEI P9', 'EVA-CL00', 'HUAWEI P9', 'VIE-AL10', 'HUAWEI P9 Plus', 'VTR-AL00', 'HUAWEI P10', 'VTR-TL00', 'HUAWEI P10', 'VKY-AL00', 'HUAWEI P10 Plus', 'VKY-TL00', 'HUAWEI P10 Plus', 'EML-AL00', 'HUAWEI P20', 'EML-TL00', 'HUAWEI P20', 'CLT-AL00', 'HUAWEI P20 Pro', 'CLT-AL01', 'HUAWEI P20 Pro', 'CLT-AL00l', 'HUAWEI P20 Pro', 'CLT-TL00', 'HUAWEI P20 Pro', 'CLT-TL01', 'HUAWEI P20 Pro', 'ELE-AL00', 'HUAWEI P30', 'ELE-TL00', 'HUAWEI P30', 'VOG-AL00', 'HUAWEI P30 Pro', 'VOG-AL10', 'HUAWEI P30 Pro', 'VOG-TL00', 'HUAWEI P30 Pro', 'ANA-AL00', 'HUAWEI P40', 'ANA-AN00', 'HUAWEI P40', 'ANA-TN00', 'HUAWEI P40', 'ELS-AN00', 'HUAWEI P40 Pro', 'ELS-TN00', 'HUAWEI P40 Pro', 'ELS-AN10', 'HUAWEI P40 Pro', 'ELS-TN10', 'HUAWEI P40 Pro', 'ABR-AL00', 'HUAWEI P50', 'ABR-AL80', 'HUAWEI P50', 'ABR-AL60', 'HUAWEI P50E', 'ABR-AL90', 'HUAWEI P50E', 'JAD-AL00', 'HUAWEI P50 Pro', 'JAD-AL80', 'HUAWEI P50 Pro', 'JAD-AL50', 'HUAWEI P50 Pro', 'JAD-AL60', 'HUAWEI P50 Pro', 'BAL-AL00', 'HUAWEI P50 Pocket', 'BAL-AL60', 'HUAWEI Pocket S', 'PIC-AL00', 'HUAWEI nova 2', 'PIC-TL00', 'HUAWEI nova 2', 'BAC-AL00', 'HUAWEI nova 2 Plus', 'BAC-TL00', 'HUAWEI nova 2 Plus', 'HWI-AL00', 'HUAWEI nova 2s', 'HWI-TL00', 'HUAWEI nova 2s', 'ANE-AL00', 'HUAWEI nova 3e', 'ANE-TL00', 'HUAWEI nova 3e', 'PAR-AL00', 'HUAWEI nova 3', 'PAR-TL00', 'HUAWEI nova 3', 'INE-AL00', 'HUAWEI nova 3i', 'INE-TL00', 'HUAWEI nova 3i', 'VCE-AL00', 'HUAWEI nova 4', 'VCE-TL00', 'HUAWEI nova 4', 'MAR-AL00', 'HUAWEI nova 4e', 'MAR-TL00', 'HUAWEI nova 4e', 'SEA-AL00', 'HUAWEI nova 5', 'SEA-TL00', 'HUAWEI nova 5', 'SEA-AL10', 'HUAWEI nova 5 Pro', 'SEA-TL10', 'HUAWEI nova 5 Pro', 'GLK-AL00', 'HUAWEI nova 5i', 'GLK-TL00', 'HUAWEI nova 5i', 'GLK-LX1U', 'HUAWEI nova 5i', 'SPN-TL00', 'HUAWEI nova 5i Pro', 'SPN-AL00', 'HUAWEI nova 5z', 'WLZ-AL10', 'HUAWEI nova 6', 'WLZ-AN00', 'HUAWEI nova 6', 'JNY-AL10', 'HUAWEI nova 6 SE', 'JNY-TL10', 'HUAWEI nova 6 SE', 'JEF-AN00', 'HUAWEI nova 7', 'JEF-AN20', 'HUAWEI nova 7', 'JEF-TN00', 'HUAWEI nova 7', 'JEF-TN20', 'HUAWEI nova 7', 'JER-AN10', 'HUAWEI nova 7 Pro', 'JER-AN20', 'HUAWEI nova 7 Pro', 'JER-TN10', 'HUAWEI nova 7 Pro', 'JER-TN20', 'HUAWEI nova 7 Pro', 'CDY-AN00', 'HUAWEI nova 7 SE', 'CDY-AN20', 'HUAWEI nova 7 SE', 'CDY-TN00', 'HUAWEI nova 7 SE', 'CDY-TN20', 'HUAWEI nova 7 SE', 'ANG-AN00', 'HUAWEI nova 8', 'BRQ-AN00', 'HUAWEI nova 8 Pro', 'BRQ-AL00', 'HUAWEI nova 8 Pro', 'JSC-AN00', 'HUAWEI nova 8 SE', 'JSC-TN00', 'HUAWEI nova 8 SE', 'JSC-AL50', 'HUAWEI nova 8 SE', 'NAM-AL00', 'HUAWEI nova 9', 'RTE-AL00', 'HUAWEI nova 9 Pro', 'JLN-AL00', 'HUAWEI nova 9 SE', 'NCO-AL00', 'HUAWEI nova 10', 'GLA-AL00', 'HUAWEI nova 10 Pro', 'CHA-AL80', 'HUAWEI nova 10z'],
['M2001J2C', 'Xiaomi 10', 'M2001J2G', 'Xiaomi 10', 'M2001J2I', 'Xiaomi 10', 'M2011K2C', 'Xiaomi 11', 'M2011K2G', 'Xiaomi 11', '2201123C', 'Xiaomi 12', '2201123G', 'Xiaomi 12', '2112123AC', 'Xiaomi 12X', '2112123AG', 'Xiaomi 12X', '2201122C', 'Xiaomi 12 Pro', '2201122G', 'Xiaomi 12 Pro'],
];
export function randDevice() {
let brandIdx = rand(0, deviceBrands.length - 1);
let brand = deviceBrands[brandIdx];
let modelIdx = rand(0, deviceModels[brandIdx].length / 2 - 1);
let model = deviceModels[brandIdx][modelIdx * 2 + 1];
let release = rand(8, 13);
let buildId = randStr(3, false).toUpperCase() + rand(11, 99) + randStr(1, false).toUpperCase();
return {
brand: brand,
model: model,
release: release,
buildId: buildId,
};
}
export function randDeviceWithId(len) {
let device = randDevice();
device['id'] = randStr(len);
return device;
}
export const MOBILE_UA = 'Mozilla/5.0 (Linux; Android 11; M2007J3SC Build/RKQ1.200826.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045714 Mobile Safari/537.36';
export const PC_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36';
export const UA = 'Mozilla/5.0';
export const UC_UA = 'Mozilla/5.0 (Linux; U; Android 9; zh-CN; MI 9 Build/PKQ1.181121.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.5.5.1035 Mobile Safari/537.36';
export const IOS_UA = 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1';
export const MAC_UA = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36 SE 2.X MetaSr 1.0';
export function formatPlayUrl(src, name) {
if (src.trim() == name.trim()) {
return name;
}
return name
.trim()
.replaceAll(src, '')
.replace(/<|>|《|》/g, '')
.replace(/\$|#/g, ' ')
.trim();
}
export function formatPlayUrl2(src, name) {
var idx = name.indexOf('$');
if (idx <= 0) {
return formatPlayUrl(src, name);
}
return formatPlayUrl(src, name.substring(0, idx)) + name.substring(idx);
}
export function stripHtmlTag(src) {
return src
.replace(/<\/?[^>]+(>|$)/g, '')
.replace(/&.{1,5};/g, '')
.replace(/\s{2,}/g, ' ');
}
export function fixUrl(base, src) {
try {
if (src.startsWith('//')) {
let parse = new URL(base);
let host = src.substring(2, src.indexOf('/', 2));
if (!host.includes('.')) {
src = parse.protocol + '://' + parse.host + src.substring(1);
} else {
src = parse.protocol + ':' + src;
}
} else if (!src.includes('://')) {
let parse = new URL(base);
src = parse.protocol + '://' + parse.host + src;
}
} catch (error) {}
return src;
}
export function jsonParse(input, json) {
try {
let url = json.url || '';
if (url.startsWith('//')) {
url = 'https:' + url;
}
if (!url.startsWith('http')) {
return {};
}
let headers = json['headers'] || {};
let ua = (json['user-agent'] || '').trim();
if (ua.length > 0) {
headers['User-Agent'] = ua;
}
let referer = (json['referer'] || '').trim();
if (referer.length > 0) {
headers['Referer'] = referer;
}
return {
header: headers,
url: url,
};
} catch (error) {
console.log(error);
}
return {};
}

View File

@ -1,255 +0,0 @@
/*
* @File : nivid_object.js
* @Author : jade
* @Date : 2023/12/20 9:50
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {Crypto} from "./cat.js";
let DesKey = "diao.com"
class ChannelResponse {
// classes
constructor() {
this.channelMsg = ""
this.channelStatus = 0
this.channelList = []
this.channelFilters = {}
}
fromJsonString(json_str, remove18ChannelCode = 0) {
let json_dic = JSON.parse(json_str)
this.channelMsg = json_dic.msg
this.channelStatus = json_dic.status
let channel_list = []
for (const channel_info of json_dic.list) {
let new_channel_info = new ChannelInfo()
switch (remove18ChannelCode) {
case 0:
new_channel_info.fromJson(channel_info)
channel_list.push(new_channel_info)
break
case 1:
if (channel_info.channelName !== "午夜场" && channel_info.channelName !== "午夜直播") {
new_channel_info.fromJson(channel_info)
channel_list.push(new_channel_info)
}
break
case 2:
if (channel_info.channelName === "午夜场" || channel_info.channelName === "午夜直播") {
new_channel_info.fromJson(channel_info)
channel_list.push(new_channel_info)
}
break
}
}
this.channelList = channel_list
this.channelFilters = json_dic.filter
}
setChannelFilters(filter_str) {
this.channelFilters = JSON.parse(filter_str)
}
getValues(typeList, name_key, id_key) {
let values = []
values.push({"n": "全部", "v": "0"})
for (const obj of typeList) {
values.push({"n": obj[name_key], "v": obj[id_key].toString()})
}
return values
}
getFilters() {
let filters = {}
for (const channel_info of this.channelList) {
filters[channel_info.channelId] = []
let sortMapList = this.channelFilters["sortsMap"][parseInt(channel_info.channelId)]
let sortValues = this.getValues(sortMapList, "title", "id")
filters[channel_info.channelId].push({"key": "1", "name": "排序", "value": sortValues})
let typeMapList = this.channelFilters["typesMap"][parseInt(channel_info.channelId)]
let typeValues = this.getValues(typeMapList, "showTypeName", "showTypeId")
filters[channel_info.channelId].push({"key": "2", "name": "类型", "value": typeValues})
let areaValues = this.getValues(this.channelFilters["regions"], "regionName", "regionId")
filters[channel_info.channelId].push({"key": "3", "name": "地区", "value": areaValues})
let langValues = this.getValues(this.channelFilters["langs"], "langName", "langId")
filters[channel_info.channelId].push({"key": "4", "name": "语言", "value": langValues})
let yearValues = this.getValues(this.channelFilters["yearRanges"], "name", "code")
filters[channel_info.channelId].push({"key": "5", "name": "年份", "value": yearValues})
}
return filters
}
getChannelFilters() {
return this.channelFilters
}
getChannelMsg() {
return this.channelMsg
}
getChannelStatus() {
return this.channelStatus
}
getChannelList() {
return this.channelList
}
getClassList() {
let classes = []
for (const channel_info of this.channelList) {
classes.push({"type_id": channel_info.channelId, "type_name": channel_info.channelName})
}
return classes
}
async save() {
await local.set("niba", "niba_channel", this.toString());
return this;
}
clear() {
this.channelMsg = ""
this.channelStatus = 0
this.channelList = []
}
async clearCache() {
this.clear()
await local.set("niba", "niba_channel", "{}");
}
toString() {
const params = {
msg: this.getChannelMsg(),
status: this.getChannelStatus(),
list: this.getChannelList(),
filter: this.getChannelFilters()
};
return JSON.stringify(params);
}
}
async function getChannelCache() {
return await local.get("niba", "niba_channel");
}
class ChannelInfo {
constructor() {
this.channelId = 0
this.channelName = ""
}
fromJsonString(json_str) {
let json_dic = JSON.parse(json_str)
this.channelId = json_dic.channelId
this.channelName = json_dic.channelName
}
fromJson(json) {
this.channelId = json.channelId
this.channelName = json.channelName
}
getChannelName() {
return this.channelName
}
getChannelId() {
return this.channelId
}
}
function isNumeric(str) {
return !isNaN(parseInt(str));
}
function getVod(video_dic_list, play_foramt_list, showIdCode) {
let episode_list = [], episode_str_list = [];
for (const video_dic of video_dic_list) {
let video_name = ""
if (isNumeric((video_dic['episodeName']))) {
video_name = "第" + video_dic["episodeName"] + "集"
} else {
video_name = video_dic["episodeName"]
}
episode_list.push(video_name + "$" + video_dic["playIdCode"] + "@" + showIdCode);
}
for (let index = 0; index < play_foramt_list.length; index++) {
episode_str_list.push(episode_list.join("#"));
}
return {
vod_play_url: episode_str_list.join("$$$"),
vod_play_from: play_foramt_list.map(item => item).join("$$$"),
};
}
function getHeader() {
return {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36",
"Referer": "https://m.nivod.tv/",
"Content-Type": "application/x-www-form-urlencoded"
}
}
function md5(text) {
return Crypto.MD5(text).toString()
}
//加密
async function createSign(body = null) {
let params = {
"_ts": Date.now(), "app_version": "1.0",
"platform": "3", "market_id": "web_nivod",
"device_code": "web", "versioncode": 1,
"oid": "8ca275aa5e12ba504b266d4c70d95d77a0c2eac5726198ea"
}
/**
* __QUERY::_ts=1702973558399&app_version=1.0&device_code=web&market_id=web_nivod&oid=8ca275aa5e12ba504b266d4c70d95d77a0c2eac5726198ea&platform=3&versioncode=1&__BODY::__KEY::2x_Give_it_a_shot
*/
let params_list = []
for (const key of Object.keys(params).sort()) {
params_list.push(`${key}=${params[key]}`)
}
let body_str = "&__BODY::"
if (body !== null) {
let body_list = []
for (const key of Object.keys(body).sort()) {
body_list.push(`${key}=${body[key]}`)
}
body_str = body_str + body_list.join("&") + "&"
}
let params_str = "__QUERY::" + params_list.join("&") + body_str + "__KEY::2x_Give_it_a_shot"
let sign_code = md5(params_str)
params_list.push(`sign=${sign_code}`)
return "?" + params_list.join("&")
}
//解密
function desDecrypt(content) {
// 定义密钥
const key = Crypto.enc.Utf8.parse(DesKey); // 密钥需要进行字节数转换
/*
const encrypted = Crypto.DES.encrypt(content, key, {
mode: Crypto.mode.ECB, // 使用ECB模式
padding: Crypto.pad.Pkcs7, // 使用Pkcs7填充
}).ciphertext.toString();
*/
return Crypto.DES.decrypt({ciphertext: Crypto.enc.Hex.parse(content)}, key, {
mode: Crypto.mode.ECB,
padding: Crypto.pad.Pkcs7,
}).toString(Crypto.enc.Utf8);
}
export {getChannelCache, desDecrypt, createSign, ChannelResponse, getHeader, getVod};

View File

@ -1,146 +0,0 @@
/*
* @File : pipiXiaObject.js
* @Author : jade
* @Date : 2024/2/4 14:33
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
const UID = "DCC147D11943AF75"
const chrsz = 8;
const hexcase = 0;
function hex_md5(s) {
return binl2hex(core_md5(str2binl(s), s.length * chrsz))
}
function str2binl(str) {
var bin = Array();
var mask = (1 << chrsz) - 1;
for (var i = 0; i < str.length * chrsz; i += chrsz)
bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32);
return bin
}
function core_md5(x, len) {
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for (var i = 0; i < x.length; i += 16) {
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd)
}
return Array(a, b, c, d)
}
function md5_gg(a, b, c, d, x, s, t) {
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t)
}
function md5_ff(a, b, c, d, x, s, t) {
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t)
}
function md5_hh(a, b, c, d, x, s, t) {
return md5_cmn(b ^ c ^ d, a, b, x, s, t)
}
function md5_ii(a, b, c, d, x, s, t) {
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t)
}
function md5_cmn(q, a, b, x, s, t) {
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b)
}
function safe_add(x, y) {
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF)
}
function bit_rol(num, cnt) {
return (num << cnt) | (num >>> (32 - cnt))
}
function binl2hex(binarray) {
let hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
let str = "";
for (let i = 0; i < binarray.length * 4; i++) {
str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) + hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF)
}
return str
}
function pipixiaMd5(date_time) {
return hex_md5('DS' + date_time + UID)
}
export {pipixiaMd5}
// let key = pipixiaMd5(Math.floor(new Date() / 1000),"DCC147D11943AF75")
// let x = 0

View File

@ -1,170 +0,0 @@
import { inRange, decoderError, encoderError, floor, isASCIICodePoint, isASCIIByte,
end_of_stream, finished } from './text_decoder_utils.js'
import index, { indexCodePointFor, indexShiftJISPointerFor } from './text_decoder_indexes.js'
// 13.3 Shift_JIS
// 13.3.1 Shift_JIS decoder
/**
* @constructor
* @implements {Decoder}
* @param {{fatal: boolean}} options
*/
export class ShiftJISDecoder {
constructor(options) {
const { fatal } = options
this.fatal = fatal
// Shift_JIS's decoder has an associated Shift_JIS lead (initially
// 0x00).
this.Shift_JIS_lead = 0x00
}
/**
* @param {Stream} stream The stream of bytes being decoded.
* @param {number} bite The next byte read from the stream.
*/
handler(stream, bite) {
// 1. If byte is end-of-stream and Shift_JIS lead is not 0x00,
// set Shift_JIS lead to 0x00 and return error.
if (bite === end_of_stream && this.Shift_JIS_lead !== 0x00) {
this.Shift_JIS_lead = 0x00
return decoderError(this.fatal)
}
// 2. If byte is end-of-stream and Shift_JIS lead is 0x00,
// return finished.
if (bite === end_of_stream && this.Shift_JIS_lead === 0x00)
return finished
// 3. If Shift_JIS lead is not 0x00, let lead be Shift_JIS lead,
// let pointer be null, set Shift_JIS lead to 0x00, and then run
// these substeps:
if (this.Shift_JIS_lead !== 0x00) {
var lead = this.Shift_JIS_lead
var pointer = null
this.Shift_JIS_lead = 0x00
// 1. Let offset be 0x40, if byte is less than 0x7F, and 0x41
// otherwise.
var offset = (bite < 0x7F) ? 0x40 : 0x41
// 2. Let lead offset be 0x81, if lead is less than 0xA0, and
// 0xC1 otherwise.
var lead_offset = (lead < 0xA0) ? 0x81 : 0xC1
// 3. If byte is in the range 0x40 to 0x7E, inclusive, or 0x80
// to 0xFC, inclusive, set pointer to (lead lead offset) ×
// 188 + byte offset.
if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0x80, 0xFC))
pointer = (lead - lead_offset) * 188 + bite - offset
// 4. If pointer is in the range 8836 to 10715, inclusive,
// return a code point whose value is 0xE000 8836 + pointer.
if (inRange(pointer, 8836, 10715))
return 0xE000 - 8836 + pointer
// 5. Let code point be null, if pointer is null, and the
// index code point for pointer in index jis0208 otherwise.
var code_point = (pointer === null) ? null :
indexCodePointFor(pointer, index('jis0208'))
// 6. If code point is null and byte is an ASCII byte, prepend
// byte to stream.
if (code_point === null && isASCIIByte(bite))
stream.prepend(bite)
// 7. If code point is null, return error.
if (code_point === null)
return decoderError(this.fatal)
// 8. Return a code point whose value is code point.
return code_point
}
// 4. If byte is an ASCII byte or 0x80, return a code point
// whose value is byte.
if (isASCIIByte(bite) || bite === 0x80)
return bite
// 5. If byte is in the range 0xA1 to 0xDF, inclusive, return a
// code point whose value is 0xFF61 0xA1 + byte.
if (inRange(bite, 0xA1, 0xDF))
return 0xFF61 - 0xA1 + bite
// 6. If byte is in the range 0x81 to 0x9F, inclusive, or 0xE0
// to 0xFC, inclusive, set Shift_JIS lead to byte and return
// continue.
if (inRange(bite, 0x81, 0x9F) || inRange(bite, 0xE0, 0xFC)) {
this.Shift_JIS_lead = bite
return null
}
// 7. Return error.
return decoderError(this.fatal)
}
}
// 13.3.2 Shift_JIS encoder
/**
* @constructor
* @implements {Encoder}
* @param {{fatal: boolean}} options
*/
export class ShiftJISEncoder {
/**
* @param {Stream} stream Input stream.
* @param {number} code_point Next code point read from the stream.
*/
handler(stream, code_point) {
// 1. If code point is end-of-stream, return finished.
if (code_point === end_of_stream)
return finished
// 2. If code point is an ASCII code point or U+0080, return a
// byte whose value is code point.
if (isASCIICodePoint(code_point) || code_point === 0x0080)
return code_point
// 3. If code point is U+00A5, return byte 0x5C.
if (code_point === 0x00A5)
return 0x5C
// 4. If code point is U+203E, return byte 0x7E.
if (code_point === 0x203E)
return 0x7E
// 5. If code point is in the range U+FF61 to U+FF9F, inclusive,
// return a byte whose value is code point 0xFF61 + 0xA1.
if (inRange(code_point, 0xFF61, 0xFF9F))
return code_point - 0xFF61 + 0xA1
// 6. If code point is U+2212, set it to U+FF0D.
if (code_point === 0x2212)
code_point = 0xFF0D
// 7. Let pointer be the index Shift_JIS pointer for code point.
var pointer = indexShiftJISPointerFor(code_point)
// 8. If pointer is null, return error with code point.
if (pointer === null)
return encoderError(code_point)
// 9. Let lead be floor(pointer / 188).
var lead = floor(pointer / 188)
// 10. Let lead offset be 0x81, if lead is less than 0x1F, and
// 0xC1 otherwise.
var lead_offset = (lead < 0x1F) ? 0x81 : 0xC1
// 11. Let trail be pointer % 188.
var trail = pointer % 188
// 12. Let offset be 0x40, if trail is less than 0x3F, and 0x41
// otherwise.
var offset = (trail < 0x3F) ? 0x40 : 0x41
// 13. Return two bytes whose values are lead + lead offset and
// trail + offset.
return [lead + lead_offset, trail + offset]
}
}

View File

@ -1,53 +0,0 @@
function compareTwoStrings(first, second) {
if ((first = first.replace(/\s+/g, "")) === (second = second.replace(/\s+/g, ""))) return 1;
if (first.length < 2 || second.length < 2) return 0;
var firstBigrams = new Map;
for (let i = 0; i < first.length - 1; i++) {
var bigram = first.substring(i, i + 2), count = firstBigrams.has(bigram) ? firstBigrams.get(bigram) + 1 : 1;
firstBigrams.set(bigram, count)
}
let intersectionSize = 0;
for (let i = 0; i < second.length - 1; i++) {
const bigram = second.substring(i, i + 2), count = firstBigrams.has(bigram) ? firstBigrams.get(bigram) : 0;
0 < count && (firstBigrams.set(bigram, count - 1), intersectionSize++)
}
return 2 * intersectionSize / (first.length + second.length - 2)
}
function findBestMatch(mainString, targetStrings) {
var ratings = [];
let bestMatchIndex = 0;
for (let i = 0; i < targetStrings.length; i++) {
var currentTargetString = targetStrings[i], currentRating = compareTwoStrings(mainString, currentTargetString);
ratings.push({
target: currentTargetString,
rating: currentRating
}), currentRating > ratings[bestMatchIndex].rating && (bestMatchIndex = i)
}
return {ratings: ratings, bestMatch: ratings[bestMatchIndex], bestMatchIndex: bestMatchIndex}
}
function lcs(str1, str2) {
if (!str1 || !str2) return {length: 0, sequence: "", offset: 0};
for (var sequence = "", str1Length = str1.length, str2Length = str2.length, num = new Array(str1Length), maxlen = 0, lastSubsBegin = 0, i = 0; i < str1Length; i++) {
for (var subArray = new Array(str2Length), j = 0; j < str2Length; j++) subArray[j] = 0;
num[i] = subArray
}
for (var thisSubsBegin = null, i = 0; i < str1Length; i++) for (j = 0; j < str2Length; j++) str1[i] !== str2[j] ? num[i][j] = 0 : (num[i][j] = 0 === i || 0 === j ? 1 : 1 + num[i - 1][j - 1], num[i][j] > maxlen && (maxlen = num[i][j], lastSubsBegin === (thisSubsBegin = i - num[i][j] + 1) ? sequence += str1[i] : (lastSubsBegin = thisSubsBegin, sequence = "", sequence += str1.substr(lastSubsBegin, i + 1 - lastSubsBegin))));
return {length: maxlen, sequence: sequence, offset: thisSubsBegin}
}
function findBestLCS(mainString, targetStrings) {
var results = [];
let bestMatchIndex = 0;
for (let i = 0; i < targetStrings.length; i++) {
var currentTargetString = targetStrings[i], currentLCS = lcs(mainString, currentTargetString);
results.push({
target: currentTargetString,
lcs: currentLCS
}), currentLCS.length > results[bestMatchIndex].lcs.length && (bestMatchIndex = i)
}
return {allLCS: results, bestMatch: results[bestMatchIndex], bestMatchIndex: bestMatchIndex}
}
export {compareTwoStrings, findBestMatch, findBestLCS};

View File

@ -1,86 +0,0 @@
import { end_of_stream, finished, isASCIIByte, decoderError, encoderError, isASCIICodePoint } from './text_decoder_utils.js'
import { indexPointerFor } from './text_decoder_indexes.js'
//
// 10. Legacy single-byte encodings
//
// 10.1 single-byte decoder
/**
* @implements {Decoder}
*/
export class SingleByteDecoder {
/**
* @param {!Array.<number>} index The encoding index.
* @param {{fatal: boolean}} options
*/
constructor(index, options) {
const { fatal } = options
this.fatal = fatal
this.index = index
}
/**
* @param {Stream} stream The stream of bytes being decoded.
* @param {number} bite The next byte read from the stream.
*/
handler(stream, bite) {
// 1. If byte is end-of-stream, return finished.
if (bite === end_of_stream)
return finished
// 2. If byte is an ASCII byte, return a code point whose value
// is byte.
if (isASCIIByte(bite))
return bite
// 3. Let code point be the index code point for byte 0x80 in
// index single-byte.
var code_point = this.index[bite - 0x80]
// 4. If code point is null, return error.
if (code_point === null)
return decoderError(this.fatal)
// 5. Return a code point whose value is code point.
return code_point
}
}
// 10.2 single-byte encoder
/**
* @implements {Encoder}
*/
export class SingleByteEncoder {
/**
* @param {!Array.<?number>} index The encoding index.
*/
constructor(index) {
this.index = index
}
/**
* @param {Stream} stream Input stream.
* @param {number} code_point Next code point read from the stream.
* @return {(number|!Array.<number>)} Byte(s) to emit.
*/
handler(stream, code_point) {
// 1. If code point is end-of-stream, return finished.
if (code_point === end_of_stream)
return finished
// 2. If code point is an ASCII code point, return a byte whose
// value is code point.
if (isASCIICodePoint(code_point))
return code_point
// 3. Let pointer be the index pointer for code point in index
// single-byte.
const pointer = indexPointerFor(code_point, this.index)
// 4. If pointer is null, return error with code point.
if (pointer === null)
encoderError(code_point)
// 5. Return a byte whose value is pointer + 0x80.
return pointer + 0x80
}
}

Some files were not shown because too many files have changed in this diff Show More