Compare commits
No commits in common. "multiThread" and "main" have entirely different histories.
multiThrea
...
main
|
|
@ -1,80 +0,0 @@
|
|||
name: Spider Jar Gen CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "multiThread" ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'jetbrains'
|
||||
cache: gradle
|
||||
|
||||
- name: Grant execute permission to gradlew
|
||||
run: chmod +x ./gradlew
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew app:buildCustomSpiderJar
|
||||
|
||||
|
||||
- name: Add & Commit
|
||||
uses: EndBug/add-and-commit@v9.1.4
|
||||
with:
|
||||
default_author: github_actions
|
||||
message: 'update spider jar and json'
|
||||
add: "['./jar/custom_spider.jar', './jar/custom_spider.jar.md5','./json/index.json']"
|
||||
|
||||
- name: upload json
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
|
||||
with:
|
||||
# ftp server
|
||||
server: ftpupload.net
|
||||
# ftp username
|
||||
username: mseet_40633048
|
||||
# ftp password
|
||||
password: ${{ secrets.FTP_PWD }}
|
||||
# Server port to connect to (read your web hosts docs)
|
||||
port: 21
|
||||
# protocol to deploy with - ftp, ftps, or ftps-legacy
|
||||
protocol: ftp
|
||||
# Folder to upload from, must end with trailing slash /
|
||||
local-dir: ${{ github.workspace }}/json/
|
||||
# Path to upload to on the server. Must end with trailing slash /
|
||||
server-dir: htdocs/json/
|
||||
# Deletes ALL contents of server-dir, even items in excluded with exclude argument
|
||||
dangerous-clean-slate: true
|
||||
exclude: |
|
||||
**/js/**
|
||||
|
||||
- name: upload jar
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
|
||||
with:
|
||||
# ftp server
|
||||
server: ftpupload.net
|
||||
# ftp username
|
||||
username: mseet_40633048
|
||||
# ftp password
|
||||
password: ${{ secrets.FTP_PWD }}
|
||||
# Server port to connect to (read your web hosts docs)
|
||||
port: 21
|
||||
# protocol to deploy with - ftp, ftps, or ftps-legacy
|
||||
protocol: ftp
|
||||
# Folder to upload from, must end with trailing slash /
|
||||
local-dir: ${{ github.workspace }}/jar/
|
||||
# Path to upload to on the server. Must end with trailing slash /
|
||||
server-dir: htdocs/jar/
|
||||
# Deletes ALL contents of server-dir, even items in excluded with exclude argument
|
||||
dangerous-clean-slate: true
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
kotlin version: 2.0.10
|
||||
error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
|
||||
1. Kotlin compile daemon is ready
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
kotlin version: 2.0.10
|
||||
error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
|
||||
1. Kotlin compile daemon is ready
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
kotlin version: 2.0.10
|
||||
error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
|
||||
1. Kotlin compile daemon is ready
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
kotlin version: 2.0.10
|
||||
error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
|
||||
1. Kotlin compile daemon is ready
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
kotlin version: 2.0.10
|
||||
error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
|
||||
1. Kotlin compile daemon is ready
|
||||
|
||||
212
CONTRIBUTING.md
212
CONTRIBUTING.md
|
|
@ -1,212 +0,0 @@
|
|||
# TVbox源贡献指南
|
||||
|
||||
|
||||
### 欢迎各路大佬踊跃提PR,分享爬虫代码。
|
||||
|
||||
## 源码仓库地址
|
||||
https://github.com/lushunming/AndroidCatVodSpider
|
||||
|
||||
## 快速开始
|
||||
----
|
||||
本工程是一个完整的AndroidStudio工程,请你用AS打开编辑。
|
||||
|
||||
工程调试完毕后要需要导出生成jar文件配合软件使用,执行根目录下的 `build.bat` 会在`jar`目录生成一个名为`custom_spider.jar`的jar文件,这个文件就是我们最终要是用的代码包。
|
||||
|
||||
### 代码包食用方式
|
||||
----
|
||||
本地加载:将`custom_spider.jar`放入设备sd卡根目录即可。 **注意,如需本地加载,请手动赋予App存储空间读写权限,App默认不申请存储空间读写权限**
|
||||
|
||||
远程加载:将`custom_spider.jar`上传到你的网络空间,获取对应的文件下载地址,在软件自定义配置的json文件中加入下面格式的键值对。
|
||||
```json
|
||||
"spider": "http://xxx.xxx.xxx/custom_spider.jar"
|
||||
```
|
||||
支持jar文件本地缓存(需v2.0.5及以上版本)
|
||||
```json
|
||||
"spider": "http://xxx.xxx.xxx/custom_spider.jar;md5;jar文件md5"
|
||||
// 例如
|
||||
"spider": "https://github.com/catvod/CatVodTVSpider/blob/master/jar/custom_spider.jar?raw=true;md5;c6ed6bc8285f0aca90e7cb3abf7f9caa",
|
||||
```
|
||||
|
||||
### 如何在自定义配置中调用我们代码包中的Spider
|
||||
----
|
||||
同样在自定义json中加入相应的播放源即可,**type=3, api对应你代码工程中自定义的爬虫类名(api必须是`csp_`开头),例如实例工程中的`Aidi`**
|
||||
```json
|
||||
{
|
||||
"key": "csp_Aidi",
|
||||
"name": "爱迪",
|
||||
"type": 3,
|
||||
"api": "csp_Aidi",
|
||||
"searchable": 1,
|
||||
"quickSearch": 0,
|
||||
"filterable": 1
|
||||
}
|
||||
```
|
||||
---
|
||||
**Json解析扩展(需v2.0.2及以上版本)**
|
||||
|
||||
通过jar包可以实现json解析并发、轮询等相关功能,**参与并发和轮询的json解析地址,默认为解析地址列表中的所有json解析(即type=1)**。
|
||||
|
||||
在自定义json中的`parse`里加入相应的解析配置(type=2)即可启用。**调用扩展类的名称配置在`parse`的`url`字段里,例如扩展类`JsonParallel`的json配置`url`字段值为`Parallel`**。如下:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Json并发",
|
||||
"type": 2,
|
||||
"url": "Parallel"
|
||||
},
|
||||
{
|
||||
"name": "Json轮询",
|
||||
"type": 2,
|
||||
"url": "Sequence"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
**部分内置代理接口使用(需v2.0.9及以上版本)**
|
||||
|
||||
入口 [Proxy](/app/src/main/java/com/github/catvod/spider/Proxy.java)
|
||||
|
||||
代理,示例参考[Ddrk](/app/src/main/java/com/github/catvod/spider/Ddrk.java)
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
## 基础类
|
||||
----
|
||||
|
||||
> com.github.catvod.spider.Spider 爬虫基类
|
||||
> com.github.catvod.spider.Cloud 网盘(UC、ali、quark)爬虫开发类
|
||||
|
||||
|
||||
|
||||
|
||||
## 示例
|
||||
----
|
||||
|
||||
请查看 仓库中的Ddrk 相关实现 ,调试可参考 `com.github.catvod.demo.MainActivity` ,直接调用对应爬虫相关接口
|
||||
|
||||
> com.github.catvod.spider.Ddrk 爬虫类
|
||||
> com.github.catvod.spider.DdrkTest 测试类
|
||||
|
||||
## 注意事项!!
|
||||
----
|
||||
1. 除了`com.github.catvod.spider`包以外的代码,最终都会被软件本身内置的代码代替掉,所以,建议你不要修改除`com.github.catvod.spider`包以外的代码。
|
||||
|
||||
2. 需要提交爬虫和对应的爬虫测试类,不然不接受PR
|
||||
|
||||
3. 待补充
|
||||
|
||||
## 爬虫类返回的相关Json字符串格式说明
|
||||
----
|
||||
### homeContent
|
||||
```json
|
||||
{
|
||||
"class": [{ // 分类
|
||||
"type_id": "dianying", // 分类id
|
||||
"type_name": "电影" // 分类名
|
||||
}, {
|
||||
"type_id": "lianxuju",
|
||||
"type_name": "连续剧"
|
||||
}],
|
||||
"filters": { // 筛选
|
||||
"dianying": [{ // 分类id 就是上面class中的分类id
|
||||
"key": "0", // 筛选key
|
||||
"name": "分类", // 筛选名称
|
||||
"value": [{ // 筛选选项
|
||||
"n": "全部", // 选项展示的名称
|
||||
"v": "dianying" // 选项最终在url中的展现
|
||||
}, {
|
||||
"n": "动作片",
|
||||
"v": "dongzuopian"
|
||||
}]
|
||||
}],
|
||||
"lianxuju": [{
|
||||
"key": 0,
|
||||
"name": "分类",
|
||||
"value": [{
|
||||
"n": "全部",
|
||||
"v": "lianxuju"
|
||||
}, {
|
||||
"n": "国产剧",
|
||||
"v": "guochanju"
|
||||
}, {
|
||||
"n": "港台剧",
|
||||
"v": "gangtaiju"
|
||||
}]
|
||||
}]
|
||||
},
|
||||
"list": [{ // 首页最近更新视频列表
|
||||
"vod_id": "1901", // 视频id
|
||||
"vod_name": "判决", // 视频名
|
||||
"vod_pic": "https:\/\/pic.imgdb.cn\/item\/614631e62ab3f51d918e9201.jpg", // 展示图片
|
||||
"vod_remarks": "6.8" // 视频信息 展示在 视频名上方
|
||||
}, {
|
||||
"vod_id": "1908",
|
||||
"vod_name": "移山的父亲",
|
||||
"vod_pic": "https:\/\/pic.imgdb.cn\/item\/6146fab82ab3f51d91c01af1.jpg",
|
||||
"vod_remarks": "6.7"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### categoryContent
|
||||
```json
|
||||
{
|
||||
"page": 1, // 当前页
|
||||
"pagecount": 2, // 总共几页
|
||||
"limit": 60, // 每页几条数据
|
||||
"total": 120, // 总共多少调数据
|
||||
"list": [{ // 视频列表 下面的视频结构 同上面homeContent中的
|
||||
"vod_id": "1897",
|
||||
"vod_name": "北区侦缉队",
|
||||
"vod_pic": "https:\/\/pic.imgdb.cn\/item\/6145d4b22ab3f51d91bd98b6.jpg",
|
||||
"vod_remarks": "7.3"
|
||||
}, {
|
||||
"vod_id": "1879",
|
||||
"vod_name": "浪客剑心 最终章 人诛篇",
|
||||
"vod_pic": "https:\/\/pic.imgdb.cn\/item\/60e3f37e5132923bf82ef95e.jpg",
|
||||
"vod_remarks": "8.0"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### detailContent
|
||||
```json
|
||||
{
|
||||
"list": [{
|
||||
"vod_id": "1902",
|
||||
"vod_name": "海岸村恰恰恰",
|
||||
"vod_pic": "https:\/\/pic.imgdb.cn\/item\/61463fd12ab3f51d91a0f44d.jpg",
|
||||
"type_name": "剧情",
|
||||
"vod_year": "2021",
|
||||
"vod_area": "韩国",
|
||||
"vod_remarks": "更新至第8集",
|
||||
"vod_actor": "申敏儿,金宣虎,李相二,孔敏晶,徐尚沅,禹美华,朴艺荣,李世亨,边胜泰,金贤佑,金英玉",
|
||||
"vod_director": "柳济元",
|
||||
"vod_content": "海岸村恰恰恰剧情: 韩剧海岸村恰恰恰 갯마을 차차차改编自2004年的电影《我的百事通男友洪班长》,海岸村恰恰恰 갯마을 차차차讲述来自大都市的牙医(申敏儿 饰)到充满人情味的海岸村开设牙医诊所,那里住着一位各方面都",
|
||||
// 播放源 多个用$$$分隔
|
||||
"vod_play_from": "qiepian$$$yun3edu",
|
||||
// 播放列表 注意分隔符 分别是 多个源$$$分隔,源中的剧集用#分隔,剧集的名称和地址用$分隔
|
||||
"vod_play_url": "第1集$1902-1-1#第2集$1902-1-2#第3集$1902-1-3#第4集$1902-1-4#第5集$1902-1-5#第6集$1902-1-6#第7集$1902-1-7#第8集$1902-1-8$$$第1集$1902-2-1#第2集$1902-2-2#第3集$1902-2-3#第4集$1902-2-4#第5集$1902-2-5#第6集$1902-2-6#第7集$1902-2-7#第8集$1902-2-8"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### searchContent
|
||||
```json
|
||||
{
|
||||
"list": [{ // 视频列表 下面的视频结构 同上面homeContent中的
|
||||
"vod_id": "1606",
|
||||
"vod_name": "陪你一起长大",
|
||||
"vod_pic": "https:\/\/img.aidi.tv\/img\/upload\/vod\/20210417-1\/e27d4eb86f7cde375171dd324b2c19ae.jpg",
|
||||
"vod_remarks": "更新至第37集"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
21
LICENSE
21
LICENSE
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2024 lushunming
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
40
README.md
40
README.md
|
|
@ -1,39 +1,5 @@
|
|||
# CatVodSpider for TVBOX android
|
||||
# CatVodSpider
|
||||
|
||||
## 提示
|
||||
本项目不提供网盘账号,需要自己登录网盘账号,如果无法使用确保自己的网盘是有空间的,需要高清视频需要自己开通网盘会员,谢谢!!!
|
||||
### Based on CatVod
|
||||
|
||||
## Based on CatVod
|
||||
|
||||
fork from https://github.com/FongMi/CatVodSpider
|
||||
|
||||
spider 参考 https://github.com/bizhangjie/CatVodSpider
|
||||
|
||||
jsSpider 参考 https://github.com/jadehh/TVSpider
|
||||
|
||||
源链接:https://mirror.ghproxy.com/https://raw.githubusercontent.com/lushunming/AndroidCatVodSpider/mine/json/index.json
|
||||
或者 https://androidcatvodspider.netlify.app/json/index.json
|
||||
|
||||
|
||||
## 贡献
|
||||
请参考 [CONTRIBUTING.md](/CONTRIBUTING.md)
|
||||
|
||||
## 教程
|
||||
请参考 [USE.md](/USE.md)
|
||||
|
||||
## ✨ Star 数
|
||||
|
||||
[](https://star-history.com/#lushunming/AndroidCatVodSpider&Date)
|
||||
---
|
||||
|
||||
|
||||
## 公众号
|
||||
关注公众号,获取最新更新。
|
||||
|
||||

|
||||
|
||||
## 备注
|
||||
该项目仅为自己自用开发,如果发现bug,可以提issues,但是基本不接受新需求(除非我感兴趣的新需求)。
|
||||
|
||||
## 群组
|
||||
为了方便讨论可以加群组,但不保证及时回复 https://t.me/+YLvmJsZoFmcyN2M1
|
||||
https://github.com/CatVodTVOfficial/CatVodTVSpider
|
||||
|
|
|
|||
20
USE.md
20
USE.md
|
|
@ -1,20 +0,0 @@
|
|||
|
||||
|
||||
|
||||
# TVBox源使用教程
|
||||
|
||||
昨天更新之后,很多人问如何使用,今天写一篇补充教程。
|
||||
|
||||
## 地址
|
||||
https://androidcatvodspider.netlify.app/json/index.json
|
||||
|
||||
## 如何操作
|
||||
|
||||
1. 清除源缓存,更新到最新的源
|
||||
2. 站源切换到`Cookie设置`
|
||||
3. 选择分类`UC`,然后点击设置Token,弹出二维码后,用手机端扫码即可。
|
||||
4. 如果以前使用过UC,那么就可以直接享受UC原画高清视频。如果是本源的新用户,需要找一个UC资源观看,他会自动弹出窗口,然后选择扫二维码扫码即可观看。
|
||||
|
||||
## 存在问题
|
||||
1. 有的新用户一直提示扫码,可能是TVBOX的文件权限没开,无法在本地生成文件,打开文件权限就行。
|
||||
2. 有的旧用户设置了Cookie还是无法观看,可以到文件管理里面找到TV文件夹,删除里面的`.uc` 和`.uctoken`文件(可能被隐藏,设置里打开显示隐藏文件,或者将文件夹删除),再重新按照操作走一遍。
|
||||
184
app/build.gradle
184
app/build.gradle
|
|
@ -1,26 +1,17 @@
|
|||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'ru.cleverpumpkin.proguard-dictionaries-generator'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
}
|
||||
|
||||
}
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(17)
|
||||
}
|
||||
}
|
||||
android {
|
||||
namespace 'com.github.catvod'
|
||||
|
||||
compileSdk 34
|
||||
compileSdk 35
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.github.catvod.demo"
|
||||
minSdk 16
|
||||
targetSdk 34
|
||||
ndk { abiFilters "arm64-v8a" }
|
||||
|
||||
|
||||
targetSdk 35
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
|
@ -37,23 +28,9 @@ android {
|
|||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
testOptions {
|
||||
unitTests.returnDefaultValues = true
|
||||
unitTests.includeAndroidResources = true
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "11"
|
||||
|
||||
}
|
||||
packagingOptions {
|
||||
|
||||
exclude 'META-INF/*'
|
||||
|
||||
}
|
||||
|
||||
|
||||
configurations.configureEach {
|
||||
resolutionStrategy {
|
||||
|
|
@ -64,160 +41,11 @@ android {
|
|||
|
||||
dependencies {
|
||||
implementation 'com.github.thegrizzlylabs:sardine-android:0.9'
|
||||
implementation 'wang.harlon.quickjs:wrapper-android:2.0.0'
|
||||
implementation 'wang.harlon.quickjs:wrapper-android:0.21.1'
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.12.13'
|
||||
implementation 'com.google.code.gson:gson:2.11.0'
|
||||
implementation 'cn.wanghaomiao:JsoupXpath:2.5.1'
|
||||
implementation 'com.google.zxing:core:3.3.0'
|
||||
implementation 'com.orhanobut:logger:2.2.0'
|
||||
implementation 'org.jsoup:jsoup:1.15.3'
|
||||
implementation 'androidx.core:core-ktx:1.10.1'
|
||||
testImplementation "io.github.dokar3:quickjs-kt-jvm:1.0.0-alpha13"
|
||||
testImplementation 'org.nanohttpd:nanohttpd:2.3.1'
|
||||
implementation 'commons-codec:commons-codec:1.17.1'
|
||||
|
||||
// Required -- JUnit 4 framework
|
||||
testImplementation 'junit:junit:4.12'
|
||||
// Optional -- Mockito framework(可选,用于模拟一些依赖对象,以达到隔离依赖的效果)
|
||||
testImplementation 'org.mockito:mockito-core:5.12.0'
|
||||
testImplementation "org.robolectric:robolectric:4.13"
|
||||
testImplementation 'cn.hutool:hutool-all:5.8.26'
|
||||
|
||||
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1"
|
||||
// https://mvnrepository.com/artifact/com.sun.net.httpserver/http
|
||||
/* implementation(files("libs/sun-common-server.jar"))
|
||||
implementation("com.sun.net.httpserver:http:20070405")*/
|
||||
// implementation("com.hibegin:simplewebserver:0.1.15")
|
||||
//implementation("com.github.codeborne.klite:klite-server:1.7.0")
|
||||
|
||||
|
||||
//implementation 'wang.harlon.quickjs:wrapper-java:1.0.0'
|
||||
// implementation(ext: 'aar', name: 'quickjs', group: 'fongmi', version: 'release')
|
||||
// api 'wang.harlon.quickjs:wrapper-android:2.0.0'
|
||||
|
||||
task buildCustomSpiderJar {
|
||||
doLast {
|
||||
def workDir = file("${projectDir}").parentFile
|
||||
def spiderJarDir = file("$workDir/jar/spider.jar")
|
||||
def smaliOutputDir = file("$workDir/jar/Smali_classes")
|
||||
def customSpiderJar = file("$workDir/jar/custom_spider.jar")
|
||||
def baksmaliJar = file("$workDir/jar/3rd/baksmali-2.5.2.jar")
|
||||
def apktoolJar = file("$workDir/jar/3rd/apktool_2.4.1.jar")
|
||||
def classesDex = file("$workDir/app/build/intermediates/dex/release/minifyReleaseWithR8/classes.dex")
|
||||
def indexJsonFile = file("$workDir/json/index.json")
|
||||
|
||||
// 删除旧文件
|
||||
if (customSpiderJar.exists()) {
|
||||
customSpiderJar.delete()
|
||||
}
|
||||
if (smaliOutputDir.exists()) {
|
||||
delete(smaliOutputDir)
|
||||
}
|
||||
|
||||
// 使用 baksmali 反编译 classes.dex
|
||||
javaexec {
|
||||
main = "-jar"
|
||||
args = [
|
||||
baksmaliJar.absolutePath,
|
||||
"d",
|
||||
classesDex.absolutePath,
|
||||
"-o",
|
||||
smaliOutputDir.absolutePath
|
||||
]
|
||||
}
|
||||
|
||||
// 删除 spider.jar 中的旧目录
|
||||
def targetDirs = [
|
||||
file("$spiderJarDir/smali/com/github/catvod/spider"),
|
||||
file("$spiderJarDir/smali/com/github/catvod/parser"),
|
||||
file("$spiderJarDir/smali/com/github/catvod/js")
|
||||
]
|
||||
targetDirs.each { dir ->
|
||||
if (dir.exists()) {
|
||||
delete(dir)
|
||||
}
|
||||
}
|
||||
|
||||
// 创建目标目录(如果不存在)
|
||||
def targetBaseDir = file("$spiderJarDir/smali/com/github/catvod")
|
||||
if (!targetBaseDir.exists()) {
|
||||
targetBaseDir.mkdirs()
|
||||
}
|
||||
|
||||
// 移动反编译后的目录
|
||||
def sourceDirs = [
|
||||
file("$smaliOutputDir/com/github/catvod/spider"),
|
||||
file("$smaliOutputDir/com/github/catvod/parser"),
|
||||
file("$smaliOutputDir/com/github/catvod/js")
|
||||
]
|
||||
def targetPaths = [
|
||||
file("$targetBaseDir/spider"),
|
||||
file("$targetBaseDir/parser"),
|
||||
file("$targetBaseDir/js")
|
||||
]
|
||||
|
||||
sourceDirs.eachWithIndex { src, idx ->
|
||||
if (src.exists()) {
|
||||
copy {
|
||||
from src
|
||||
into targetPaths[idx]
|
||||
}
|
||||
delete(src)
|
||||
}
|
||||
}
|
||||
|
||||
// 使用 apktool 打包
|
||||
javaexec {
|
||||
main = "-jar"
|
||||
args = [
|
||||
apktoolJar.absolutePath,
|
||||
"b",
|
||||
spiderJarDir.absolutePath,
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
|
||||
// 移动生成的 dex.jar 到 custom_spider.jar
|
||||
def distJar = file("$spiderJarDir/dist/dex.jar")
|
||||
if (distJar.exists()) {
|
||||
copy {
|
||||
from distJar
|
||||
into file("$workDir/jar")
|
||||
rename "dex.jar", "custom_spider.jar"
|
||||
}
|
||||
}
|
||||
|
||||
// 生成 MD5 校验文件
|
||||
def md5File = file("$workDir/jar/custom_spider.jar.md5")
|
||||
def md5 = java.security.MessageDigest.getInstance("MD5").digest(customSpiderJar.bytes).encodeHex().toString()
|
||||
md5File.text = md5
|
||||
|
||||
// 替换index.json md5 内容
|
||||
def indexJsonContent = indexJsonFile.text
|
||||
|
||||
// 使用正则表达式替换 spider 字段中的 MD5 值
|
||||
def updatedContent = indexJsonContent.replaceAll(
|
||||
/("spider":\s*"[^;]+;md5;)[^"]+"/,
|
||||
'$1' + md5 + '"'
|
||||
)
|
||||
|
||||
// 写回文件
|
||||
indexJsonFile.write(updatedContent)
|
||||
|
||||
// 清理临时目录
|
||||
delete(
|
||||
"$spiderJarDir/build",
|
||||
"$spiderJarDir/smali",
|
||||
"$spiderJarDir/dist",
|
||||
smaliOutputDir
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
tasks.named('buildCustomSpiderJar') {
|
||||
dependsOn 'assembleRelease'
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
|
@ -39,17 +39,4 @@
|
|||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
# Please add these rules to your existing keep rules in order to suppress warnings.
|
||||
# This is generated automatically by the Android Gradle plugin.
|
||||
-dontwarn org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
|
||||
|
||||
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
|
||||
|
||||
# 禁用代码混淆
|
||||
#-dontobfuscate
|
||||
}
|
||||
|
|
@ -507,7 +507,7 @@ public class AliYun {
|
|||
Map<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
List<String> keys = Arrays.asList("referer", "icy-metadata", "range", "connection", "accept-encoding", "user-agent");
|
||||
for (String key : params.keySet()) if (keys.contains(key)) headers.put(key, params.get(key));
|
||||
return ProxyVideo.proxyMultiThread(downloadUrl, headers);
|
||||
return ProxyVideo.proxy(downloadUrl, headers);
|
||||
}
|
||||
|
||||
private String getM3u8Url(String shareId, String fileId, String templateId) {
|
||||
|
|
|
|||
|
|
@ -1,262 +0,0 @@
|
|||
package com.github.catvod.api
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.text.TextUtils
|
||||
import android.view.Gravity
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import com.github.catvod.bean.BD.Cache
|
||||
import com.github.catvod.bean.yun.User
|
||||
import com.github.catvod.crawler.SpiderDebug
|
||||
import com.github.catvod.net.OkHttp
|
||||
import com.github.catvod.spider.Init
|
||||
import com.github.catvod.utils.*
|
||||
import okhttp3.Headers
|
||||
import okhttp3.Request
|
||||
import org.apache.commons.lang3.StringEscapeUtils
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.UnsupportedEncodingException
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.ScheduledExecutorService
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.concurrent.Volatile
|
||||
|
||||
|
||||
class BaiDuYunHandler private constructor() {
|
||||
private val cache: Cache
|
||||
private var service: ScheduledExecutorService? = null
|
||||
private var dialog: AlertDialog? = null
|
||||
private var cookies = ""
|
||||
private val headers = mapOf(
|
||||
"User-Agent" to "Mozilla/5.0 (Linux; Android 12; SM-X800) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.40 Safari/537.36",
|
||||
"Accept" to "application/json, text/plain, */*",
|
||||
"Content-Type" to "application/x-www-form-urlencoded",
|
||||
"Origin" to "https://pan.baidu.com",
|
||||
"Referer" to "https://pan.baidu.com/"
|
||||
)
|
||||
|
||||
fun getCache(): File {
|
||||
return Path.tv("bd")
|
||||
}
|
||||
|
||||
init {
|
||||
cache = Cache.objectFrom(Path.read(getCache()))
|
||||
}
|
||||
|
||||
private object Loader {
|
||||
@Volatile
|
||||
var INSTANCE: BaiDuYunHandler = BaiDuYunHandler()
|
||||
}
|
||||
|
||||
val token: String
|
||||
get() {
|
||||
val user: User = cache.getUser()
|
||||
return user.getCookie()
|
||||
//return "cGM6MTg4OTY3ODE2MDE6eTM1Tjd1dG58MXxSQ1N8MTc1NDQ2OTgwNzEyOXxzMlN0T1VEV3lOVmF5V3pNbGFfM2tJbVp1ZmlqSHBqaEhTSzVyNHZqVXNRLmlhV3loSUxHNDFkMUI5N1BqXzhWN0dtVWtKLnBTclhpNGpZU1EuTGZWMTV3MVFoZmNpcEVoZkxUV2tvYjB0bkFTYV9RTUhhaHhveWx6YkdmcEhQdjNCS1lrbnp1LkxaWDdKOE40YkNNRjkzT3piNmx2Y0d3TWdVUkl5b18ubVUt";
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun get(): BaiDuYunHandler {
|
||||
return Loader.INSTANCE
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(java.lang.Exception::class)
|
||||
fun startScan(): ByteArray {
|
||||
val result = loginByQRCode()
|
||||
// Step 2: Get QR Code
|
||||
val byteStr: ByteArray = downloadQRCode(result["qrCodeImageUrl"]!!);
|
||||
|
||||
Init.run(Runnable { showQRCode(byteStr) })
|
||||
// Step 3: Check login status
|
||||
|
||||
Init.execute(Runnable {
|
||||
startService(
|
||||
result["sign"]!!
|
||||
)
|
||||
})
|
||||
return byteStr
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun downloadQRCode(url: String): ByteArray {
|
||||
val headers: MutableMap<String?, String?> = HashMap<String?, String?>()
|
||||
headers.put(
|
||||
"user-agent",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36"
|
||||
)
|
||||
|
||||
|
||||
val request = Request.Builder().url(url).headers(Headers.of(headers)).build()
|
||||
val response = OkHttp.newCall(request)
|
||||
if (response.code() == 200) {
|
||||
return response.body()!!.bytes()
|
||||
}
|
||||
return "".toByteArray()
|
||||
}
|
||||
|
||||
fun loginByQRCode(): Map<String, String> {
|
||||
return try {
|
||||
// 获取登录二维码
|
||||
val timestamp = System.currentTimeMillis()
|
||||
val qrCodeUrl = "https://passport.baidu.com/v2/api/getqrcode?lp=pc&_=$timestamp"
|
||||
|
||||
val response = OkHttp.string(qrCodeUrl, emptyMap(), headers)
|
||||
val json = Json.safeObject(response)
|
||||
|
||||
if (json["errno"].asInt != 0) {
|
||||
return mapOf("error" to "获取登录二维码错误, code: ${json["errno"].asInt}")
|
||||
}
|
||||
|
||||
val sign = json["sign"].asString
|
||||
val imgurl = json["imgurl"].asString
|
||||
val qrCodeImageUrl = "https://$imgurl"
|
||||
|
||||
val qrLoginUrl =
|
||||
"https://wappass.baidu.com/wp/?qrlogin&t=$timestamp" + "&error=0&sign=$sign&cmd=login&lp=pc&tpl=netdisk&uaonly=" + "&client_id=&adapter=3&client=&qrloginfrom=pc&wechat=0&traceid="
|
||||
|
||||
// 返回二维码信息供前端显示
|
||||
val result = mapOf(
|
||||
"qrCodeImageUrl" to qrCodeImageUrl, "qrLoginUrl" to qrLoginUrl, "sign" to sign
|
||||
)
|
||||
|
||||
result
|
||||
} catch (e: Exception) {
|
||||
mapOf("error" to "获取二维码失败: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
fun checkQRLoginStatus(sign: String): Map<String, Any> {
|
||||
return try {
|
||||
val timestamp = System.currentTimeMillis()
|
||||
val checkUrl =
|
||||
"https://passport.baidu.com/channel/unicast?channel_id=$sign" + "&tpl=netdisk&callback=&apiver=v3&tt=$timestamp&_=$timestamp"
|
||||
|
||||
val response = OkHttp.string(checkUrl, emptyMap(), headers)
|
||||
val cleanResponse = response.trim('(', ' ', '\n', ')')
|
||||
val json = Json.safeObject(cleanResponse)
|
||||
|
||||
if (json["errno"].asInt == 0) {
|
||||
SpiderDebug.log("百度扫码成功")
|
||||
val channelV = json["channel_v"].asString
|
||||
val channelJson = Json.safeObject(channelV)
|
||||
|
||||
if (channelJson["status"].asInt == 0) {
|
||||
val bduss = channelJson["v"].asString
|
||||
|
||||
// 执行登录
|
||||
val loginTimestamp = System.currentTimeMillis()
|
||||
val loginUrl =
|
||||
"https://passport.baidu.com/v3/login/main/qrbdusslogin?" + "v=$loginTimestamp&bduss=$bduss&u=&loginVersion=v4&qrcode=1&tpl=netdisk&apiver=v3" + "&tt=$loginTimestamp&traceid=&callback=bd__cbs__cupstt"
|
||||
|
||||
val loginResponse = OkHttp.get(loginUrl, emptyMap(), headers)
|
||||
val cleanLoginResponse = loginResponse.body.substringAfter("(").substringBeforeLast(")")
|
||||
val loginJson = Json.safeObject(StringEscapeUtils.unescapeHtml4(cleanLoginResponse))
|
||||
|
||||
if (loginJson.has("errInfo") && loginJson["errInfo"].asJsonObject["no"].asString == "0") {
|
||||
// 登录成功,设置cookie
|
||||
SpiderDebug.log("百度登录成功,设置cookie:${bduss}")
|
||||
cookies = "BDUSS=$bduss"
|
||||
cookies = generateCooike(loginResponse.resp["set-cookie"])
|
||||
|
||||
if (cookies.isNotEmpty()) {
|
||||
cache.setUser(User.objectFrom(this.cookies))
|
||||
//停止检验线程,关闭弹窗
|
||||
stopService()
|
||||
Notify.show("百度登录成功")
|
||||
|
||||
}
|
||||
|
||||
|
||||
mapOf("success" to true, "bduss" to bduss)
|
||||
} else {
|
||||
mapOf("error" to "登录失败: $cleanLoginResponse")
|
||||
}
|
||||
} else {
|
||||
mapOf("status" to channelJson["status"].asInt)
|
||||
}
|
||||
} else {
|
||||
mapOf("errno" to json["errno"].asInt)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
mapOf("error" to "检查登录状态失败: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
fun generateCooike(cookies: List<String>?): String {
|
||||
if (cookies == null || cookies.isEmpty()) {
|
||||
return ""
|
||||
}
|
||||
|
||||
val cookieList: MutableList<String?> = ArrayList<String?>()
|
||||
for (cookie in cookies) {
|
||||
cookieList.add(cookie.split(";".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0])
|
||||
}
|
||||
return TextUtils.join(";", cookieList)
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示qrcode
|
||||
*
|
||||
* @param base64Str
|
||||
*/
|
||||
fun showQRCode(bytes: ByteArray) {
|
||||
try {
|
||||
val size = ResUtil.dp2px(240)
|
||||
val params = FrameLayout.LayoutParams(size, size)
|
||||
val image = ImageView(Init.context())
|
||||
image.setScaleType(ImageView.ScaleType.CENTER_CROP)
|
||||
image.setImageBitmap(QRCode.Bytes2Bimap(bytes))
|
||||
val frame = FrameLayout(Init.context())
|
||||
params.gravity = Gravity.CENTER
|
||||
frame.addView(image, params)
|
||||
dialog = AlertDialog.Builder(Init.getActivity()).setView(frame)
|
||||
.setOnCancelListener(DialogInterface.OnCancelListener { dialog: DialogInterface? -> this.dismiss(dialog) })
|
||||
.setOnDismissListener(DialogInterface.OnDismissListener { dialog: DialogInterface? ->
|
||||
this.dismiss(dialog)
|
||||
}).show()
|
||||
dialog!!.getWindow()!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
Notify.show("请使用百度网盘App扫描二维码")
|
||||
} catch (ignored: java.lang.Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun dismiss() {
|
||||
try {
|
||||
dialog?.dismiss()
|
||||
} catch (ignored: java.lang.Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun dismiss(dialog: DialogInterface?) {
|
||||
stopService()
|
||||
}
|
||||
|
||||
private fun stopService() {
|
||||
service?.shutdownNow()
|
||||
Init.run(Runnable { this.dismiss() })
|
||||
}
|
||||
|
||||
fun startService(sign: String) {
|
||||
SpiderDebug.log("----start 百度 token service")
|
||||
|
||||
service = Executors.newScheduledThreadPool(1)
|
||||
|
||||
service?.scheduleWithFixedDelay(Runnable {
|
||||
try {
|
||||
SpiderDebug.log("----check百度tatus中")
|
||||
|
||||
checkQRLoginStatus(sign)
|
||||
} catch (e: UnsupportedEncodingException) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}, 3, 3, TimeUnit.SECONDS)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,797 +0,0 @@
|
|||
package com.github.catvod.api
|
||||
|
||||
import com.github.catvod.bean.Result
|
||||
import com.github.catvod.bean.Vod
|
||||
import com.github.catvod.bean.Vod.VodPlayBuilder
|
||||
import com.github.catvod.net.OkHttp
|
||||
import com.github.catvod.utils.Json
|
||||
import com.github.catvod.utils.ProxyServer.buildProxyUrl
|
||||
import com.github.catvod.utils.Util
|
||||
import com.github.catvod.utils.Util.MEDIA
|
||||
import com.google.gson.JsonObject
|
||||
import java.net.URLEncoder
|
||||
import java.util.*
|
||||
|
||||
object BaiduDrive {
|
||||
private val cache = mutableMapOf<String, String>();
|
||||
|
||||
private val headers = mapOf(
|
||||
"User-Agent" to "Mozilla/5.0 (Linux; Android 12; SM-X800) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.40 Safari/537.36",
|
||||
"Accept" to "application/json, text/plain, */*",
|
||||
"Content-Type" to "application/x-www-form-urlencoded",
|
||||
"Origin" to "https://pan.baidu.com",
|
||||
"Referer" to "https://pan.baidu.com/"
|
||||
)
|
||||
|
||||
//是否删除过文件标志
|
||||
private var deleteTag = 0;
|
||||
private val saveDirName = "TVBOX_BD"
|
||||
|
||||
private var cookies = BaiDuYunHandler.get().token
|
||||
|
||||
|
||||
private val apiHost = "https://pan.baidu.com"
|
||||
private val displayName = listOf("BD原画")
|
||||
|
||||
|
||||
fun setCookie(extend: String) {
|
||||
if (extend.isEmpty()) return
|
||||
cookies = extend
|
||||
}
|
||||
|
||||
fun processShareLinks(urls: List<String>): Pair<List<String>, List<String>> {
|
||||
|
||||
//首先确保cookie不为空
|
||||
if (cookies.isEmpty()) {
|
||||
BaiDuYunHandler.get().startScan()
|
||||
cookies = BaiDuYunHandler.get().token
|
||||
}
|
||||
if (urls.isEmpty()) return emptyList<String>() to emptyList()
|
||||
|
||||
|
||||
val results = urls.map { url ->
|
||||
processSingleLink(url)
|
||||
}
|
||||
|
||||
val names = mutableListOf<String>()
|
||||
val allVideos = mutableListOf<String>()
|
||||
|
||||
results.forEach { result ->
|
||||
if (result != null) {
|
||||
val (avideos, videos) = result
|
||||
names.addAll(displayName)
|
||||
allVideos.add(avideos.joinToString("#"))
|
||||
//allVideos.add(videos.joinToString("#"))
|
||||
}
|
||||
}
|
||||
|
||||
return names to allVideos
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fun processSingleLink(url: String): Pair<List<String>, List<String>>? {
|
||||
return try {
|
||||
val urlInfo = parseShareUrl(url)
|
||||
if (urlInfo.containsKey("error")) return null
|
||||
|
||||
val tokenInfo = getShareToken(urlInfo)
|
||||
if (tokenInfo?.containsKey("error") == true) return null
|
||||
|
||||
getAllVideos(tokenInfo!!)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseShareUrl(url: String): Map<String, String> {
|
||||
var lurl = url
|
||||
if ("提取码" in url) lurl = url.replace("提取码:", "?pwd=")
|
||||
|
||||
if ("/share/" !in url) {
|
||||
val response = OkHttp.getLocation(url, headers)
|
||||
lurl = response ?: ""
|
||||
}
|
||||
|
||||
val queryParams = parseQueryParams(lurl)
|
||||
val finalUrl = if ("/share/" in url) url.replace("share/init?surl=", "s/1") else url
|
||||
|
||||
return mapOf<String, String>(
|
||||
"url" to finalUrl,
|
||||
"surl" to (queryParams["surl"]?.firstOrNull() ?: ""),
|
||||
"pwd" to (queryParams["pwd"]?.firstOrNull() ?: "")
|
||||
)
|
||||
}
|
||||
|
||||
private fun getShareToken(urlInfo: Map<String, String>): Map<String, String>? {
|
||||
val params = mapOf(
|
||||
"t" to System.currentTimeMillis().toString(), "surl" to (urlInfo["surl"] ?: "")
|
||||
)
|
||||
|
||||
val data = mapOf("pwd" to (urlInfo["pwd"] ?: ""))
|
||||
|
||||
val response = OkHttp.post(
|
||||
"$apiHost/share/verify?t=${params["t"]}&surl=${params["surl"]}", data, headers
|
||||
)
|
||||
|
||||
// if ("error" in response) return response
|
||||
val json = Json.safeObject(response.body)
|
||||
|
||||
|
||||
val randsk = json.asJsonObject.get("randsk").asString ?: return mapOf("error" to "获取randsk失败")
|
||||
|
||||
return mapOf(
|
||||
"yurl" to (urlInfo["url"]?.split("s/")?.last()?.split("?")?.first() ?: ""),
|
||||
"randsk" to randsk,
|
||||
"surl" to (urlInfo["surl"] ?: "")
|
||||
)
|
||||
}
|
||||
|
||||
private fun getAllVideos(tokenInfo: Map<String, String>): Pair<List<String>, List<String>> {
|
||||
val videos = mutableListOf<String>()
|
||||
val avideos = mutableListOf<String>()
|
||||
val seenFolders = mutableSetOf<String>()
|
||||
val pendingFolders = mutableListOf<Map<String, Any>>()
|
||||
|
||||
try {
|
||||
// 处理根目录
|
||||
var currentPage = 1
|
||||
var uk = ""
|
||||
var shareid = ""
|
||||
|
||||
while (true) {
|
||||
val rootFolder = mutableMapOf(
|
||||
"surl" to tokenInfo["surl"]!!,
|
||||
"randsk" to tokenInfo["randsk"]!!,
|
||||
"page" to currentPage,
|
||||
"is_root" to true
|
||||
)
|
||||
|
||||
val rootResult = getFolderContents(rootFolder)
|
||||
// if ("error" in rootResult) break
|
||||
val data = rootResult?.asJsonObject
|
||||
|
||||
val items = data?.get("list")?.asJsonArray ?: break
|
||||
|
||||
if (items.isEmpty) break
|
||||
|
||||
// 第一页获取uk和shareid
|
||||
if (currentPage == 1) {
|
||||
uk = data["uk"]?.toString() ?: ""
|
||||
shareid = data["share_id"]?.toString() ?: ""
|
||||
if (uk.isEmpty() || shareid.isEmpty()) return emptyList<String>() to emptyList()
|
||||
}
|
||||
|
||||
// 处理items
|
||||
items.forEach { item ->
|
||||
if (item.asJsonObject["isdir"].asInt == 1) {
|
||||
val folderPath =
|
||||
"/sharelink$uk-${item.asJsonObject["fs_id"].asString}/${item.asJsonObject["server_filename"].asString}"
|
||||
if (folderPath !in seenFolders) {
|
||||
seenFolders.add(folderPath)
|
||||
pendingFolders.add(
|
||||
mapOf(
|
||||
"surl" to tokenInfo["surl"]!!,
|
||||
"randsk" to tokenInfo["randsk"]!!,
|
||||
"uk" to uk,
|
||||
"shareid" to shareid,
|
||||
"dir" to folderPath,
|
||||
"page" to 1
|
||||
)
|
||||
)
|
||||
}
|
||||
} else if (isVideoFile(item.asJsonObject["server_filename"].asString ?: "")) {
|
||||
addVideo(item.asJsonObject, uk, shareid, tokenInfo, avideos, videos)
|
||||
}
|
||||
}
|
||||
|
||||
if (items.size() < 9999) break
|
||||
currentPage++
|
||||
}
|
||||
|
||||
// 处理子文件夹
|
||||
while (pendingFolders.isNotEmpty()) {
|
||||
val currentBatch = pendingFolders.toList()
|
||||
pendingFolders.clear()
|
||||
|
||||
val results = currentBatch.map { folderInfo ->
|
||||
getFolderContents(folderInfo)
|
||||
}
|
||||
|
||||
results.forEachIndexed { i, result ->
|
||||
val folderInfo = currentBatch[i]
|
||||
//if ("error" in result) return@forEachIndexed
|
||||
|
||||
val items = result?.asJsonObject?.get("list")?.asJsonArray ?: return@forEachIndexed
|
||||
|
||||
items.forEach { item ->
|
||||
if (item.asJsonObject["isdir"].asInt == 1) {
|
||||
val folderPath = item.asJsonObject["path"].asString ?: ""
|
||||
if (folderPath !in seenFolders) {
|
||||
seenFolders.add(folderPath)
|
||||
pendingFolders.add(
|
||||
mapOf(
|
||||
"surl" to tokenInfo["surl"]!!,
|
||||
"randsk" to tokenInfo["randsk"]!!,
|
||||
"uk" to folderInfo["uk"]!!,
|
||||
"shareid" to folderInfo["shareid"]!!,
|
||||
"dir" to folderPath,
|
||||
"page" to 1
|
||||
)
|
||||
)
|
||||
}
|
||||
} else if (isVideoFile(item.asJsonObject["server_filename"].asString ?: "")) {
|
||||
addVideo(
|
||||
item.asJsonObject,
|
||||
folderInfo["uk"]?.toString() ?: "",
|
||||
folderInfo["shareid"]?.toString() ?: "",
|
||||
tokenInfo,
|
||||
avideos,
|
||||
videos
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (items.size() >= 9999) {
|
||||
pendingFolders.add(folderInfo.toMutableMap().apply {
|
||||
this["page"] = (this["page"] as Int) + 1
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return avideos to videos
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return emptyList<String>() to emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isVideoFile(string: String): Boolean {
|
||||
|
||||
return string.substringAfterLast(".").lowercase(Locale.ROOT) in MEDIA
|
||||
}
|
||||
|
||||
private fun addVideo(
|
||||
item: JsonObject,
|
||||
uk: String,
|
||||
shareid: String,
|
||||
tokenInfo: Map<String, String>,
|
||||
avideos: MutableList<String>,
|
||||
videos: MutableList<String>
|
||||
) {
|
||||
val sizeStr = formatSize(item["size"].asLong)
|
||||
val name = item["server_filename"] ?: ""
|
||||
|
||||
val originalData = mapOf(
|
||||
"uk" to uk,
|
||||
"shareid" to shareid,
|
||||
"fid" to item["fs_id"],
|
||||
"randsk" to tokenInfo["randsk"],
|
||||
"pname" to name,
|
||||
"qtype" to "original"
|
||||
)
|
||||
|
||||
val previewData = mapOf(
|
||||
"uk" to uk,
|
||||
"fid" to item["fs_id"],
|
||||
"shareid" to shareid,
|
||||
"surl" to tokenInfo["yurl"],
|
||||
"pname" to name,
|
||||
"qtype" to "preview"
|
||||
)
|
||||
|
||||
avideos.add(
|
||||
"[$sizeStr]$name$${
|
||||
Util.base64Encode(Json.toJson(originalData).toByteArray())
|
||||
}"
|
||||
)
|
||||
videos.add(
|
||||
"[$sizeStr]$name$${
|
||||
Util.base64Encode(Json.toJson(previewData).toByteArray())
|
||||
}"
|
||||
)
|
||||
}
|
||||
|
||||
private fun getFolderContents(folderInfo: Map<String, Any>): JsonObject? {
|
||||
val params = if (folderInfo.containsKey("dir")) {
|
||||
mapOf(
|
||||
"uk" to folderInfo["uk"]!!.toString(),
|
||||
"shareid" to folderInfo["shareid"]!!.toString(),
|
||||
"page" to folderInfo["page"].toString(),
|
||||
"num" to "9999",
|
||||
"dir" to URLEncoder.encode(folderInfo["dir"]!!.toString()),
|
||||
"desc" to "0",
|
||||
"order" to "name",
|
||||
)
|
||||
} else {
|
||||
mapOf(
|
||||
"page" to folderInfo["page"].toString(),
|
||||
"num" to "9999",
|
||||
"shorturl" to folderInfo["surl"]!!.toString(),
|
||||
"root" to "1",
|
||||
"desc" to "0",
|
||||
"order" to "name",
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
val tempHeader = headers.toMutableMap()
|
||||
tempHeader.put("Cookie", "BDCLND=${folderInfo["randsk"]}")
|
||||
val result = OkHttp.string("$apiHost/share/list", params, tempHeader)
|
||||
return Json.safeObject(result)
|
||||
|
||||
}
|
||||
|
||||
|
||||
private fun parseQueryParams(url: String): Map<String, List<String>> {
|
||||
val query = url.substringAfter(
|
||||
"?"
|
||||
).substringBefore('#')
|
||||
return query.split('&').associate {
|
||||
val (key, value) = it.split('=', limit = 2)
|
||||
key to listOf(value)
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatSize(bytes: Long): String {
|
||||
if (bytes <= 0) return "0 B"
|
||||
val units = arrayOf("B", "KB", "MB", "GB", "TB")
|
||||
val digitGroups = (Math.log10(bytes.toDouble()) / Math.log10(1024.0)).toInt()
|
||||
return "%.1f %s".format(bytes / Math.pow(1024.0, digitGroups.toDouble()), units[digitGroups])
|
||||
}
|
||||
|
||||
|
||||
fun getBdUid(): String? {
|
||||
if (cache["uid"] != null) {
|
||||
return cache["uid"]
|
||||
}
|
||||
val tempHeader = headers.toMutableMap()
|
||||
tempHeader.put("Cookie", cookies)
|
||||
try {
|
||||
val response = OkHttp.string(
|
||||
|
||||
"https://mbd.baidu.com/userx/v1/info/get?appname=baiduboxapp&fields=%20%20%20%20%20%20%20%20%5B%22bg_image%22,%22member%22,%22uid%22,%22avatar%22,%20%22avatar_member%22%5D&client&clientfrom&lang=zh-cn&tpl&ttt",
|
||||
emptyMap<String, String>(),
|
||||
tempHeader
|
||||
|
||||
)
|
||||
|
||||
val responseJson = Json.safeObject(response)
|
||||
val user = responseJson["data"].asJsonObject
|
||||
|
||||
val fields = user?.get("fields")?.asJsonObject
|
||||
|
||||
val uidValue = fields?.get("uid")?.asString
|
||||
|
||||
if (uidValue != null) {
|
||||
cache["uid"] = uidValue
|
||||
return uidValue
|
||||
} else {
|
||||
throw Exception("Failed to retrieve UID from Baidu Drive.")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
println("获取百度网盘用户ID失败: ${e.message}")
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
fun _getSign(videoData: JsonObject): Pair<String, String> {
|
||||
val tempHeader = headers.toMutableMap()
|
||||
tempHeader.put("Cookie", cookies)
|
||||
val response: String? = OkHttp.string(
|
||||
"${apiHost}/share/tplconfig", mapOf<String, String>(
|
||||
"surl" to videoData["surl"].asString, "fields" to "cfrom_id,Espace_info,card_info,sign,timestamp"
|
||||
),
|
||||
|
||||
tempHeader
|
||||
)
|
||||
return try {
|
||||
val data = Json.safeObject(response)["data"].asJsonObject
|
||||
|
||||
data["sign"].asString to data["timestamp"].asString
|
||||
} catch (_: Exception) {
|
||||
"" to ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun _getDownloadUrl(videoData: JsonObject): String {
|
||||
return try {
|
||||
var cookie = ""
|
||||
val BDCLND = "BDCLND=" + videoData["randsk"].asString
|
||||
// 更新Cookie中的BDCLND值
|
||||
if (!this.cookies.contains("BDCLND")) {
|
||||
cookie = this.cookies + ";" + BDCLND
|
||||
|
||||
} else {
|
||||
cookie = this.cookies.split(";").joinToString(";") {
|
||||
if (it.contains("BDCLND")) {
|
||||
BDCLND
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
val transferHeaders = mapOf(
|
||||
"User-Agent" to "Android",
|
||||
"Connection" to "Keep-Alive",
|
||||
"Content-Type" to "application/x-www-form-urlencoded",
|
||||
"Accept-Language" to "zh-CN,zh;q=0.8",
|
||||
"charset" to "UTF-8",
|
||||
"Referer" to "https://pan.baidu.com",
|
||||
"Cookie" to cookie
|
||||
)
|
||||
// 先清空文件夹在创建文件夹
|
||||
|
||||
if (deleteTag == 0) {
|
||||
_deleteTransferFile("/$saveDirName")
|
||||
//创建路径
|
||||
createSaveDir()
|
||||
deleteTag = 1
|
||||
}
|
||||
|
||||
|
||||
val data =
|
||||
"from=${videoData["uk"].asString}&shareid=${videoData["shareid"].asString}&ondup=newcopy&path=/${saveDirName}&fsidlist=[${videoData["fid"].asString}]"
|
||||
|
||||
var to = ""
|
||||
for (i in 1..30) {
|
||||
|
||||
|
||||
val response =
|
||||
OkHttp.post("${apiHost}/share/transfer?${data}", emptyMap<String, String>(), transferHeaders)
|
||||
|
||||
val result = Json.safeObject(response.body)
|
||||
|
||||
try {
|
||||
to = (result["extra"].asJsonObject)["list"].asJsonArray[0].asJsonObject["to"].asString
|
||||
// videoData["to"] = to
|
||||
if (to.isNotEmpty()) {
|
||||
println("成功转存文件到: $to")
|
||||
break
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
println("解析转存响应出错: ${e.message}")
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if (to.isEmpty()) {
|
||||
println("转存文件失败,无法获取下载链接")
|
||||
return ""
|
||||
}
|
||||
|
||||
val mediaInfoHeaders = mapOf(
|
||||
|
||||
"User-Agent" to "netdisk;1.4.2;22021211RC;android-android;12;JSbridge4.4.0;jointBridge;1.1.0;",
|
||||
"Connection" to "Keep-Alive",
|
||||
"Accept-Language" to "zh-CN,zh;q=0.8",
|
||||
"charset" to "UTF-8",
|
||||
"Cookie" to cookie
|
||||
).toMutableMap()
|
||||
|
||||
|
||||
val mediaInfoParams = mapOf(
|
||||
"type" to "M3U8_FLV_264_480", "path" to "/$to", "clienttype" to "80", "origin" to "dlna"
|
||||
)
|
||||
|
||||
|
||||
val mediaInfoResponse: String? = OkHttp.string(
|
||||
"${apiHost}/api/mediainfo", mediaInfoParams, mediaInfoHeaders
|
||||
)
|
||||
val responseJson = Json.safeObject(mediaInfoResponse)
|
||||
val info = responseJson["info"].asJsonObject
|
||||
val downloadUrl = info["dlink"].asString
|
||||
println("获取到下载链接: $downloadUrl")
|
||||
downloadUrl
|
||||
} catch (e: Exception) {
|
||||
println("获取下载链接过程中出错: ${e.message}")
|
||||
e.printStackTrace()
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
fun getVideoUrl(videoData: JsonObject, flag: String): Map<String, Any> {
|
||||
return try {
|
||||
val bdUid = getBdUid()
|
||||
println("获取百度网盘用户ID: $bdUid")
|
||||
|
||||
if (flag.contains("原画")) {
|
||||
|
||||
var headersApp = mapOf("User-Agent" to "netdisk;P2SP;2.2.91.136;android-android;")
|
||||
|
||||
var downloadUrl = _getAppDownloadUrl(videoData)
|
||||
if (downloadUrl.isEmpty()) {
|
||||
|
||||
headersApp = mapOf(
|
||||
|
||||
"User-Agent" to "netdisk;1.4.2;22021211RC;android-android;12;JSbridge4.4.0;jointBridge;1.1.0;"
|
||||
)
|
||||
|
||||
downloadUrl = _getDownloadUrl(videoData)
|
||||
}
|
||||
if (downloadUrl.isNotEmpty()) {
|
||||
|
||||
val result = mapOf(
|
||||
"parse" to "0", "url" to downloadUrl, "header" to headersApp
|
||||
)
|
||||
|
||||
result
|
||||
} else {
|
||||
_handleError
|
||||
}
|
||||
} else {
|
||||
val (sign, time) = _getSign(videoData)
|
||||
if (sign.isEmpty() || time.isEmpty()) {
|
||||
return _handleError
|
||||
}
|
||||
val plist = _getPlayList(videoData, sign, time)
|
||||
val tempHeader = headers.toMutableMap()
|
||||
tempHeader.put("Cookie", cookies)
|
||||
mapOf(
|
||||
"parse" to "0", "url" to plist[0], "header" to tempHeader
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
println("获取播放链接失败: ${e.message}")
|
||||
_handleError
|
||||
}
|
||||
}
|
||||
|
||||
private fun _getAppDownloadUrl(videoData: JsonObject): String {
|
||||
return try {
|
||||
val headers = mapOf<String, String>(
|
||||
|
||||
"User-Agent" to "netdisk;P2SP;2.2.91.136;android-android;",
|
||||
"Connection" to "Keep-Alive",
|
||||
"Accept-Language" to "zh-CN,zh;q=0.8",
|
||||
"charset" to "UTF-8",
|
||||
"cookie" to cookies
|
||||
)
|
||||
val uid = this.getBdUid()
|
||||
val t = System.currentTimeMillis()
|
||||
val params = mapOf<String, String>(
|
||||
"shareid" to videoData["shareid"].asString,
|
||||
"uk" to videoData["uk"].asString,
|
||||
"fid" to videoData["fid"].asString,
|
||||
"sekey" to unquote(videoData["randsk"].asString),
|
||||
"origin" to "dlna",
|
||||
"devuid" to "73CED981D0F186D12BC18CAE1684FFD5|VSRCQTF6W",
|
||||
"clienttype" to "1",
|
||||
"channel" to "android_12_zhao_bd-netdisk_1024266h",
|
||||
"version" to "11.30.2",
|
||||
"time" to t.toString()
|
||||
).toMutableMap()
|
||||
|
||||
val randstr = this.sha1(
|
||||
this.sha1(
|
||||
Util.findByRegex(
|
||||
"BDUSS=(.+?);", cookies, 1
|
||||
)
|
||||
) + uid + "ebrcUYiuxaZv2XGu7KIYKxUrqfnOfpDF$t${params["devuid"]}11.30.2ae5821440fab5e1a61a025f014bd8972"
|
||||
)
|
||||
|
||||
params.put("rand", randstr)
|
||||
|
||||
val response = OkHttp.string(
|
||||
"${apiHost}/share/list", params, headers
|
||||
)
|
||||
val json = Json.safeObject(response)
|
||||
val dlink = json["list"].asJsonArray[0].asJsonObject["dlink"].asString
|
||||
|
||||
/* val url = response["data"] as Map<String, Any>
|
||||
val list = url["list"] as List<Map<String, Any>>
|
||||
val dlink = list[0]["dlink"] as String
|
||||
|
||||
val pDataResponse = client.get(dlink) {
|
||||
headers { this@_getAppDownloadUrl.headers.forEach { name, value -> append(name, value) } }
|
||||
cookies?.let { setCookie(it) }
|
||||
followRedirects = false
|
||||
timeout.socketTimeoutMillis = 10000
|
||||
}
|
||||
|
||||
val pUrl = pDataResponse.headers[HttpHeaders.Location]?.toString()
|
||||
pUrl ?: dlink*/
|
||||
dlink
|
||||
} catch (e: Exception) {
|
||||
println("获取下载链接失败: ${e.message}")
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
private fun _getPlayList(videoData: JsonObject, sign: String, time: String): List<String> {
|
||||
val hz = getPlayFormatList()
|
||||
val plist = mutableListOf<String>()
|
||||
|
||||
for (quality in hz) {
|
||||
val url =
|
||||
("${apiHost}/share/streaming?" + "uk=${videoData["uk"].asString}&" + "fid=${videoData["fid"].asString}&" + "sign=$sign&" + "timestamp=$time&" + "shareid=${videoData["shareid"].asString}&" + "type=M3U8_AUTO_${
|
||||
quality.replace(
|
||||
"P", ""
|
||||
)
|
||||
}")
|
||||
plist.add(url)
|
||||
}
|
||||
|
||||
return plist
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建保存目录
|
||||
*/
|
||||
fun createSaveDir(): Long? {
|
||||
var saveDirId: Long? = null
|
||||
// 创建保存目录
|
||||
if (cookies.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
val tempHeader = headers.toMutableMap()
|
||||
tempHeader.put("Cookie", cookies)
|
||||
return try {
|
||||
val listResp = OkHttp.string(
|
||||
"${apiHost}/api/list", mapOf(
|
||||
"dir" to "/",
|
||||
"order" to "name",
|
||||
"desc" to "0",
|
||||
"showempty" to "0",
|
||||
"web" to "1",
|
||||
"app_id" to "250528"
|
||||
), tempHeader
|
||||
)
|
||||
val json = Json.safeObject(listResp)
|
||||
|
||||
if (json["errno"].asInt != 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
val drpyDir = json["list"].asJsonArray.find { item ->
|
||||
item.asJsonObject.get("isdir").asInt == 1 && item.asJsonObject.get("server_filename").asString == saveDirName
|
||||
|
||||
}
|
||||
|
||||
if (drpyDir != null) {
|
||||
saveDirId = drpyDir.asJsonObject.get("fs_id").asLong
|
||||
return saveDirId
|
||||
}
|
||||
|
||||
val createResp = OkHttp.post(
|
||||
"${apiHost}/api/create?a=commit&bdstoken=${getBdstoken()}&clienttype=0&app_id=250528&web=1&dp-logid=73131200762376420075",
|
||||
mapOf(
|
||||
"path" to "//$saveDirName",
|
||||
"isdir" to "1",
|
||||
"block_list" to "[]",
|
||||
|
||||
),
|
||||
tempHeader
|
||||
)
|
||||
val createJson = Json.safeObject(createResp.body)
|
||||
|
||||
|
||||
|
||||
saveDirId = createJson["fs_id"].asLong
|
||||
saveDirId
|
||||
|
||||
} catch (e: Exception) {
|
||||
println("创建保存目录失败: ${e.message}")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun getBdstoken(): String {
|
||||
if (cache["bdstoken"] != null) {
|
||||
return cache["bdstoken"]!!
|
||||
}
|
||||
val tempHeader = headers.toMutableMap()
|
||||
tempHeader.put("Cookie", cookies)
|
||||
val userInfo = OkHttp.string(
|
||||
"${apiHost}/api/gettemplatevariable?clienttype=0&app_id=250528&web=1&fields=[\"bdstoken\",\"token\",\"uk\",\"isdocuser\",\"servertime\"]",
|
||||
mapOf(),
|
||||
tempHeader
|
||||
|
||||
)
|
||||
val json = Json.safeObject(userInfo)
|
||||
|
||||
val bdstoken: String? = json["result"]?.asJsonObject?.get("bdstoken")?.asString
|
||||
cache["bdstoken"] = bdstoken ?: ""
|
||||
return bdstoken ?: ""
|
||||
}
|
||||
|
||||
|
||||
private fun _deleteTransferFile(filePath: String) {
|
||||
try {
|
||||
val url =
|
||||
"$apiHost/api/filemanager?async=2&onnest=fail&opera=delete&bdstoken=${getBdstoken()}&newVerify=1&clienttype=0&app_id=250528&web=1&dp-logid=39292100213290200076"
|
||||
val params = mapOf(
|
||||
"filelist" to "[\"$filePath\"]"
|
||||
)
|
||||
|
||||
val headers = mutableMapOf(
|
||||
"User-Agent" to "Android",
|
||||
"Connection" to "Keep-Alive",
|
||||
"Accept-Encoding" to "br,gzip",
|
||||
"Content-Type" to "application/x-www-form-urlencoded; charset=utf-8",
|
||||
"Accept-Language" to "zh-CN,zh;q=0.8",
|
||||
"charset" to "UTF-8",
|
||||
"Cookie" to cookies,
|
||||
)
|
||||
|
||||
|
||||
val response = OkHttp.post(url, params, headers)
|
||||
|
||||
|
||||
|
||||
println("删除文件响应: ${response.body}")
|
||||
println("响应状态码: ${response.code}")
|
||||
} catch (e: Exception) {
|
||||
println("删除文件出错: ${e.message}")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun unquote(encoded: String): String {
|
||||
return encoded.replace("%([0-9A-Fa-f]{2})".toRegex()) { match ->
|
||||
Integer.parseInt(match.groupValues[1], 16).toChar().toString()
|
||||
}
|
||||
}
|
||||
|
||||
private fun sha1(input: String): String {
|
||||
|
||||
return Util.sha1Hex(input)
|
||||
}
|
||||
|
||||
private val _handleError = mapOf(
|
||||
"parse" to "1", "msg" to "Error retrieving video URL"
|
||||
)
|
||||
|
||||
|
||||
fun getVod(shareUrl: String): Vod {
|
||||
val (froms, urls) = processShareLinks(listOf(shareUrl))
|
||||
val builder = VodPlayBuilder()
|
||||
for (i in froms.indices) {
|
||||
val playUrls = mutableListOf<VodPlayBuilder.PlayUrl>();
|
||||
for (url in urls[i].split("#")) {
|
||||
val arr = url.split("$")
|
||||
val play = VodPlayBuilder.PlayUrl()
|
||||
play.name = arr[0]
|
||||
play.url = arr[1]
|
||||
|
||||
playUrls.add(play)
|
||||
|
||||
}
|
||||
builder.append(froms[i], playUrls)
|
||||
}
|
||||
val buildResult = builder.build();
|
||||
|
||||
val vod = Vod()
|
||||
vod.setVodId(shareUrl)
|
||||
vod.setVodPic("")
|
||||
vod.setVodYear("")
|
||||
vod.setVodName("")
|
||||
vod.setVodContent("")
|
||||
vod.setVodPlayFrom(buildResult.vodPlayFrom)
|
||||
vod.setVodPlayUrl(buildResult.vodPlayUrl)
|
||||
return vod
|
||||
}
|
||||
|
||||
fun playerContent(json: JsonObject, flag: String): String {
|
||||
val play = getVideoUrl(json, flag);
|
||||
val header = play["header"] as Map<String, String>
|
||||
return Result.get().url(buildProxyUrl(play["url"] as String, header)).octet().header(header).string();
|
||||
}
|
||||
|
||||
fun getPlayFormatList(): Array<String> {
|
||||
return listOf("1080P").toTypedArray()
|
||||
}
|
||||
|
||||
fun proxyVideo(params: MutableMap<String, String>): Array<Any> {
|
||||
return emptyList<Any>().toTypedArray()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,398 +0,0 @@
|
|||
package com.github.catvod.api
|
||||
|
||||
import com.github.catvod.bean.Result
|
||||
import com.github.catvod.bean.Vod
|
||||
import com.github.catvod.bean.Vod.VodPlayBuilder
|
||||
import com.github.catvod.bean.pan123.ShareInfo
|
||||
import com.github.catvod.crawler.SpiderDebug
|
||||
import com.github.catvod.net.OkHttp
|
||||
import com.github.catvod.utils.Json
|
||||
import com.github.catvod.utils.ProxyServer.buildProxyUrl
|
||||
import com.github.catvod.utils.Util
|
||||
import com.google.gson.JsonObject
|
||||
import okhttp3.HttpUrl
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
* 123网盘API操作类
|
||||
* 提供123网盘的文件分享、下载、播放等功能
|
||||
*/
|
||||
object Pan123Api {
|
||||
public const val regex =
|
||||
"https://(123592\\.com|123912\\.com|123865\\.com|123684\\.com|www\\.123684\\.com|www\\.123865\\.com|www\\.123912\\.com|www\\.123pan\\.com|www\\.123pan\\.cn|www\\.123592\\.com)/s/([^/]+)"
|
||||
|
||||
private const val api = "https://www.123684.com/b/api/share/"
|
||||
private const val loginUrl = "https://login.123pan.com/api/user/sign_in"
|
||||
|
||||
private var authToken = ""
|
||||
|
||||
|
||||
/**
|
||||
* 初始化方法,检查登录状态
|
||||
*/
|
||||
fun init() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取认证token
|
||||
*/
|
||||
private fun getAuth(): String {
|
||||
if (authToken.isNotBlank()) {
|
||||
return authToken
|
||||
}
|
||||
return Pan123Handler.getAuth()
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 登录方法
|
||||
*/
|
||||
fun login(passport: String, password: String): JsonObject? {
|
||||
|
||||
val data = mapOf(
|
||||
"passport" to passport, "password" to password, "remember" to true
|
||||
)
|
||||
|
||||
val headers = mapOf(
|
||||
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
|
||||
"Content-Type" to "application/json",
|
||||
"App-Version" to "43",
|
||||
"Referer" to "https://login.123pan.com/centerlogin?redirect_url=https%3A%2F%2Fwww.123684.com&source_page=website",
|
||||
"Accept" to "application/json, text/plain, */*",
|
||||
"Origin" to "https://login.123pan.com",
|
||||
"Connection" to "keep-alive",
|
||||
"Accept-Language" to "zh-CN,zh;q=0.9"
|
||||
)
|
||||
|
||||
try {
|
||||
val response = OkHttp.post(loginUrl, Json.toJson(data), headers)
|
||||
SpiderDebug.log("登录请求信息:")
|
||||
SpiderDebug.log("URL: $loginUrl")
|
||||
SpiderDebug.log("账号: ${passport}")
|
||||
SpiderDebug.log("响应内容: ${response.body}")
|
||||
|
||||
if (response.code == 200) {
|
||||
val authData = Json.safeObject(response.body)
|
||||
SpiderDebug.log("解析后的响应数据: $authData")
|
||||
if (authData.has("data") && authData.getAsJsonObject("data").has("token")) {
|
||||
val token = authData.getAsJsonObject("data").get("token").asString
|
||||
// setAuth(token)
|
||||
SpiderDebug.log("登录成功")
|
||||
authToken=token
|
||||
|
||||
return authData.get("data").asJsonObject
|
||||
}
|
||||
}
|
||||
|
||||
throw Exception("登录失败: HTTP状态码=${response.code}, 响应=${response.body}")
|
||||
} catch (e: Exception) {
|
||||
SpiderDebug.log("登录过程中发生错误: ${e.message}")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析分享链接,提取分享密钥和提取码
|
||||
*/
|
||||
fun getShareData(url: String): Map<String, String> {
|
||||
SpiderDebug.log("123链接:$url")
|
||||
var sharePwd = ""
|
||||
var lurl = java.net.URLDecoder.decode(url, "UTF-8")
|
||||
|
||||
// 处理提取码格式
|
||||
if ("提取码" in lurl && "?" !in lurl) {
|
||||
lurl = lurl.replace(Regex("提取码[::]"), "?")
|
||||
}
|
||||
if ("提取码" in lurl && "?" in lurl) {
|
||||
lurl = lurl.replace(Regex("提取码[::]?"), "")
|
||||
}
|
||||
if (":" in lurl) {
|
||||
lurl = lurl.replace(":", "")
|
||||
}
|
||||
|
||||
val matcher = Pattern.compile(regex).matcher(lurl)
|
||||
|
||||
// 提取分享密码
|
||||
if ("?" in lurl) {
|
||||
val queryPart = lurl.split("?")[1]
|
||||
val pwdMatcher = Regex("[A-Za-z0-9]+").find(queryPart)
|
||||
if (pwdMatcher != null) {
|
||||
sharePwd = queryPart.split("=")[1]
|
||||
}
|
||||
}
|
||||
|
||||
if (matcher.find()) {
|
||||
val match = matcher.group(2) ?: ""
|
||||
val key = when {
|
||||
"?" in match -> match.split("?")[0]
|
||||
".html" in match -> match.replace(".html", "")
|
||||
"www" in match -> matcher.group(1) ?: match
|
||||
else -> match
|
||||
}
|
||||
return mapOf("key" to key, "sharePwd" to sharePwd)
|
||||
}
|
||||
|
||||
return emptyMap()
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据分享链接获取文件列表
|
||||
*/
|
||||
fun getFilesByShareUrl(shareKey: String, sharePwd: String): List<ShareInfo> {
|
||||
// 获取分享信息
|
||||
val cate = getShareInfo(shareKey, sharePwd, 0, 0)
|
||||
|
||||
return cate
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取分享信息
|
||||
*/
|
||||
private fun getShareInfo(
|
||||
shareKey: String, sharePwd: String, next: Int, parentFileId: Long
|
||||
): List<ShareInfo> {
|
||||
|
||||
|
||||
//文件夹
|
||||
val folders = mutableListOf<ShareInfo>()
|
||||
//视频
|
||||
val videos = mutableListOf<ShareInfo>()
|
||||
|
||||
|
||||
val url =
|
||||
"${api}get?limit=100&next=$next&orderBy=file_name&orderDirection=asc&shareKey=${shareKey.trim()}&SharePwd=${sharePwd.ifEmpty { "" }}&ParentFileId=$parentFileId&Page=1"
|
||||
|
||||
try {
|
||||
val response = OkHttp.string(
|
||||
url, mapOf(
|
||||
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
|
||||
)
|
||||
)
|
||||
|
||||
val data = Json.safeObject(response)
|
||||
if (data.has("code") && data.get("code").asInt == 5103) {
|
||||
SpiderDebug.log("123获取文件列表出错:" + data.get("message").asString)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val info = data.getAsJsonObject("data")
|
||||
//其下没有文件
|
||||
if (info.get("Len").asLong <= 0) {
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
val nextValue = info.get("Next").asInt
|
||||
val infoList = info.getAsJsonArray("InfoList")
|
||||
|
||||
// 处理文件夹
|
||||
for (item in infoList) {
|
||||
val itemObj = item.asJsonObject
|
||||
//文件夹
|
||||
if (itemObj.get("Category").asInt == 0) {
|
||||
folders.add(
|
||||
ShareInfo(
|
||||
itemObj.get("FileName").asString,
|
||||
shareKey,
|
||||
sharePwd,
|
||||
nextValue,
|
||||
itemObj.get("FileId").asLong,
|
||||
itemObj["S3KeyFlag"].asString,
|
||||
itemObj["Size"].asLong,
|
||||
itemObj["Etag"].asString,
|
||||
|
||||
)
|
||||
)
|
||||
} else if (itemObj.get("Category").asInt == 2) {
|
||||
videos.add(
|
||||
ShareInfo(
|
||||
itemObj.get("FileName").asString,
|
||||
shareKey,
|
||||
sharePwd,
|
||||
nextValue,
|
||||
itemObj.get("FileId").asLong,
|
||||
itemObj["S3KeyFlag"].asString,
|
||||
itemObj["Size"].asLong,
|
||||
itemObj["Etag"].asString,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 递归获取子文件夹信息
|
||||
|
||||
for (item in folders) {
|
||||
val result = getShareInfo(
|
||||
item.shareKey, item.sharePwd, item.next, item.fileId
|
||||
)
|
||||
videos.addAll(result)
|
||||
}
|
||||
|
||||
return videos
|
||||
} catch (e: Exception) {
|
||||
SpiderDebug.log("获取分享信息时发生错误: ${e.message}")
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取文件下载链接
|
||||
*/
|
||||
fun getDownload(
|
||||
shareKey: String, fileId: Long, s3KeyFlag: String, size: Long, etag: String
|
||||
): String {
|
||||
|
||||
|
||||
SpiderDebug.log("获取下载链接参数:")
|
||||
SpiderDebug.log("ShareKey: $shareKey")
|
||||
SpiderDebug.log("FileID: $fileId")
|
||||
SpiderDebug.log("S3KeyFlag: $s3KeyFlag")
|
||||
SpiderDebug.log("Size: $size")
|
||||
SpiderDebug.log("Etag: $etag")
|
||||
SpiderDebug.log("Auth Token: ${getAuth().take(30)}...")
|
||||
|
||||
val data = mapOf(
|
||||
"ShareKey" to shareKey, "FileID" to fileId, "S3KeyFlag" to s3KeyFlag, "Size" to size, "Etag" to etag
|
||||
)
|
||||
|
||||
val url = "${api}download/info"
|
||||
SpiderDebug.log("请求URL: $url")
|
||||
SpiderDebug.log("请求数据: ${Json.toJson(data)}")
|
||||
|
||||
val headers = mapOf(
|
||||
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
|
||||
"Content-Type" to "application/json",
|
||||
"Authorization" to "Bearer ${getAuth()}",
|
||||
"platform" to "android"
|
||||
|
||||
)
|
||||
|
||||
try {
|
||||
val response = OkHttp.post(url, Json.toJson(data), headers)
|
||||
SpiderDebug.log("响应状态码: ${response.code}")
|
||||
SpiderDebug.log("响应内容: ${response.body}")
|
||||
|
||||
if (response.code == 200) {
|
||||
val responseData = Json.safeObject(response.body)
|
||||
if (responseData.has("data") && responseData.getAsJsonObject("data").has("DownloadURL")) {
|
||||
val encodeUrl = responseData.getAsJsonObject("data").get("DownloadURL").asString
|
||||
return Util.base64Decode(HttpUrl.parse(encodeUrl)?.queryParameter("params"))
|
||||
}
|
||||
}
|
||||
|
||||
throw Exception("获取下载链接失败: HTTP状态码=${response.code}, 响应=${response.body}")
|
||||
} catch (e: Exception) {
|
||||
SpiderDebug.log("获取下载链接时发生错误: ${e.message}")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取视频在线播放链接
|
||||
*/
|
||||
fun getLiveTranscoding(
|
||||
shareKey: String, fileId: Long, s3KeyFlag: String, size: Long, etag: String
|
||||
): List<Map<String, String>> {
|
||||
|
||||
|
||||
val url = "https://www.123684.com/b/api/video/play/info?" + "etag=$etag&size=$size&from=1&shareKey=$shareKey"
|
||||
|
||||
val headers = mapOf(
|
||||
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
|
||||
"Authorization" to "Bearer ${getAuth()}",
|
||||
"Content-Type" to "application/json;charset=UTF-8",
|
||||
"platform" to "android"
|
||||
)
|
||||
|
||||
try {
|
||||
val response = OkHttp.string(url, headers)
|
||||
|
||||
val downData = Json.safeObject(response)
|
||||
if (downData.has("data") && downData.getAsJsonObject("data").has("video_play_info")) {
|
||||
val videoInfo = mutableListOf<Map<String, String>>()
|
||||
val videoPlayInfo = downData.getAsJsonObject("data").getAsJsonArray("video_play_info")
|
||||
|
||||
for (item in videoPlayInfo) {
|
||||
val itemObj = item.asJsonObject
|
||||
if (itemObj.has("url") && !itemObj.get("url").isJsonNull) {
|
||||
val resolution = if (itemObj.has("resolution")) itemObj.get("resolution").asString else ""
|
||||
val urlValue = itemObj.get("url").asString
|
||||
|
||||
videoInfo.add(
|
||||
mapOf(
|
||||
"name" to resolution, "url" to urlValue
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return videoInfo
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
SpiderDebug.log("获取视频播放链接时发生错误: ${e.message}")
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
fun getPlayFormatList(): Array<String> {
|
||||
return arrayOf("原画")
|
||||
}
|
||||
|
||||
fun getVod(key: String, sharePwd: String): Vod {
|
||||
val list = getFilesByShareUrl(key, sharePwd)
|
||||
|
||||
val builder = VodPlayBuilder()
|
||||
for (i in getPlayFormatList().indices) {
|
||||
val playUrls = mutableListOf<VodPlayBuilder.PlayUrl>();
|
||||
for (item in list) {
|
||||
|
||||
val play = VodPlayBuilder.PlayUrl()
|
||||
play.name = "[${Util.getSize(item.Size.toDouble())}]${item.filename}"
|
||||
play.url =
|
||||
listOf(item.shareKey, item.fileId, item.S3KeyFlag, item.Size, item.Etag).joinToString("\\+\\+")
|
||||
|
||||
playUrls.add(play)
|
||||
|
||||
}
|
||||
builder.append("pan123" + getPlayFormatList()[i], playUrls)
|
||||
}
|
||||
val buildResult = builder.build();
|
||||
|
||||
val vod = Vod()
|
||||
vod.setVodId(key + "++" + sharePwd)
|
||||
vod.setVodPic("")
|
||||
vod.setVodYear("")
|
||||
vod.setVodName("")
|
||||
vod.setVodContent("")
|
||||
vod.setVodPlayFrom(buildResult.vodPlayFrom)
|
||||
vod.setVodPlayUrl(buildResult.vodPlayUrl)
|
||||
return vod
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun playerContent(id: String, flag: String): String {
|
||||
val itemJson = id.split("\\+\\+")
|
||||
|
||||
SpiderDebug.log("播放参数:$itemJson")
|
||||
val url = getDownload(
|
||||
itemJson[0], itemJson[1].toLong(), itemJson[2], itemJson[3].toLong(), itemJson[4]
|
||||
)
|
||||
val header = mapOf(
|
||||
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
|
||||
)
|
||||
|
||||
return Result.get().url(buildProxyUrl(url, header)).octet().header(header).string();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,142 +0,0 @@
|
|||
package com.github.catvod.api
|
||||
|
||||
|
||||
import android.R
|
||||
import android.app.AlertDialog
|
||||
import android.content.DialogInterface
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
import com.github.catvod.api.Pan123Api.login
|
||||
import com.github.catvod.bean.pan123.Cache
|
||||
import com.github.catvod.bean.pan123.User
|
||||
import com.github.catvod.crawler.SpiderDebug
|
||||
import com.github.catvod.spider.Init
|
||||
import com.github.catvod.utils.Notify
|
||||
import com.github.catvod.utils.Path
|
||||
import com.github.catvod.utils.ResUtil
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import java.io.File
|
||||
|
||||
object Pan123Handler {
|
||||
|
||||
|
||||
private var cache: Cache? = null
|
||||
private var dialog: AlertDialog? = null
|
||||
|
||||
private var auth = ""
|
||||
private var userName = ""
|
||||
private var passwd = ""
|
||||
private var expire = 0L;
|
||||
|
||||
fun getCache(): File {
|
||||
return Path.tv("pan123")
|
||||
}
|
||||
|
||||
fun getAuth(): String {
|
||||
return auth
|
||||
}
|
||||
|
||||
|
||||
init {
|
||||
|
||||
cache = Cache.objectFrom(Path.read(getCache()))
|
||||
if (cache == null) {
|
||||
SpiderDebug.log("cache 为null")
|
||||
startFlow()
|
||||
} else {
|
||||
userName = cache!!.user.userName
|
||||
passwd = cache!!.user.password
|
||||
auth = cache!!.user.cookie
|
||||
expire = cache!!.user.expire
|
||||
if (StringUtils.isNotBlank(userName) && StringUtils.isNotBlank(passwd)) {
|
||||
if (StringUtils.isBlank(auth) || expire == 0L || System.currentTimeMillis() > expire) {
|
||||
SpiderDebug.log("auth 为空或者登录已过期")
|
||||
this.loginWithPassword(userName, passwd)
|
||||
}
|
||||
} else {
|
||||
SpiderDebug.log("userName passwd 为空")
|
||||
startFlow()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun loginWithPassword(uname: String?, passwd: String?) {
|
||||
SpiderDebug.log("loginWithPassword uname: $uname,passwd:$passwd")
|
||||
|
||||
try {
|
||||
//保存的账号密码
|
||||
val json = login(uname!!, passwd!!)
|
||||
if (json != null) {
|
||||
val user = User()
|
||||
user.cookie = json.get("token").asString
|
||||
user.password = passwd
|
||||
user.userName = uname
|
||||
user.expire = json.get("refresh_token_expire_time").asLong * 1000
|
||||
this.auth = json.get("token").asString
|
||||
cache?.setUserInfo(user)
|
||||
Notify.show("123登录成功")
|
||||
} else {
|
||||
Notify.show("123登录失败")
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
SpiderDebug.log("登录失败: " + e.message)
|
||||
Notify.show("123登录失败: " + e.message)
|
||||
}
|
||||
}
|
||||
|
||||
fun startFlow() {
|
||||
Init.run { this.showInput() }
|
||||
}
|
||||
|
||||
|
||||
private fun showInput() {
|
||||
try {
|
||||
val margin = ResUtil.dp2px(16)
|
||||
val params =
|
||||
LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
val frame = LinearLayout(Init.context())
|
||||
frame.setOrientation(LinearLayout.VERTICAL)
|
||||
// frame.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
// params.setMargins(margin, margin, margin, margin);
|
||||
val username = EditText(Init.context())
|
||||
username.setHint("请输入123用户名")
|
||||
val password = EditText(Init.context())
|
||||
password.setHint("请输入123密码")
|
||||
frame.addView(username, params)
|
||||
frame.addView(password, params)
|
||||
dialog = AlertDialog.Builder(Init.getActivity()).setTitle("请输入123用户名和密码").setView(frame)
|
||||
.setNegativeButton(
|
||||
R.string.cancel, null
|
||||
).setPositiveButton(
|
||||
R.string.ok, DialogInterface.OnClickListener { dialog: DialogInterface?, which: Int ->
|
||||
onPositive(
|
||||
username.getText().toString(), password.getText().toString()
|
||||
)
|
||||
}).show()
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun onPositive(username: String?, password: String?) {
|
||||
SpiderDebug.log("123用户名: $username")
|
||||
SpiderDebug.log("123密码: $password")
|
||||
dismiss()
|
||||
Init.execute(Runnable {
|
||||
loginWithPassword(username, password)
|
||||
})
|
||||
}
|
||||
|
||||
private fun dismiss() {
|
||||
try {
|
||||
if (dialog != null) dialog!!.dismiss()
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,726 +0,0 @@
|
|||
package com.github.catvod.api;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.SystemClock;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Gravity;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.bean.quark.Cache;
|
||||
import com.github.catvod.bean.quark.Item;
|
||||
import com.github.catvod.bean.quark.ShareData;
|
||||
import com.github.catvod.bean.quark.User;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.net.OkResult;
|
||||
import com.github.catvod.spider.Init;
|
||||
import com.github.catvod.spider.Proxy;
|
||||
import com.github.catvod.utils.*;
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class QuarkApi {
|
||||
private String apiUrl = "https://drive-pc.quark.cn/1/clouddrive/";
|
||||
private String cookie = "";
|
||||
private String ckey = "";
|
||||
private Map<String, Map<String, Object>> shareTokenCache = new HashMap<>();
|
||||
private String pr = "pr=ucpro&fr=pc";
|
||||
private List<String> subtitleExts = Arrays.asList(".srt", ".ass", ".scc", ".stl", ".ttml");
|
||||
private Map<String, String> saveFileIdCaches = new HashMap<>();
|
||||
private String saveDirId = null;
|
||||
private String saveDirName = "TV";
|
||||
private boolean isVip = false;
|
||||
private final Cache cache;
|
||||
private ScheduledExecutorService service;
|
||||
|
||||
|
||||
private AlertDialog dialog;
|
||||
private String serviceTicket;
|
||||
|
||||
public Object[] proxyVideo(Map<String, String> params) throws Exception {
|
||||
String url = Util.base64Decode(params.get("url"));
|
||||
Map header = new Gson().fromJson(Util.base64Decode(params.get("header")), Map.class);
|
||||
if (header == null) header = new HashMap<>();
|
||||
List<String> arr = List.of("Range", "Accept", "Accept-Encoding", "Accept-Language", "Cookie", "Origin", "Referer", "Sec-Ch-Ua", "Sec-Ch-Ua-Mobile", "Sec-Ch-Ua-Platform", "Sec-Fetch-Dest", "Sec-Fetch-Mode", "Sec-Fetch-Site", "User-Agent");
|
||||
for (String key : params.keySet()) {
|
||||
for (String s : arr) {
|
||||
if (s.toLowerCase().equals(key.toLowerCase())) {
|
||||
header.put(key, params.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (Util.getExt(url).contains("m3u8")) {
|
||||
return getM3u8(url, header);
|
||||
}
|
||||
return ProxyVideo.proxyMultiThread(url, header);
|
||||
}
|
||||
|
||||
/**
|
||||
* 代理m3u8
|
||||
*
|
||||
* @param url
|
||||
* @param header
|
||||
* @return
|
||||
*/
|
||||
private Object[] getM3u8(String url, Map header) {
|
||||
|
||||
OkResult result = OkHttp.get(url, new HashMap<>(), header);
|
||||
String[] m3u8Arr = result.getBody().split("\n");
|
||||
List<String> listM3u8 = new ArrayList<>();
|
||||
|
||||
String site = url.substring(0, url.lastIndexOf("/")) + "/";
|
||||
int mediaId = 0;
|
||||
for (String oneLine : m3u8Arr) {
|
||||
String thisOne = oneLine;
|
||||
if (oneLine.contains(".ts")) {
|
||||
thisOne = proxyVideoUrl(site + thisOne, header);
|
||||
mediaId++;
|
||||
}
|
||||
listM3u8.add(thisOne);
|
||||
}
|
||||
String m3u8Str = TextUtils.join("\n", listM3u8);
|
||||
String contentType = result.getResp().get("Content-Type").get(0);
|
||||
|
||||
Map<String, String> respHeaders = new HashMap<>();
|
||||
for (String key : result.getResp().keySet()) {
|
||||
respHeaders.put(key, result.getResp().get(key).get(0));
|
||||
}
|
||||
return new Object[]{result.getCode(), contentType, new ByteArrayInputStream(m3u8Str.getBytes(Charset.forName("UTF-8"))), respHeaders};
|
||||
}
|
||||
|
||||
private static class Loader {
|
||||
static volatile QuarkApi INSTANCE = new QuarkApi();
|
||||
}
|
||||
|
||||
public static QuarkApi get() {
|
||||
return QuarkApi.Loader.INSTANCE;
|
||||
}
|
||||
|
||||
public void setCookie(String token) throws Exception {
|
||||
if (StringUtils.isNoneBlank(token)) {
|
||||
this.cookie = token;
|
||||
initUserInfo();
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> getHeaders() {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) quark-cloud-drive/2.5.20 Chrome/100.0.4896.160 Electron/18.3.5.4-b478491100 Safari/537.36 Channel/pckk_other_ch");
|
||||
headers.put("Referer", "https://pan.quark.cn/");
|
||||
headers.put("Content-Type", "application/json");
|
||||
headers.put("Cookie", cookie);
|
||||
headers.put("Host", "drive-pc.quark.cn");
|
||||
return headers;
|
||||
}
|
||||
|
||||
private Map<String, String> getWebHeaders() {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) quark-cloud-drive/2.5.20 Chrome/100.0.4896.160 Electron/18.3.5.4-b478491100 Safari/537.36 Channel/pckk_other_ch");
|
||||
headers.put("Referer", "https://pan.quark.cn/");
|
||||
headers.put("Cookie", cookie);
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void initQuark(String cookie) throws Exception {
|
||||
this.ckey = Util.MD5(cookie);
|
||||
this.cookie = cookie;
|
||||
this.isVip = getVip();
|
||||
}
|
||||
|
||||
private QuarkApi() {
|
||||
Init.checkPermission();
|
||||
|
||||
cache = Cache.objectFrom(Path.read(getCache()));
|
||||
}
|
||||
|
||||
public File getCache() {
|
||||
return Path.tv("quark");
|
||||
}
|
||||
|
||||
public Vod getVod(ShareData shareData) throws Exception {
|
||||
getShareToken(shareData);
|
||||
List<Item> files = new ArrayList<>();
|
||||
List<Item> subs = new ArrayList<>();
|
||||
try {
|
||||
List<Map<String, Object>> listData = listFile(1, shareData, files, subs, shareData.getShareId(), shareData.getFolderId(), 1);
|
||||
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log("资源已取消:" + e.getMessage());
|
||||
Notify.show("资源已取消");
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
List<String> playFrom = QuarkApi.get().getPlayFormatList();
|
||||
|
||||
List<String> playFromtmp = new ArrayList<>();
|
||||
playFromtmp.add("quark原画");
|
||||
for (String s : playFrom) {
|
||||
playFromtmp.add("quark" + s);
|
||||
}
|
||||
|
||||
List<String> playUrl = new ArrayList<>();
|
||||
|
||||
if (files.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < files.get(files.size() - 1).getShareIndex(); i++) {
|
||||
for (int index = 0; index < playFromtmp.size(); index++) {
|
||||
List<String> vodItems = new ArrayList<>();
|
||||
for (Item video_item : files) {
|
||||
if (video_item.getShareIndex() == i + 1) {
|
||||
vodItems.add(video_item.getEpisodeUrl("电影"));// + findSubs(video_item.getName(), subs));
|
||||
}
|
||||
}
|
||||
playUrl.add(TextUtils.join("#", vodItems));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId("");
|
||||
vod.setVodContent("");
|
||||
vod.setVodPic("");
|
||||
vod.setVodName("");
|
||||
vod.setVodPlayUrl(TextUtils.join("$$$", playUrl));
|
||||
vod.setVodPlayFrom(TextUtils.join("$$$", playFromtmp));
|
||||
vod.setTypeName("夸克云盘");
|
||||
return vod;
|
||||
}
|
||||
|
||||
public String playerContent(String[] split, String flag) throws Exception {
|
||||
|
||||
String fileId = split[0], fileToken = split[1], shareId = split[2], stoken = split[3];
|
||||
String playUrl = "";
|
||||
Map<String, String> header = getHeaders();
|
||||
header.remove("Host");
|
||||
header.remove("Content-Type");
|
||||
if (flag.contains("quark原画")) {
|
||||
playUrl = this.getDownload(shareId, stoken, fileId, fileToken, true);
|
||||
return Result.get().url(ProxyServer.INSTANCE.buildProxyUrl(playUrl, header)).octet().header(header).string();
|
||||
} else {
|
||||
playUrl = this.getLiveTranscoding(shareId, stoken, fileId, fileToken, flag);
|
||||
return Result.get().url(proxyVideoUrl(playUrl, header)).octet().header(header).string();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private String proxyVideoUrl(String url, Map<String, String> header) {
|
||||
return String.format(Proxy.getUrl() + "?do=quark&type=video&url=%s&header=%s", Util.base64Encode(url.getBytes(Charset.defaultCharset())), Util.base64Encode(Json.toJson(header).getBytes(Charset.defaultCharset())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param url
|
||||
* @param params get 参数
|
||||
* @param data post json
|
||||
* @param retry
|
||||
* @param method
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private String api(String url, Map<String, String> params, Map<String, Object> data, Integer retry, String method) throws Exception {
|
||||
|
||||
|
||||
int leftRetry = retry != null ? retry : 3;
|
||||
if (StringUtils.isAllBlank(cookie)) {
|
||||
this.initUserInfo();
|
||||
return api(url, params, data, leftRetry - 1, method);
|
||||
}
|
||||
OkResult okResult;
|
||||
if ("GET".equals(method)) {
|
||||
okResult = OkHttp.get(this.apiUrl + url, params, getHeaders());
|
||||
} else {
|
||||
okResult = OkHttp.post(this.apiUrl + url, Json.toJson(data), getHeaders());
|
||||
}
|
||||
if (okResult.getResp().get("Set-Cookie") != null) {
|
||||
Matcher matcher = Pattern.compile("__puus=([^;]+)").matcher(StringUtils.join(okResult.getResp().get("Set-Cookie"), ";;;"));
|
||||
if (matcher.find()) {
|
||||
Matcher cookieMatcher = Pattern.compile("__puus=([^;]+)").matcher(this.cookie);
|
||||
if (cookieMatcher.find() && !cookieMatcher.group(1).equals(matcher.group(1))) {
|
||||
this.cookie = this.cookie.replaceAll("__puus=[^;]+", "__puus=" + matcher.group(1));
|
||||
} else {
|
||||
this.cookie = this.cookie + ";__puus=" + matcher.group(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (okResult.getCode() != 200 && leftRetry > 0) {
|
||||
SpiderDebug.log("api error code:" + okResult.getCode());
|
||||
Thread.sleep(1000);
|
||||
return api(url, params, data, leftRetry - 1, method);
|
||||
}
|
||||
return okResult.getBody();
|
||||
}
|
||||
|
||||
private void initUserInfo() {
|
||||
try {
|
||||
SpiderDebug.log("initUserInfo...");
|
||||
|
||||
//extend没有cookie,从缓存中获取
|
||||
if (StringUtils.isAllBlank(cookie)) {
|
||||
SpiderDebug.log(" cookie from ext is empty...");
|
||||
cookie = cache.getUser().getCookie();
|
||||
}
|
||||
//获取到cookie,初始化quark,并且把cookie缓存一次
|
||||
if (StringUtils.isNoneBlank(cookie) && cookie.contains("__pus")) {
|
||||
SpiderDebug.log(" initQuark ...");
|
||||
initQuark(this.cookie);
|
||||
cache.setUser(User.objectFrom(this.cookie));
|
||||
return;
|
||||
}
|
||||
|
||||
//没有cookie,也没有serviceTicket,抛出异常,提示用户重新登录
|
||||
if (StringUtils.isAllBlank(cookie) && StringUtils.isAllBlank(serviceTicket)) {
|
||||
SpiderDebug.log("cookie为空");
|
||||
throw new RuntimeException("cookie为空");
|
||||
}
|
||||
|
||||
String token = serviceTicket;
|
||||
OkResult result = OkHttp.get("https://pan.quark.cn/account/info?st=" + token + "&lw=scan", new HashMap<>(), getWebHeaders());
|
||||
Map json = Json.parseSafe(result.getBody(), Map.class);
|
||||
if (json.get("success").equals(Boolean.TRUE)) {
|
||||
List<String> cookies = result.getResp().get("set-Cookie");
|
||||
List<String> cookieList = new ArrayList<>();
|
||||
for (String cookie : cookies) {
|
||||
cookieList.add(cookie.split(";")[0]);
|
||||
}
|
||||
this.cookie += TextUtils.join(";", cookieList);
|
||||
|
||||
cache.setUser(User.objectFrom(this.cookie));
|
||||
if (cache.getUser().getCookie().isEmpty()) throw new Exception(this.cookie);
|
||||
initQuark(this.cookie);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
cache.getUser().clean();
|
||||
e.printStackTrace();
|
||||
stopService();
|
||||
startFlow();
|
||||
} finally {
|
||||
while (cache.getUser().getCookie().isEmpty()) SystemClock.sleep(250);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取二维码登录的令牌
|
||||
*
|
||||
* @return 返回包含二维码登录令牌的字符串
|
||||
*/
|
||||
private String getTokenForQrcodeLogin() {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("client_id", "386");
|
||||
params.put("v", "1.2");
|
||||
params.put("request_id", UUID.randomUUID().toString());
|
||||
OkResult res = OkHttp.get("https://uop.quark.cn/cas/ajax/getTokenForQrcodeLogin", params, new HashMap<>());
|
||||
if (this.cookie.isEmpty()) {
|
||||
List<String> cookies = res.getResp().get("set-Cookie");
|
||||
List<String> cookieList = new ArrayList<>();
|
||||
for (String cookie : cookies) {
|
||||
cookieList.add(cookie.split(";")[0]);
|
||||
}
|
||||
this.cookie = TextUtils.join(";", cookieList);
|
||||
}
|
||||
Map<String, Object> json = Json.parseSafe(res.getBody(), Map.class);
|
||||
if (Objects.equals(json.get("message"), "ok")) {
|
||||
return (String) ((Map<String, Object>) ((Map<String, Object>) json.get("data")).get("members")).get("token");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取二维码内容
|
||||
* <p>
|
||||
* 此方法用于生成二维码的URL内容该URL用于二维码登录,包含了登录所需的token和客户端信息
|
||||
*
|
||||
* @return 返回包含token的二维码URL字符串
|
||||
*/
|
||||
private String getQrCodeToken() {
|
||||
// 获取用于二维码登录的token
|
||||
String token = getTokenForQrcodeLogin();
|
||||
// 组装二维码URL,包含token和客户端标识
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
public ShareData getShareData(String url) {
|
||||
Pattern pattern = Pattern.compile("https://pan\\.quark\\.cn/s/([^\\\\|#/]+)");
|
||||
Matcher matcher = pattern.matcher(url);
|
||||
if (matcher.find()) {
|
||||
return new ShareData(matcher.group(1), "0");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean getVip() throws Exception {
|
||||
Map<String, Object> listData = Json.parseSafe(api("member?pr=ucpro&fr=pc&uc_param_str=&fetch_subscribe=true&_ch=home&fetch_identity=true", null, null, 0, "GET"), Map.class);
|
||||
return ((Map<String, String>) listData.get("data")).get("member_type").contains("VIP");
|
||||
}
|
||||
|
||||
public List<String> getPlayFormatList() {
|
||||
if (this.isVip) {
|
||||
return Arrays.asList("4K"/*, "超清", "高清", "普画"*/);
|
||||
} else {
|
||||
return Collections.singletonList("普画");
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getPlayFormatQuarkList() {
|
||||
if (this.isVip) {
|
||||
return Arrays.asList("4k", "2k", "super", "high", "normal", "low");
|
||||
} else {
|
||||
return Collections.singletonList("low");
|
||||
}
|
||||
}
|
||||
|
||||
private void getShareToken(ShareData shareData) throws Exception {
|
||||
if (!this.shareTokenCache.containsKey(shareData.getShareId())) {
|
||||
this.shareTokenCache.remove(shareData.getShareId());
|
||||
Map<String, Object> shareToken = Json.parseSafe(api("share/sharepage/token?" + this.pr, Collections.emptyMap(), Map.of("pwd_id", shareData.getShareId(), "passcode", shareData.getSharePwd() == null ? "" : shareData.getSharePwd()), 0, "POST"), Map.class);
|
||||
if (shareToken.containsKey("data") && ((Map<String, Object>) shareToken.get("data")).containsKey("stoken")) {
|
||||
this.shareTokenCache.put(shareData.getShareId(), (Map<String, Object>) shareToken.get("data"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> listFile(int shareIndex, ShareData shareData, List<Item> videos, List<Item> subtitles, String shareId, String folderId, Integer page) throws Exception {
|
||||
int prePage = 200;
|
||||
page = page != null ? page : 1;
|
||||
|
||||
Map<String, Object> listData = Json.parseSafe(api("share/sharepage/detail?" + this.pr + "&pwd_id=" + shareId + "&stoken=" + encodeURIComponent((String) this.shareTokenCache.get(shareId).get("stoken")) + "&pdir_fid=" + folderId + "&force=0&_page=" + page + "&_size=" + prePage + "&_sort=file_type:asc,file_name:asc", Collections.emptyMap(), Collections.emptyMap(), 0, "GET"), Map.class);
|
||||
if (listData.get("data") == null) return Collections.emptyList();
|
||||
List<Map<String, Object>> items = (List<Map<String, Object>>) ((Map<String, Object>) listData.get("data")).get("list");
|
||||
if (items == null) return Collections.emptyList();
|
||||
List<Map<String, Object>> subDir = new ArrayList<>();
|
||||
for (Map<String, Object> item : items) {
|
||||
if (Boolean.TRUE.equals(item.get("dir"))) {
|
||||
subDir.add(item);
|
||||
} else if (Boolean.TRUE.equals(item.get("file")) && (Util.isMedia((String) item.get("file_name")))) {
|
||||
if ((Double) item.get("size") < 1024 * 1024 * 5) continue;
|
||||
item.put("stoken", this.shareTokenCache.get(shareData.getShareId()).get("stoken"));
|
||||
videos.add(Item.objectFrom(item, shareData.getShareId(), shareIndex));
|
||||
} else if ("file".equals(item.get("type")) && this.subtitleExts.contains("." + Util.getExt((String) item.get("file_name")))) {
|
||||
subtitles.add(Item.objectFrom(item, shareData.getShareId(), shareIndex));
|
||||
}
|
||||
}
|
||||
if (page < Math.ceil((double) ((Map<String, Object>) listData.get("metadata")).get("_total") / prePage)) {
|
||||
List<Map<String, Object>> nextItems = listFile(shareIndex, shareData, videos, subtitles, shareId, folderId, page + 1);
|
||||
items.addAll(nextItems);
|
||||
}
|
||||
for (Map<String, Object> dir : subDir) {
|
||||
List<Map<String, Object>> subItems = listFile(shareIndex, shareData, videos, subtitles, shareId, dir.get("fid").toString(), null);
|
||||
items.addAll(subItems);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
private Map<String, Object> findBestLCS(Item mainItem, List<Item> targetItems) {
|
||||
List<Map<String, Object>> results = new ArrayList<>();
|
||||
int bestMatchIndex = 0;
|
||||
for (int i = 0; i < targetItems.size(); i++) {
|
||||
Util.LCSResult currentLCS = Util.lcs(mainItem.getName(), targetItems.get(i).getName());
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("target", targetItems.get(i));
|
||||
result.put("lcs", currentLCS);
|
||||
results.add(result);
|
||||
if (currentLCS.length > results.get(bestMatchIndex).get("lcs").toString().length()) {
|
||||
bestMatchIndex = i;
|
||||
}
|
||||
}
|
||||
Map<String, Object> bestMatch = results.get(bestMatchIndex);
|
||||
Map<String, Object> finalResult = new HashMap<>();
|
||||
finalResult.put("allLCS", results);
|
||||
finalResult.put("bestMatch", bestMatch);
|
||||
finalResult.put("bestMatchIndex", bestMatchIndex);
|
||||
return finalResult;
|
||||
}
|
||||
|
||||
public void getFilesByShareUrl(int shareIndex, String shareInfo, List<Item> videos, List<Item> subtitles) throws Exception {
|
||||
ShareData shareData = getShareData((String) shareInfo);
|
||||
if (shareData == null) return;
|
||||
getShareToken(shareData);
|
||||
if (!this.shareTokenCache.containsKey(shareData.getShareId())) return;
|
||||
listFile(shareIndex, shareData, videos, subtitles, shareData.getShareId(), shareData.getFolderId(), 1);
|
||||
if (!subtitles.isEmpty()) {
|
||||
for (Item video : videos) {
|
||||
Map<String, Object> matchSubtitle = findBestLCS(video, subtitles);
|
||||
if (matchSubtitle.get("bestMatch") != null) {
|
||||
video.setSubtitle((String) ((Map<String, Object>) matchSubtitle.get("bestMatch")).get("target"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void clean() {
|
||||
saveFileIdCaches.clear();
|
||||
}
|
||||
|
||||
private void clearSaveDir() throws Exception {
|
||||
Map<String, Object> listData = Json.parseSafe(api("file/sort?" + this.pr + "&pdir_fid=" + this.saveDirId + "&_page=1&_size=200&_sort=file_type:asc,updated_at:desc", Collections.emptyMap(), Collections.emptyMap(), 0, "GET"), Map.class);
|
||||
|
||||
if (listData.get("data") != null) {
|
||||
List<Map<String, Object>> fileList = (List<Map<String, Object>>) ((Map<String, Object>) listData.get("data")).get("list");
|
||||
if (fileList.size() >= 10) {
|
||||
List<String> fileIdsToDelete = new ArrayList<>();
|
||||
for (Map<String, Object> file : fileList) {
|
||||
fileIdsToDelete.add((String) file.get("fid"));
|
||||
}
|
||||
api("file/delete?" + this.pr + "&uc_param_str=", Collections.emptyMap(), Map.of("action_type", 2, "filelist", fileIdsToDelete, "exclude_fids", Collections.emptyList()), 0, "POST");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createSaveDir(boolean clean) throws Exception {
|
||||
if (this.saveDirId != null) {
|
||||
if (clean) clearSaveDir();
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> listData = Json.parseSafe(api("file/sort?" + this.pr + "&pdir_fid=0&_page=1&_size=200&_sort=file_type:asc,updated_at:desc", Collections.emptyMap(), Collections.emptyMap(), 0, "GET"), Map.class);
|
||||
if (listData.get("data") != null) {
|
||||
for (Map<String, Object> item : (List<Map<String, Object>>) ((Map<String, Object>) listData.get("data")).get("list")) {
|
||||
if (this.saveDirName.equals(item.get("file_name"))) {
|
||||
this.saveDirId = item.get("fid").toString();
|
||||
clearSaveDir();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.saveDirId == null) {
|
||||
Map<String, Object> create = Json.parseSafe(api("file?" + this.pr, Collections.emptyMap(), Map.of("pdir_fid", "0", "file_name", this.saveDirName, "dir_path", "", "dir_init_lock", "false"), 0, "POST"), Map.class);
|
||||
if (create.get("data") != null && ((Map<String, Object>) create.get("data")).get("fid") != null) {
|
||||
this.saveDirId = ((Map<String, Object>) create.get("data")).get("fid").toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String save(String shareId, String stoken, String fileId, String fileToken, boolean clean) throws Exception {
|
||||
createSaveDir(clean);
|
||||
if (clean) {
|
||||
clean();
|
||||
}
|
||||
if (this.saveDirId == null) return null;
|
||||
if (stoken == null) {
|
||||
getShareToken(new ShareData(shareId, null));
|
||||
if (!this.shareTokenCache.containsKey(shareId)) return null;
|
||||
}
|
||||
|
||||
Map<String, Object> saveResult = Json.parseSafe(api("share/sharepage/save?" + this.pr, null, Map.of("fid_list", List.of(fileId), "fid_token_list", List.of(fileToken), "to_pdir_fid", this.saveDirId, "pwd_id", shareId, "stoken", stoken != null ? stoken : (String) this.shareTokenCache.get(shareId).get("stoken"), "pdir_fid", "0", "scene", "link"), 0, "POST"), Map.class);
|
||||
if (saveResult.get("data") != null && ((Map<Object, Object>) saveResult.get("data")).get("task_id") != null) {
|
||||
int retry = 0;
|
||||
while (true) {
|
||||
|
||||
Map<String, Object> taskResult = Json.parseSafe(api("task?" + this.pr + "&task_id=" + ((Map<String, Object>) saveResult.get("data")).get("task_id") + "&retry_index=" + retry, Collections.emptyMap(), Collections.emptyMap(), 0, "GET"), Map.class);
|
||||
if (taskResult.get("data") != null && ((Map<Object, Object>) taskResult.get("data")).get("save_as") != null && ((Map<Object, Object>) ((Map<Object, Object>) taskResult.get("data")).get("save_as")).get("save_as_top_fids") != null && ((List<String>) ((Map<String, Object>) ((Map<String, Object>) taskResult.get("data")).get("save_as")).get("save_as_top_fids")).size() > 0) {
|
||||
return ((List<String>) ((Map<String, Object>) ((Map<Object, Object>) taskResult.get("data")).get("save_as")).get("save_as_top_fids")).get(0);
|
||||
}
|
||||
retry++;
|
||||
if (retry > 2) break;
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getLiveTranscoding(String shareId, String stoken, String fileId, String fileToken, String flag) throws Exception {
|
||||
if (!this.saveFileIdCaches.containsKey(fileId)) {
|
||||
String saveFileId = save(shareId, stoken, fileId, fileToken, true);
|
||||
if (saveFileId == null) return null;
|
||||
this.saveFileIdCaches.put(fileId, saveFileId);
|
||||
}
|
||||
|
||||
Map<String, Object> transcoding = Json.parseSafe(api("file/v2/play?" + this.pr, Collections.emptyMap(), Map.of("fid", this.saveFileIdCaches.get(fileId), "resolutions", "normal,low,high,super,2k,4k", "supports", "fmp4"), 0, "POST"), Map.class);
|
||||
if (transcoding.get("data") != null && ((Map<Object, Object>) transcoding.get("data")).get("video_list") != null) {
|
||||
String flagId = flag.split("-")[flag.split("-").length - 1];
|
||||
int index = Util.findAllIndexes(getPlayFormatList(), flagId);
|
||||
String quarkFormat = getPlayFormatQuarkList().get(index);
|
||||
for (Map<String, Object> video : (List<Map<String, Object>>) ((Map<Object, Object>) transcoding.get("data")).get("video_list")) {
|
||||
if (video.get("resolution").equals(quarkFormat)) {
|
||||
return (String) ((Map<String, Object>) video.get("video_info")).get("url");
|
||||
}
|
||||
}
|
||||
return (String) ((Map<String, Object>) ((List<Map<String, Object>>) ((Map<Object, Object>) transcoding.get("data")).get("video_list")).get(index).get("video_info")).get("url");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getDownload(String shareId, String stoken, String fileId, String fileToken, boolean clean) throws Exception {
|
||||
if (!this.saveFileIdCaches.containsKey(fileId)) {
|
||||
String saveFileId = save(shareId, stoken, fileId, fileToken, clean);
|
||||
if (saveFileId == null) return null;
|
||||
this.saveFileIdCaches.put(fileId, saveFileId);
|
||||
}
|
||||
Map<String, Object> down = Json.parseSafe(api("file/download?" + this.pr + "&uc_param_str=", Collections.emptyMap(), Map.of("fids", List.of(this.saveFileIdCaches.get(fileId))), 0, "POST"), Map.class);
|
||||
if (down.get("data") != null) {
|
||||
return ((List<Map<String, Object>>) down.get("data")).get(0).get("download_url").toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Helper method to convert bytes to hex string
|
||||
private String bytesToHex(byte[] bytes) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
sb.append(String.format("%02x", b));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// Encoding helper method
|
||||
private String encodeURIComponent(String value) {
|
||||
try {
|
||||
return java.net.URLEncoder.encode(value, "UTF-8");
|
||||
} catch (Exception e) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private void startFlow() {
|
||||
Init.run(this::showInput);
|
||||
}
|
||||
|
||||
private void showInput() {
|
||||
try {
|
||||
int margin = ResUtil.dp2px(16);
|
||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
FrameLayout frame = new FrameLayout(Init.context());
|
||||
params.setMargins(margin, margin, margin, margin);
|
||||
EditText input = new EditText(Init.context());
|
||||
frame.addView(input, params);
|
||||
dialog = new AlertDialog.Builder(Init.getActivity()).setTitle("请输入cookie").setView(frame).setNeutralButton("夸克二维码", (dialog, which) -> onNeutral()).setNegativeButton(android.R.string.cancel, null).setPositiveButton(android.R.string.ok, (dialog, which) -> onPositive(input.getText().toString())).show();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void onNeutral() {
|
||||
dismiss();
|
||||
Init.execute(this::getQRCode);
|
||||
}
|
||||
|
||||
private void onPositive(String text) {
|
||||
dismiss();
|
||||
Init.execute(() -> {
|
||||
if (text.startsWith("http")) setToken(OkHttp.string(text));
|
||||
else setToken(text);
|
||||
});
|
||||
}
|
||||
|
||||
private void getQRCode() {
|
||||
String token = getQrCodeToken();
|
||||
|
||||
Init.run(() -> openApp(token));
|
||||
}
|
||||
|
||||
private void openApp(String token) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setClassName("com.alicloud.databox", "com.taobao.login4android.scan.QrScanActivity");
|
||||
intent.putExtra("key_scanParam", token);
|
||||
Init.getActivity().startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
showQRCode("https://su.quark.cn/4_eMHBJ?uc_param_str=&token=" + token + "&client_id=532&uc_biz_str=S%3Acustom%7COPT%3ASAREA%400%7COPT%3AIMMERSIVE%401%7COPT%3ABACK_BTN_STYLE%400");
|
||||
} finally {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("token", token);
|
||||
Init.execute(() -> startService(map));
|
||||
}
|
||||
}
|
||||
|
||||
private void showQRCode(String content) {
|
||||
try {
|
||||
int size = ResUtil.dp2px(240);
|
||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(size, size);
|
||||
ImageView image = new ImageView(Init.context());
|
||||
image.setScaleType(ImageView.ScaleType.CENTER_CROP);
|
||||
image.setImageBitmap(QRCode.getBitmap(content, size, 2));
|
||||
FrameLayout frame = new FrameLayout(Init.context());
|
||||
params.gravity = Gravity.CENTER;
|
||||
frame.addView(image, params);
|
||||
dialog = new AlertDialog.Builder(Init.getActivity()).setView(frame).setOnCancelListener(this::dismiss).setOnDismissListener(this::dismiss).show();
|
||||
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
Notify.show("请使用夸克网盘App扫描二维码");
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void startService(Map<String, String> params) {
|
||||
SpiderDebug.log("----startservice");
|
||||
params.put("client_id", "532");
|
||||
params.put("v", "1.2");
|
||||
params.put("request_id", UUID.randomUUID().toString());
|
||||
service = Executors.newScheduledThreadPool(1);
|
||||
/* timer = new Timer(true);
|
||||
TimerTask task = new TimerTask()
|
||||
{
|
||||
@Override
|
||||
public void run() {
|
||||
SpiderDebug.log("----scheduleAtFixedRate"+new Date().toString());
|
||||
String result = OkHttp.string("https://uop.quark.cn/cas/ajax/getServiceTicketByQrcodeToken", params, getWebHeaders());
|
||||
Map<String,Object> json = Json.parseSafe(result, Map.class);
|
||||
if (json.get("status").equals(2000000)) {
|
||||
setToken((String) ((Map<String,Object>)((Map<String,Object>)json.get("data")).get("members")).get("service_ticket"));
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
timer.schedule(task, 1000, 2000);*/
|
||||
|
||||
service.scheduleWithFixedDelay(() -> {
|
||||
SpiderDebug.log("----scheduleAtFixedRate" + new Date().toString());
|
||||
String result = OkHttp.string("https://uop.quark.cn/cas/ajax/getServiceTicketByQrcodeToken", params, getWebHeaders());
|
||||
Map<String, Object> json = Json.parseSafe(result, Map.class);
|
||||
if (json.get("status").equals(new Double(2000000))) {
|
||||
setToken((String) ((Map<String, Object>) ((Map<String, Object>) json.get("data")).get("members")).get("service_ticket"));
|
||||
|
||||
}
|
||||
|
||||
}, 1, 3, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void setToken(String value) {
|
||||
this.serviceTicket = value;
|
||||
SpiderDebug.log("ServiceTicket:" + value);
|
||||
Notify.show("ServiceTicket:" + value);
|
||||
initUserInfo();
|
||||
stopService();
|
||||
}
|
||||
|
||||
private void stopService() {
|
||||
if (service != null) service.shutdownNow();
|
||||
|
||||
|
||||
Init.run(this::dismiss);
|
||||
}
|
||||
|
||||
private void dismiss(DialogInterface dialog) {
|
||||
stopService();
|
||||
}
|
||||
|
||||
private void dismiss() {
|
||||
try {
|
||||
if (dialog != null) dialog.dismiss();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
package com.github.catvod.api;
|
||||
|
||||
|
||||
import com.github.catvod.bean.tianyi.Cache;
|
||||
import com.github.catvod.bean.tianyi.User;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.Path;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import okhttp3.HttpUrl;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SimpleCookieJar {
|
||||
private Map<String, Map<String, String>> cookieStore = new HashMap<>();
|
||||
|
||||
|
||||
public Map<String, Map<String, String>> getCookieStore() {
|
||||
return cookieStore;
|
||||
}
|
||||
|
||||
public void setCookieStore(Map<String, Map<String, String>> cookieStore) {
|
||||
this.cookieStore = cookieStore;
|
||||
}
|
||||
|
||||
public SimpleCookieJar() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void saveFromResponse(String url, List<String> cookies) {
|
||||
HttpUrl httpUrl = HttpUrl.parse(url);
|
||||
SpiderDebug.log(" saveFromResponse url: " + url);
|
||||
SpiderDebug.log(" saveFromResponse cookie : " + Json.toJson(cookies));
|
||||
// 创建可修改的 Cookie 列表副本
|
||||
Map<String, String> oldCookies = cookieStore.get(httpUrl.host()) != null ? cookieStore.get(httpUrl.host()) : new HashMap<>();
|
||||
|
||||
// 更新 Cookie
|
||||
for (String newCookie : cookies) {
|
||||
String[] split = newCookie.split(";");
|
||||
String cookieItem = split[0].trim();
|
||||
int equalsIndex = cookieItem.indexOf('=');
|
||||
if (equalsIndex > 0) {
|
||||
String key = cookieItem.substring(0, equalsIndex);
|
||||
String value = equalsIndex < cookieItem.length() - 1 ? cookieItem.substring(equalsIndex + 1) : "";
|
||||
if (value.equals("SSON") && StringUtils.isAllBlank(value)) {
|
||||
|
||||
} else {
|
||||
oldCookies.put(key, value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cookieStore.put(httpUrl.host(), oldCookies);
|
||||
SpiderDebug.log(" cookieStore now: " + Json.toJson(cookieStore));
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void setGlobalCookie(JsonObject jsonObject) {
|
||||
|
||||
for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
JsonObject value = entry.getValue().getAsJsonObject();
|
||||
Map<String, String> cookiesForHost = new HashMap<>();
|
||||
for (String k : value.keySet()) {
|
||||
String cookieobj = value.get(k).getAsString();
|
||||
cookiesForHost.put(k, cookieobj);
|
||||
}
|
||||
cookieStore.put(key, cookiesForHost);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据请求URl获取cookie
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public String loadForRequest(String url) {
|
||||
HttpUrl httpUrl = HttpUrl.parse(url);
|
||||
Map<String, String> cookieMap = cookieStore.get(httpUrl.host());
|
||||
List<String> cookieList = new ArrayList<>();
|
||||
if (cookieMap != null && cookieMap.size() > 0) {
|
||||
for (String s : cookieMap.keySet()) {
|
||||
cookieList.add(s + "=" + cookieMap.get(s));
|
||||
}
|
||||
}
|
||||
String cookie = StringUtils.join(cookieList, ";");
|
||||
SpiderDebug.log(" loadForRequest url:" + url);
|
||||
SpiderDebug.log(" loadForRequest cookie:" + cookie);
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,627 +0,0 @@
|
|||
package com.github.catvod.api;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.util.Base64;
|
||||
import android.view.Gravity;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.github.catvod.bean.tianyi.Cache;
|
||||
import com.github.catvod.bean.tianyi.User;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.net.OkResult;
|
||||
import com.github.catvod.spider.Init;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.Notify;
|
||||
import com.github.catvod.utils.Path;
|
||||
import com.github.catvod.utils.QRCode;
|
||||
import com.github.catvod.utils.ResUtil;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class TianYiHandler {
|
||||
|
||||
public static final String API_URL = "https://open.e.189.cn";
|
||||
private ScheduledExecutorService service;
|
||||
private AlertDialog dialog;
|
||||
private Cache cache = null;
|
||||
|
||||
public File getCache() {
|
||||
return Path.tv("tianyi");
|
||||
}
|
||||
|
||||
public File geteCache() {
|
||||
return Path.tv("tianyie");
|
||||
}
|
||||
|
||||
private String indexUrl = "";
|
||||
|
||||
private String reqId;
|
||||
private String lt;
|
||||
|
||||
private SimpleCookieJar cookieJar;
|
||||
|
||||
public SimpleCookieJar getCookieJar() {
|
||||
return cookieJar;
|
||||
}
|
||||
|
||||
private static class Loader {
|
||||
static volatile TianYiHandler INSTANCE = new TianYiHandler();
|
||||
}
|
||||
|
||||
public static TianYiHandler get() {
|
||||
return TianYiHandler.Loader.INSTANCE;
|
||||
}
|
||||
|
||||
private TianYiHandler() {
|
||||
|
||||
cookieJar = new SimpleCookieJar();
|
||||
cache = Cache.objectFrom(Path.read(getCache()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
public void init() {
|
||||
String user = cache.getUser().getCookie();
|
||||
if (StringUtils.isNoneBlank(user)) {
|
||||
JsonObject jsonObject = Json.safeObject(user);
|
||||
String username = jsonObject.get("username").getAsString();
|
||||
String password = jsonObject.get("password").getAsString();
|
||||
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
|
||||
this.startFlow();
|
||||
return;
|
||||
}
|
||||
this.loginWithPassword(username, password);
|
||||
} else {
|
||||
this.startFlow();
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanCookie() {
|
||||
|
||||
cache.setTianyiUser(new User(""));
|
||||
}
|
||||
|
||||
private Map<String, String> getHeader(String url) {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
|
||||
headers.put("Cookie", cookieJar.loadForRequest(url));
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void refreshCookie() throws IOException {
|
||||
|
||||
String url = "https://cloud.189.cn/api/portal/loginUrl.action?redirectURL=https%3A%2F%2Fcloud.189.cn%2Fweb%2Fredirect.html&defaultSaveName=3&defaultSaveNameCheck=uncheck&browserId=16322f24d9405fb83331c3f6ce971b53";
|
||||
String index = OkHttp.getLocation(url, getHeader(url));
|
||||
SpiderDebug.log("unifyAccountLogin:" + index);
|
||||
|
||||
Map<String, List<String>> resHeaderMap = OkHttp.getLocationHeader(index, getHeader(index));
|
||||
saveCookie(resHeaderMap.get("Set-Cookie"), index);
|
||||
indexUrl = resHeaderMap.get("Location").get(0);
|
||||
SpiderDebug.log("callbackUnify: " + indexUrl);
|
||||
|
||||
Map<String, List<String>> callbackUnify = OkHttp.getLocationHeader(indexUrl, getHeader(indexUrl));
|
||||
saveCookie(callbackUnify.get("Set-Cookie"), indexUrl);
|
||||
SpiderDebug.log("refreshCookie header:" + Json.toJson(callbackUnify));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* 保存cookie
|
||||
*
|
||||
* @param cookie
|
||||
* @param url
|
||||
*/
|
||||
private void saveCookie(List<String> cookie, String url) {
|
||||
if (cookie != null && cookie.size() > 0) {
|
||||
cookieJar.saveFromResponse(url, cookie);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] startScan() throws Exception {
|
||||
|
||||
|
||||
SpiderDebug.log("index ori: " + "https://cloud.189.cn/api/portal/loginUrl.action?redirectURL=https%3A%2F%2Fcloud.189.cn%2Fweb%2Fredirect.html&defaultSaveName=3&defaultSaveNameCheck=uncheck&browserId=dff95dced0b03d9d972d920f03ddd05e");
|
||||
String index = OkHttp.getLocation("https://cloud.189.cn/api/portal/loginUrl.action?redirectURL=https://cloud.189.cn/web/redirect.html&defaultSaveName=3&defaultSaveNameCheck=uncheck&browserId=8d38da4344fba4699d13d6e6854319d7", Map.of("Cookie", ""));
|
||||
SpiderDebug.log("index red: " + index);
|
||||
Map<String, List<String>> resHeaderMap = OkHttp.getLocationHeader(index, getHeader(index));
|
||||
|
||||
saveCookie(resHeaderMap.get("Set-Cookie"), index);
|
||||
|
||||
indexUrl = resHeaderMap.get("Location").get(0);
|
||||
SpiderDebug.log("indexUrl red: " + indexUrl);
|
||||
|
||||
HttpUrl httpParams = HttpUrl.parse(indexUrl);
|
||||
reqId = httpParams.queryParameter("reqId");
|
||||
lt = httpParams.queryParameter("lt");
|
||||
|
||||
Result result = appConf();
|
||||
|
||||
// Step 1: Get UUID
|
||||
JsonObject uuidInfo = getUUID();
|
||||
String uuid = uuidInfo.get("uuid").getAsString();
|
||||
String encryuuid = uuidInfo.get("encryuuid").getAsString();
|
||||
String encodeuuid = uuidInfo.get("encodeuuid").getAsString();
|
||||
|
||||
// Step 2: Get QR Code
|
||||
byte[] byteStr = downloadQRCode(encodeuuid, reqId);
|
||||
|
||||
Init.run(() -> showQRCode(byteStr));
|
||||
// Step 3: Check login status
|
||||
// return
|
||||
Init.execute(() -> startService(uuid, encryuuid, reqId, lt, result.paramId, result.returnUrl));
|
||||
/*Map<String, Object> result = new HashMap<>();
|
||||
result.put("qrcode", "data:image/png;base64," + qrCode);
|
||||
result.put("status", "NEW");*/
|
||||
return byteStr;
|
||||
|
||||
}
|
||||
|
||||
public void loginWithPassword(String uname, String passwd) {
|
||||
try {
|
||||
// Step 1: 获取加密配置
|
||||
JsonObject encryptConf = getEncryptConf();
|
||||
String pubKey = encryptConf.getAsJsonObject("data").get("pubKey").getAsString();
|
||||
|
||||
// Step 2: 获取登录参数
|
||||
PasswordLoginParams params = getLoginParams();
|
||||
|
||||
// Step 3: 准备请求头
|
||||
Map<String, String> headers = buildLoginHeaders(params.lt, params.reqId);
|
||||
|
||||
// Step 4: 获取应用配置
|
||||
AppConfig config = getAppConfig(headers);
|
||||
|
||||
// Step 5: 加密凭证
|
||||
EncryptedCredentials credentials = encryptCredentials(uname, passwd, pubKey);
|
||||
|
||||
// Step 6: 提交登录
|
||||
LoginResult loginResult = submitLogin(headers, config, credentials);
|
||||
|
||||
// Step 7: 处理登录结果
|
||||
processLoginResult(loginResult);
|
||||
|
||||
//保存的账号密码
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("username", uname);
|
||||
jsonObject.addProperty("password", passwd);
|
||||
cache.setTianyiUser(new User(Json.toJson(jsonObject)));
|
||||
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log("登录失败: " + e.getMessage());
|
||||
Notify.show("天翼登录失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助方法实现
|
||||
private JsonObject getEncryptConf() throws Exception {
|
||||
String url = API_URL + "/api/logbox/config/encryptConf.do?appId=cloud";
|
||||
OkResult result = OkHttp.post(url, new HashMap<>(), getHeader(url));
|
||||
return Json.safeObject(result.getBody());
|
||||
}
|
||||
|
||||
private PasswordLoginParams getLoginParams() throws Exception {
|
||||
String url = "https://cloud.189.cn/api/portal/loginUrl.action?redirectURL=https://cloud.189.cn/web/redirect.html?returnURL=/main.action";
|
||||
Map<String, List<String>> resHeaderMap = OkHttp.getLocationHeader(url, getHeader(url));
|
||||
|
||||
|
||||
String redUrl = resHeaderMap.get("Location").get(0);
|
||||
resHeaderMap = OkHttp.getLocationHeader(redUrl, getHeader(redUrl));
|
||||
HttpUrl httpUrl = HttpUrl.parse(resHeaderMap.get("Location").get(0));
|
||||
return new PasswordLoginParams(httpUrl.queryParameter("reqId"), httpUrl.queryParameter("lt"));
|
||||
}
|
||||
|
||||
private Map<String, String> buildLoginHeaders(String lt, String reqId) {
|
||||
Map<String, String> headers = new HashMap<>(getHeader(API_URL));
|
||||
headers.put("Content-Type", "application/x-www-form-urlencoded");
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/76.0");
|
||||
headers.put("Referer", "https://open.e.189.cn/");
|
||||
headers.put("Lt", lt);
|
||||
headers.put("Reqid", reqId);
|
||||
return headers;
|
||||
}
|
||||
|
||||
private AppConfig getAppConfig(Map<String, String> headers) throws Exception {
|
||||
Map<String, String> data = new HashMap<>();
|
||||
data.put("version", "2.0");
|
||||
data.put("appKey", "cloud");
|
||||
|
||||
OkResult result = OkHttp.post(API_URL + "/api/logbox/oauth2/appConf.do", data, headers);
|
||||
JsonObject dataObj = Json.safeObject(result.getBody()).getAsJsonObject("data");
|
||||
return new AppConfig(dataObj.get("returnUrl").getAsString(), dataObj.get("paramId").getAsString());
|
||||
}
|
||||
|
||||
private EncryptedCredentials encryptCredentials(String uname, String passwd, String pubKey) throws Exception {
|
||||
SpiderDebug.log("pubKey: " + pubKey);
|
||||
PublicKey publicKey = parsePublicKey(pubKey);
|
||||
return new EncryptedCredentials(encryptRSA(uname, publicKey), encryptRSA(passwd, publicKey));
|
||||
}
|
||||
|
||||
private LoginResult submitLogin(Map<String, String> headers, AppConfig config, EncryptedCredentials credentials) throws Exception {
|
||||
Map<String, String> data = new HashMap<>();
|
||||
data.put("appKey", "cloud");
|
||||
data.put("version", "2.0");
|
||||
data.put("accountType", "02");
|
||||
//data.put("mailSuffix", "@189.cn");
|
||||
data.put("validateCode", "");
|
||||
data.put("returnUrl", config.returnUrl);
|
||||
data.put("paramId", config.paramId);
|
||||
data.put("captchaToken", "");
|
||||
data.put("dynamicCheck", "FALSE");
|
||||
data.put("clientType", "1");
|
||||
data.put("cb_SaveName", "3");
|
||||
data.put("isOauth2", "false");
|
||||
data.put("userName", "{NRP}" + credentials.encryptedUname);
|
||||
data.put("password", "{NRP}" + credentials.encryptedPasswd);
|
||||
|
||||
OkResult result = OkHttp.post(API_URL + "/api/logbox/oauth2/loginSubmit.do", data, headers);
|
||||
return new LoginResult(Json.safeObject(result.getBody()).get("toUrl").getAsString(), result.getResp().get("Set-Cookie"));
|
||||
}
|
||||
|
||||
private void processLoginResult(LoginResult result) throws Exception {
|
||||
saveCookie(result.cookies, API_URL + "/api/logbox/oauth2/loginSubmit.do");
|
||||
|
||||
// 处理重定向
|
||||
Map<String, List<String>> okResult = OkHttp.getLocationHeader(result.toUrl, getHeader(result.toUrl));
|
||||
saveCookie(okResult.get("Set-Cookie"), result.toUrl);
|
||||
}
|
||||
|
||||
// 辅助类
|
||||
private static class PasswordLoginParams {
|
||||
final String reqId;
|
||||
final String lt;
|
||||
|
||||
PasswordLoginParams(String reqId, String lt) {
|
||||
this.reqId = reqId;
|
||||
this.lt = lt;
|
||||
}
|
||||
}
|
||||
|
||||
private static class AppConfig {
|
||||
final String returnUrl;
|
||||
final String paramId;
|
||||
|
||||
AppConfig(String returnUrl, String paramId) {
|
||||
this.returnUrl = returnUrl;
|
||||
this.paramId = paramId;
|
||||
}
|
||||
}
|
||||
|
||||
private static class EncryptedCredentials {
|
||||
final String encryptedUname;
|
||||
final String encryptedPasswd;
|
||||
|
||||
EncryptedCredentials(String encryptedUname, String encryptedPasswd) {
|
||||
this.encryptedUname = encryptedUname;
|
||||
this.encryptedPasswd = encryptedPasswd;
|
||||
}
|
||||
}
|
||||
|
||||
private static class LoginResult {
|
||||
final String toUrl;
|
||||
final List<String> cookies;
|
||||
|
||||
LoginResult(String toUrl, List<String> cookies) {
|
||||
this.toUrl = toUrl;
|
||||
this.cookies = cookies;
|
||||
}
|
||||
}
|
||||
|
||||
private PublicKey parsePublicKey(String pubKey) throws Exception {
|
||||
|
||||
byte[] decoded = android.util.Base64.decode(pubKey, Base64.NO_WRAP);
|
||||
X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded);
|
||||
return KeyFactory.getInstance("RSA").generatePublic(spec);
|
||||
|
||||
}
|
||||
|
||||
private String encryptRSA(String data, PublicKey publicKey) throws Exception {
|
||||
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
byte[] encrypted = cipher.doFinal(data.getBytes(Charset.defaultCharset()));
|
||||
return bytesToHex(encrypted);
|
||||
}
|
||||
|
||||
private String bytesToHex(byte[] bytes) {
|
||||
StringBuilder hex = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
hex.append(String.format("%02x", b));
|
||||
}
|
||||
return hex.toString().toUpperCase();
|
||||
}
|
||||
|
||||
private String api(String url, Map<String, String> params, Map<String, String> headers, Integer retry, String method) throws InterruptedException {
|
||||
|
||||
|
||||
int leftRetry = retry != null ? retry : 3;
|
||||
|
||||
OkResult okResult;
|
||||
if ("GET".equals(method)) {
|
||||
okResult = OkHttp.get(this.API_URL + url, params, headers);
|
||||
} else {
|
||||
okResult = OkHttp.post(this.API_URL + url, params, headers);
|
||||
}
|
||||
if (okResult.getResp().get("Set-Cookie") != null) {
|
||||
saveCookie(okResult.getResp().get("Set-Cookie"), this.API_URL);
|
||||
}
|
||||
|
||||
if (okResult.getCode() != 200 && leftRetry > 0) {
|
||||
SpiderDebug.log("请求" + url + " failed;");
|
||||
Thread.sleep(1000);
|
||||
return api(url, params, headers, leftRetry - 1, method);
|
||||
}
|
||||
SpiderDebug.log("请求" + url + " 成功;" + "返回结果:" + okResult.getBody());
|
||||
return okResult.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取appConf
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
|
||||
private @NotNull Result appConf() throws Exception {
|
||||
Map<String, String> tHeaders = getHeader(API_URL);
|
||||
tHeaders.put("Content-Type", "application/x-www-form-urlencoded");
|
||||
tHeaders.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/76.0");
|
||||
tHeaders.put("Referer", indexUrl);
|
||||
tHeaders.put("origin", API_URL);
|
||||
tHeaders.put("Lt", lt);
|
||||
tHeaders.put("Reqid", reqId);
|
||||
|
||||
Map<String, String> param = new HashMap<>();
|
||||
|
||||
param.put("version", "2.0");
|
||||
param.put("appKey", "cloud");
|
||||
String paramId;
|
||||
String returnUrl;
|
||||
String body = api("/api/logbox/oauth2/appConf.do", param, tHeaders, 3, "POST");
|
||||
|
||||
paramId = Json.safeObject(body).get("data").getAsJsonObject().get("paramId").getAsString();
|
||||
returnUrl = Json.safeObject(body).get("data").getAsJsonObject().get("returnUrl").getAsString();
|
||||
|
||||
SpiderDebug.log("paramId: " + paramId);
|
||||
SpiderDebug.log("returnUrl: " + returnUrl);
|
||||
return new Result(paramId, returnUrl);
|
||||
}
|
||||
|
||||
public void setCookie(JsonObject obj) {
|
||||
cookieJar.setGlobalCookie(obj);
|
||||
}
|
||||
|
||||
private static class Result {
|
||||
public final String paramId;
|
||||
public final String returnUrl;
|
||||
|
||||
public Result(String paramId, String returnUrl) {
|
||||
this.paramId = paramId;
|
||||
this.returnUrl = returnUrl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public JsonObject getUUID() throws InterruptedException {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("appId", "cloud");
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36");
|
||||
headers.put("lt", lt);
|
||||
headers.put("reqId", reqId);
|
||||
headers.put("referer", indexUrl);
|
||||
|
||||
|
||||
String body = api("/api/logbox/oauth2/getUUID.do", params, headers, 3, "POST");
|
||||
return Json.safeObject(body);
|
||||
|
||||
}
|
||||
|
||||
public byte[] downloadQRCode(String uuid, String reqId) throws IOException {
|
||||
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36");
|
||||
|
||||
headers.put("referer", indexUrl);
|
||||
|
||||
// OkResult okResult = OkHttp.get("https://open.e.189.cn/api/logbox/oauth2/image.do", params, headers);
|
||||
//.addQueryParameter("uuid", uuid).addQueryParameter("REQID", reqId)
|
||||
HttpUrl url = HttpUrl.parse(API_URL + "/api/logbox/oauth2/image.do?uuid=" + uuid + "&REQID=" + reqId).newBuilder().build();
|
||||
|
||||
Request request = new Request.Builder().url(url).headers(Headers.of(headers)).build();
|
||||
Response response = OkHttp.newCall(request);
|
||||
if (response.code() == 200) {
|
||||
return response.body().bytes();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private Map<String, Object> checkLoginStatus(String uuid, String encryuuid, String reqId, String lt, String paramId, String returnUrl) throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("appId", "cloud");
|
||||
params.put("encryuuid", encryuuid);
|
||||
params.put("uuid", uuid);
|
||||
params.put("date", DateFormatUtils.format(new Date(), "yyyy-MM-ddHH:mm:ss") + new Random().nextInt(24));
|
||||
params.put("returnUrl", URLEncoder.encode(returnUrl, "UTF-8"));
|
||||
params.put("clientType", "1");
|
||||
params.put("timeStamp", (System.currentTimeMillis() / 1000 + 1) + "000");
|
||||
params.put("cb_SaveName", "0");
|
||||
params.put("isOauth2", "false");
|
||||
params.put("state", "");
|
||||
params.put("paramId", paramId);
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36");
|
||||
headers.put("referer", indexUrl);
|
||||
headers.put("Reqid", reqId);
|
||||
|
||||
String body = api("/api/logbox/oauth2/qrcodeLoginState.do", params, headers, 3, "POST");
|
||||
// OkResult okResult = OkHttp.post(API_URL + "/api/logbox/oauth2/qrcodeLoginState.do", params, headers);
|
||||
SpiderDebug.log("qrcodeLoginState result------" + body);
|
||||
|
||||
JsonObject obj = Json.safeObject(body).getAsJsonObject();
|
||||
if (Objects.nonNull(obj.get("status")) && obj.get("status").getAsInt() == 0) {
|
||||
|
||||
SpiderDebug.log("扫码成功------" + obj.get("redirectUrl").getAsString());
|
||||
String redirectUrl = obj.get("redirectUrl").getAsString();
|
||||
|
||||
|
||||
fetchUserInfo(redirectUrl);
|
||||
|
||||
|
||||
} else {
|
||||
SpiderDebug.log("扫码失败------" + body);
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void fetchUserInfo(String redirectUrl) throws IOException {
|
||||
|
||||
|
||||
Map<String, List<String>> okResult = OkHttp.getLocationHeader(redirectUrl, getHeader(redirectUrl));
|
||||
saveCookie(okResult.get("Set-Cookie"), redirectUrl);
|
||||
SpiderDebug.log("扫码返回数据:" + Json.toJson(okResult));
|
||||
if (okResult.containsKey("Set-Cookie")) {
|
||||
|
||||
//停止检验线程,关闭弹窗
|
||||
stopService();
|
||||
}
|
||||
|
||||
|
||||
/* if (okResult.getCode() == 200) {
|
||||
okResult.getBody();
|
||||
}*/
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 显示qrcode
|
||||
*
|
||||
* @param bytes
|
||||
*/
|
||||
public void showQRCode(byte[] bytes) {
|
||||
try {
|
||||
int size = ResUtil.dp2px(240);
|
||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(size, size);
|
||||
ImageView image = new ImageView(Init.context());
|
||||
image.setScaleType(ImageView.ScaleType.CENTER_CROP);
|
||||
image.setImageBitmap(QRCode.Bytes2Bimap(bytes));
|
||||
FrameLayout frame = new FrameLayout(Init.context());
|
||||
params.gravity = Gravity.CENTER;
|
||||
frame.addView(image, params);
|
||||
dialog = new AlertDialog.Builder(Init.getActivity()).setView(frame).setOnCancelListener(this::dismiss).setOnDismissListener(this::dismiss).show();
|
||||
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
Notify.show("请使用天翼网盘App扫描二维码");
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public void startFlow() {
|
||||
Init.run(this::showInput);
|
||||
}
|
||||
|
||||
|
||||
private void showInput() {
|
||||
try {
|
||||
int margin = ResUtil.dp2px(16);
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
LinearLayout frame = new LinearLayout(Init.context());
|
||||
frame.setOrientation(LinearLayout.VERTICAL);
|
||||
// frame.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
// params.setMargins(margin, margin, margin, margin);
|
||||
EditText username = new EditText(Init.context());
|
||||
username.setHint("请输入天翼用户名");
|
||||
EditText password = new EditText(Init.context());
|
||||
password.setHint("请输入天翼密码");
|
||||
frame.addView(username, params);
|
||||
frame.addView(password, params);
|
||||
dialog = new AlertDialog.Builder(Init.getActivity()).setTitle("请输入天意用户名和密码").setView(frame).setNegativeButton(android.R.string.cancel, null).setPositiveButton(android.R.string.ok, (dialog, which) -> onPositive(username.getText().toString(), password.getText().toString())).show();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onPositive(String username, String password) {
|
||||
dismiss();
|
||||
Init.execute(() -> {
|
||||
loginWithPassword(username, password);
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private void dismiss() {
|
||||
try {
|
||||
if (dialog != null) dialog.dismiss();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void dismiss(DialogInterface dialog) {
|
||||
stopService();
|
||||
}
|
||||
|
||||
private void stopService() {
|
||||
if (service != null) service.shutdownNow();
|
||||
Init.run(this::dismiss);
|
||||
}
|
||||
|
||||
public void startService(String uuid, String encryuuid, String reqId, String lt, String paramId, String returnUrl) {
|
||||
SpiderDebug.log("----start checkLoginStatus service");
|
||||
|
||||
service = Executors.newScheduledThreadPool(1);
|
||||
|
||||
service.scheduleWithFixedDelay(() -> {
|
||||
SpiderDebug.log("----checkLoginStatus ing....");
|
||||
try {
|
||||
checkLoginStatus(uuid, encryuuid, reqId, lt, paramId, returnUrl);
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log("----checkLoginStatus error" + e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}, 1, 3, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,413 +0,0 @@
|
|||
package com.github.catvod.api;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.bean.tianyi.Item;
|
||||
import com.github.catvod.bean.tianyi.ShareData;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.net.OkResult;
|
||||
import com.github.catvod.spider.Init;
|
||||
import com.github.catvod.utils.*;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class TianyiApi {
|
||||
private String apiUrl = "https://cloud.189.cn/api/open/share/";
|
||||
public static final String URL_CONTAIN = "cloud.189.cn/";
|
||||
|
||||
|
||||
private Map<String, JsonObject> shareTokenCache = new HashMap<>();
|
||||
|
||||
|
||||
private ScheduledExecutorService service;
|
||||
private String sessionKey = "";
|
||||
private TianYiHandler tianYiHandler;
|
||||
private SimpleCookieJar cookieJar;
|
||||
|
||||
|
||||
public String[] getPlayFormatList() {
|
||||
return new String[]{"天意"};
|
||||
}
|
||||
|
||||
private static class Loader {
|
||||
static volatile TianyiApi INSTANCE = new TianyiApi();
|
||||
}
|
||||
|
||||
public static TianyiApi get() {
|
||||
return TianyiApi.Loader.INSTANCE;
|
||||
}
|
||||
|
||||
public void setCookie(String token) throws Exception {
|
||||
if (StringUtils.isNoneBlank(token)) {
|
||||
JsonObject obj = Json.safeObject(token);
|
||||
//初始化CookieJar
|
||||
if (Objects.nonNull(obj)) {
|
||||
tianYiHandler.setCookie(obj);
|
||||
tianYiHandler.loginWithPassword(obj.get("username").getAsString(), obj.get("password").getAsString());
|
||||
}
|
||||
}
|
||||
if (!isCookieValid()) {
|
||||
SpiderDebug.log("CookieJar不合法,请重新登录");
|
||||
// tianYiHandler.startScan();
|
||||
}
|
||||
getUserSizeInfo();
|
||||
this.sessionKey = getUserBriefInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断cookie是否为空,或者SSon为空,那就需要重新登陆
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private boolean isCookieValid() {
|
||||
if (cookieJar.getCookieStore().size() == 0) {
|
||||
SpiderDebug.log("CookieJar为空");
|
||||
return false;
|
||||
} else {
|
||||
for (String key : cookieJar.getCookieStore().keySet()) {
|
||||
Map<String, String> cookieMap = cookieJar.getCookieStore().get(key);
|
||||
for (String k : cookieMap.keySet()) {
|
||||
String cookieobj = cookieMap.get(k);
|
||||
if (k.equals("SSON") && StringUtils.isNoneBlank(cookieobj)) {
|
||||
SpiderDebug.log("SSON 不为空");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
SpiderDebug.log("CookieJar 不合法,重新登录");
|
||||
return false;
|
||||
}
|
||||
|
||||
private Map<String, String> getHeaders() {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) quark-cloud-drive/2.5.20 Chrome/100.0.4896.160 Electron/18.3.5.4-b478491100 Safari/537.36 Channel/pckk_other_ch");
|
||||
|
||||
headers.put("Content-Type", "application/x-www-form-urlencoded");
|
||||
headers.put("accept", "application/json;charset=UTF-8");
|
||||
headers.put("cookie", cookieJar.loadForRequest("https://cloud.189.cn/api/portal/getNewVlcVideoPlayUrl.action"));
|
||||
|
||||
if (StringUtils.isNotBlank(sessionKey)) {
|
||||
headers.put("sessionKey", sessionKey);
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
|
||||
private TianyiApi() {
|
||||
Init.checkPermission();
|
||||
|
||||
tianYiHandler = TianYiHandler.get();
|
||||
tianYiHandler.init();
|
||||
cookieJar = tianYiHandler.getCookieJar();
|
||||
}
|
||||
|
||||
public File getCache() {
|
||||
return Path.tv("tianyi");
|
||||
}
|
||||
|
||||
public Vod getVod(ShareData shareData) throws Exception {
|
||||
getShareToken(shareData);
|
||||
List<Item> files = new ArrayList<>();
|
||||
List<Item> subs = new ArrayList<>();
|
||||
try {
|
||||
JsonArray listData = listFile(1, shareData, files, subs, shareData.getShareId(), shareData.getFolderId(), 1);
|
||||
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log("资源已取消:" + e.getMessage());
|
||||
Notify.show("资源已取消");
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
List<String> playFromtmp = new ArrayList<>();
|
||||
playFromtmp.add("天意");
|
||||
|
||||
|
||||
List<String> playUrl = new ArrayList<>();
|
||||
|
||||
if (files.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int index = 0; index < playFromtmp.size(); index++) {
|
||||
List<String> vodItems = new ArrayList<>();
|
||||
for (Item video_item : files) {
|
||||
vodItems.add(video_item.getEpisodeUrl("电影"));// + findSubs(video_item.getName(), subs));
|
||||
}
|
||||
playUrl.add(TextUtils.join("#", vodItems));
|
||||
}
|
||||
|
||||
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId("");
|
||||
vod.setVodContent("");
|
||||
vod.setVodPic("");
|
||||
vod.setVodName("");
|
||||
vod.setVodPlayUrl(TextUtils.join("$$$", playUrl));
|
||||
vod.setVodPlayFrom(TextUtils.join("$$$", playFromtmp));
|
||||
vod.setTypeName("天意云盘");
|
||||
return vod;
|
||||
}
|
||||
|
||||
public String playerContent(String[] split, String flag) throws Exception {
|
||||
|
||||
String fileId = split[0], shareId = split[1];
|
||||
String playUrl = "";
|
||||
|
||||
playUrl = this.getDownload(shareId, fileId);
|
||||
Map<String, String> header = getHeaders();
|
||||
header.remove("Host");
|
||||
header.remove("Content-Type");
|
||||
|
||||
|
||||
header.put("Cookie", cookieJar.loadForRequest("https://cloud.189.cn/api/portal/getNewVlcVideoPlayUrl.action"));
|
||||
return Result.get().url(ProxyServer.INSTANCE.buildProxyUrl(playUrl, header)).octet().header(header).string();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param url
|
||||
* @param params get 参数
|
||||
* @param data post json
|
||||
* @param retry
|
||||
* @param method
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private String api(String url, Map<String, String> params, Map<String, Object> data, Integer retry, String method) throws Exception {
|
||||
|
||||
|
||||
int leftRetry = retry != null ? retry : 3;
|
||||
|
||||
OkResult okResult;
|
||||
if ("GET".equals(method)) {
|
||||
okResult = OkHttp.get(this.apiUrl + url, params, getHeaders());
|
||||
} else {
|
||||
okResult = OkHttp.post(this.apiUrl + url, Json.toJson(data), getHeaders());
|
||||
}
|
||||
/* if (okResult.getResp().get("Set-Cookie") != null) {
|
||||
Matcher matcher = Pattern.compile("__puus=([^;]+)").matcher(StringUtils.join(okResult.getResp().get("Set-Cookie"), ";;;"));
|
||||
if (matcher.find()) {
|
||||
Matcher cookieMatcher = Pattern.compile("__puus=([^;]+)").matcher(this.cookie);
|
||||
if (cookieMatcher.find() && !cookieMatcher.group(1).equals(matcher.group(1))) {
|
||||
this.cookie = this.cookie.replaceAll("__puus=[^;]+", "__puus=" + matcher.group(1));
|
||||
} else {
|
||||
this.cookie = this.cookie + ";__puus=" + matcher.group(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (okResult.getCode() != 200 && leftRetry > 0) {
|
||||
SpiderDebug.log("api error code:" + okResult.getCode());
|
||||
Thread.sleep(1000);
|
||||
return api(url, params, data, leftRetry - 1, method);
|
||||
}
|
||||
return okResult.getBody();
|
||||
}
|
||||
|
||||
|
||||
public ShareData getShareData(String url, String accessCode) {
|
||||
// 从整个URL中直接提取访问码,无论格式如何
|
||||
Matcher accessMatcher = Pattern.compile("访问码[::]([a-zA-Z0-9]+)").matcher(url);
|
||||
if (accessMatcher.find()) {
|
||||
accessCode = accessMatcher.group(1);
|
||||
} else if (accessCode == null || accessCode.isEmpty()) {
|
||||
accessCode = "";
|
||||
}
|
||||
|
||||
String shareCode = null;
|
||||
// 第一种匹配规则:兼容http和https
|
||||
Matcher matcher = Pattern.compile("https?:\\/\\/cloud\\.189\\.cn\\/web\\/share\\?code=([^&\\s]+)").matcher(url);
|
||||
if (matcher.find() && matcher.group(1) != null) {
|
||||
shareCode = matcher.group(1);
|
||||
} else {
|
||||
// 第二种匹配规则:直接匹配 cloud.189.cn/t/ 格式,兼容http和https,匹配到空格前
|
||||
Matcher fallbackMatcher = Pattern.compile("https?:\\/\\/cloud\\.189\\.cn\\/t/([^\\s]+)").matcher(url);
|
||||
if (fallbackMatcher.find()) {
|
||||
shareCode = fallbackMatcher.group(1);
|
||||
}
|
||||
}
|
||||
|
||||
ShareData shareData = new ShareData(shareCode, "0");
|
||||
shareData.setSharePwd(accessCode);
|
||||
return shareData;
|
||||
}
|
||||
|
||||
|
||||
private String getUserBriefInfo() throws Exception {
|
||||
OkResult result = OkHttp.get("https://cloud.189.cn/api/portal/v2/getUserBriefInfo.action", new HashMap<>(), getHeaders());
|
||||
JsonObject obj = Json.safeObject(result.getBody());
|
||||
return obj.get("sessionKey") == null ? "" : obj.get("sessionKey").getAsString();
|
||||
}
|
||||
|
||||
private String getUserSizeInfo() throws Exception {
|
||||
OkResult result = OkHttp.get("https://cloud.189.cn/api/portal/getUserSizeInfo.action", new HashMap<>(), getHeaders());
|
||||
JsonObject res = Json.safeObject(result.getBody());
|
||||
if (StringUtils.isAllBlank(result.getBody()) || (Objects.nonNull(res.get("errorCode")) && res.get("errorCode").getAsString().equals("InvalidSessionKey"))) {
|
||||
// tianYiHandler.startScan();
|
||||
tianYiHandler.refreshCookie();
|
||||
//tianYiHandler.startScan();
|
||||
}
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void getShareToken(ShareData shareData) throws Exception {
|
||||
if (!this.shareTokenCache.containsKey(shareData.getShareId())) {
|
||||
this.shareTokenCache.remove(shareData.getShareId());
|
||||
JsonObject shareToken = Json.safeObject(api("getShareInfoByCodeV2.action?noCache=0.8886566349412803&shareCode=" + shareData.getShareId(), new HashMap<>(), new HashMap<>(), 0, "GET"));
|
||||
/**
|
||||
* {
|
||||
* "res_code" : 0.0,
|
||||
* "res_message" : "成功",
|
||||
* "accessCode" : "",
|
||||
* "creator" : {
|
||||
* "iconURL" : "",
|
||||
* "oper" : false,
|
||||
* "ownerAccount" : "185****1601@189.cn",
|
||||
* "superVip" : 33.0,
|
||||
* "vip" : 0.0
|
||||
* },
|
||||
* "expireTime" : 6.0,
|
||||
* "expireType" : 1.0,
|
||||
* "fileCreateDate" : "2025-03-20 13:49:18",
|
||||
* "fileId" : "12350115314094",
|
||||
* "fileLastOpTime" : "2025-03-20 13:49:19",
|
||||
* "fileName" : "05_如何制作动感影集.mp4等",
|
||||
* "fileSize" : 0.0,
|
||||
* "fileType" : "batchShare",
|
||||
* "isFolder" : true,
|
||||
* "needAccessCode" : 1.0,
|
||||
* "reviewStatus" : 1.0,
|
||||
* "shareDate" : 1.742449758E12,
|
||||
* "shareMode" : 1.0,
|
||||
* "shareType" : 1.0
|
||||
* }
|
||||
*/
|
||||
if (Objects.nonNull(shareToken.get("res_code")) && shareToken.get("res_code").getAsInt() == 0) {
|
||||
shareData.setShareId(shareToken.get("shareId").getAsString());
|
||||
shareData.setShareMode(shareToken.get("shareMode").getAsInt());
|
||||
shareData.setFolder(shareToken.get("isFolder").getAsBoolean());
|
||||
shareData.setFileId(shareToken.get("fileId").getAsString());
|
||||
shareData.setFolderId(shareToken.get("fileId").getAsString());
|
||||
|
||||
this.shareTokenCache.put(shareData.getShareId(), shareToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JsonArray listFile(int shareIndex, ShareData shareData, List<Item> videos, List<Item> subtitles, String shareId, String folderId, Integer page) throws Exception {
|
||||
int prePage = 200;
|
||||
page = page != null ? page : 1;
|
||||
String url = "listShareDir.action?" + "pageNum=" + page + "&pageSize=" + prePage + "&fileId=" + folderId + "&shareDirFileId=" + folderId + "&isFolder=" + shareData.getFolder() + "&shareId=" + shareId + "&shareMode=" + shareData.getShareMode() + "&iconOption=5" + "&orderBy=filename" + "&descending=false" + "&accessCode=" + shareData.getSharePwd();
|
||||
|
||||
JsonObject listData = Json.safeObject(api(url, Collections.emptyMap(), Collections.emptyMap(), 0, "GET"));
|
||||
if (listData.get("res_code").getAsInt() != 0) return new JsonArray();
|
||||
if (listData.get("fileListAO").getAsJsonObject().get("count").getAsInt() == 0 && listData.get("fileListAO").getAsJsonObject().get("fileListSize").getAsInt() == 0)
|
||||
return new JsonArray();
|
||||
|
||||
JsonArray items = listData.get("fileListAO").getAsJsonObject().get("fileList").getAsJsonArray();
|
||||
JsonArray subDir = listData.get("fileListAO").getAsJsonObject().get("folderList").getAsJsonArray();
|
||||
|
||||
for (JsonElement item : items) {
|
||||
if (item.getAsJsonObject().get("mediaType").getAsInt() == 3) {
|
||||
if (item.getAsJsonObject().get("size").getAsLong() < 1024 * 1024 * 5) continue;
|
||||
|
||||
videos.add(Item.objectFrom(item.getAsJsonObject(), shareData.getShareId(), shareIndex));
|
||||
} /*else if ("file".equals(item.get("type")) && this.subtitleExts.contains("." + Util.getExt((String) item.get("file_name")))) {
|
||||
subtitles.add(Item.objectFrom(item, shareData.getShareId(), shareIndex));
|
||||
}*/
|
||||
}
|
||||
if (listData.get("fileListAO").getAsJsonObject().get("count").getAsInt() > (items.size() + subDir.size())) {
|
||||
JsonArray nextItems = listFile(shareIndex, shareData, videos, subtitles, shareId, folderId, page + 1);
|
||||
items.addAll(nextItems);
|
||||
}
|
||||
for (JsonElement dir : subDir) {
|
||||
String subfolderId = dir.getAsJsonObject().get("id").getAsString();
|
||||
JsonArray subItems = listFile(shareIndex, shareData, videos, subtitles, shareId, subfolderId, null);
|
||||
items.addAll(subItems);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private Map<String, Object> findBestLCS(Item mainItem, List<Item> targetItems) {
|
||||
List<Map<String, Object>> results = new ArrayList<>();
|
||||
int bestMatchIndex = 0;
|
||||
for (int i = 0; i < targetItems.size(); i++) {
|
||||
Util.LCSResult currentLCS = Util.lcs(mainItem.getName(), targetItems.get(i).getName());
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("target", targetItems.get(i));
|
||||
result.put("lcs", currentLCS);
|
||||
results.add(result);
|
||||
if (currentLCS.length > results.get(bestMatchIndex).get("lcs").toString().length()) {
|
||||
bestMatchIndex = i;
|
||||
}
|
||||
}
|
||||
Map<String, Object> bestMatch = results.get(bestMatchIndex);
|
||||
Map<String, Object> finalResult = new HashMap<>();
|
||||
finalResult.put("allLCS", results);
|
||||
finalResult.put("bestMatch", bestMatch);
|
||||
finalResult.put("bestMatchIndex", bestMatchIndex);
|
||||
return finalResult;
|
||||
}
|
||||
|
||||
public void getFilesByShareUrl(int shareIndex, String shareInfo, List<Item> videos, List<Item> subtitles) throws Exception {
|
||||
ShareData shareData = getShareData((String) shareInfo, "");
|
||||
if (shareData == null) return;
|
||||
getShareToken(shareData);
|
||||
if (!this.shareTokenCache.containsKey(shareData.getShareId())) return;
|
||||
listFile(shareIndex, shareData, videos, subtitles, shareData.getShareId(), shareData.getFolderId(), 1);
|
||||
if (!subtitles.isEmpty()) {
|
||||
for (Item video : videos) {
|
||||
Map<String, Object> matchSubtitle = findBestLCS(video, subtitles);
|
||||
if (matchSubtitle.get("bestMatch") != null) {
|
||||
video.setSubtitle((String) ((Map<String, Object>) matchSubtitle.get("bestMatch")).get("target"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String getDownload(String shareId, String fileId) throws Exception {
|
||||
Map<String, String> headers = getHeaders();
|
||||
//headers.remove("sessionKey");
|
||||
OkResult result = OkHttp.get("https://cloud.189.cn/api/portal/getNewVlcVideoPlayUrl.action?shareId=" + shareId + "&dt=1&fileId=" + fileId + "&type=4&key=noCache", new HashMap<>(), headers);
|
||||
JsonObject res = Json.safeObject(result.getBody());
|
||||
if (Objects.nonNull(res.get("res_code")) && res.get("res_code").getAsInt() == 0) {
|
||||
|
||||
if (res.get("normal") != null) {
|
||||
String normal = res.get("normal").getAsJsonObject().get("url").getAsString();
|
||||
//String downloadUrl = OkHttp.getLocation(normal, headers);
|
||||
SpiderDebug.log("获取天翼下载地址成功:" + normal);
|
||||
return normal;
|
||||
}
|
||||
} else if (res.get("errorCode") != null && res.get("errorCode").getAsString().equals("InvalidSessionKey")) {
|
||||
//刷新cookie
|
||||
SpiderDebug.log("天意cookie 过期,刷新cookie。。。。");
|
||||
tianYiHandler.refreshCookie();
|
||||
//重试下载
|
||||
SpiderDebug.log("重试下载。。。。");
|
||||
getDownload(shareId, fileId);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,753 +0,0 @@
|
|||
package com.github.catvod.api;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.SystemClock;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Gravity;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.bean.uc.Cache;
|
||||
import com.github.catvod.bean.uc.Item;
|
||||
import com.github.catvod.bean.uc.ShareData;
|
||||
import com.github.catvod.bean.uc.User;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.net.OkResult;
|
||||
import com.github.catvod.spider.Init;
|
||||
import com.github.catvod.spider.Proxy;
|
||||
import com.github.catvod.utils.*;
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.commons.lang3.RandomUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class UCApi {
|
||||
private String apiUrl = "https://pc-api.uc.cn/1/clouddrive/";
|
||||
private String cookie = "";
|
||||
private String cookieToken = "";
|
||||
private String ckey = "";
|
||||
private Map<String, Map<String, Object>> shareTokenCache = new HashMap<>();
|
||||
private String pr = "pr=UCBrowser&fr=pc&sys=darwin&ve=1.8.6&ut=Nk27FcCv6q1eo6rXz8QHR/nIG6qLA3jh7KdL+agFgcOvww==";
|
||||
private List<String> subtitleExts = Arrays.asList(".srt", ".ass", ".scc", ".stl", ".ttml");
|
||||
private Map<String, String> saveFileIdCaches = new HashMap<>();
|
||||
private String saveDirId = null;
|
||||
private final String saveDirName = "TV";
|
||||
private boolean isVip = false;
|
||||
private final Cache cache;
|
||||
private final Cache tokenCache;
|
||||
private ScheduledExecutorService service;
|
||||
|
||||
|
||||
private AlertDialog dialog;
|
||||
private String serviceTicket;
|
||||
private UCTokenHandler qrCodeHandler;
|
||||
|
||||
private Map<String, String> getHeaders() {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36");
|
||||
headers.put("Referer", "https://drive.uc.cn");
|
||||
headers.put("Content-Type", "application/json");
|
||||
headers.put("Cookie", cookie);
|
||||
//headers.put("Host", "drive-pc.quark.cn");
|
||||
return headers;
|
||||
}
|
||||
|
||||
private Map<String, String> getWebHeaders() {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36");
|
||||
headers.put("Referer", "https://drive.uc.cn");
|
||||
headers.put("Cookie", cookie);
|
||||
return headers;
|
||||
}
|
||||
|
||||
/* cookieToken = qrCodeHandler.startUC_TOKENScan();
|
||||
SpiderDebug.log("扫码登录获取到的cookieToken: " + cookieToken);*/
|
||||
|
||||
|
||||
private UCApi() {
|
||||
Init.checkPermission();
|
||||
qrCodeHandler = new UCTokenHandler();
|
||||
cache = Cache.objectFrom(Path.read(getCache()));
|
||||
tokenCache = Cache.objectFrom(Path.read(qrCodeHandler.getCache()));
|
||||
|
||||
java.lang.String tokenCacheJson = tokenCache.getUser().getCookie();
|
||||
if (StringUtils.isNoneBlank(tokenCacheJson)) {
|
||||
|
||||
|
||||
//刷新token,并返回
|
||||
this.cookieToken = qrCodeHandler.refreshToken(Json.safeObject(tokenCacheJson).getAsJsonObject().get("refresh_token").getAsString());
|
||||
|
||||
SpiderDebug.log("UC初始化获取到的cookieToken: " + cookieToken);
|
||||
}
|
||||
SpiderDebug.log("UC初始化获取到的cookieToken: " + cookieToken);
|
||||
}
|
||||
|
||||
private static class Loader {
|
||||
static volatile UCApi INSTANCE = new UCApi();
|
||||
}
|
||||
|
||||
public static UCApi get() {
|
||||
return UCApi.Loader.INSTANCE;
|
||||
}
|
||||
|
||||
//从配置中获取cookie
|
||||
public void setCookie(String token) throws Exception {
|
||||
if (StringUtils.isNoneBlank(token)) {
|
||||
this.cookie = token;
|
||||
initUserInfo();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化UC信息
|
||||
*/
|
||||
private void initUserInfo() {
|
||||
try {
|
||||
SpiderDebug.log("uc initUserInfo...");
|
||||
|
||||
//extend没有cookie,从缓存中获取
|
||||
if (StringUtils.isAllBlank(cookie)) {
|
||||
SpiderDebug.log("uc cookie from ext is empty...");
|
||||
cookie = cache.getUser().getCookie();
|
||||
}
|
||||
//获取到cookie,初始化uc,并且把cookie缓存一次
|
||||
if (StringUtils.isNoneBlank(cookie) && cookie.contains("__pus")) {
|
||||
SpiderDebug.log(" initUc ...");
|
||||
initUc(this.cookie);
|
||||
cache.setUser(User.objectFrom(this.cookie));
|
||||
return;
|
||||
}
|
||||
|
||||
//没有cookie,也没有serviceTicket,抛出异常,提示用户重新登录
|
||||
if (StringUtils.isAllBlank(cookie) && StringUtils.isAllBlank(serviceTicket)) {
|
||||
SpiderDebug.log("uccookie为空");
|
||||
throw new RuntimeException("uccookie为空");
|
||||
}
|
||||
|
||||
String token = serviceTicket;
|
||||
OkResult result = OkHttp.get("https://drive.uc.cn/account/info?st=" + token + "", new HashMap<>(), getWebHeaders());
|
||||
Map json = Json.parseSafe(result.getBody(), Map.class);
|
||||
if (json.get("success").equals(Boolean.TRUE)) {
|
||||
List<String> cookies = result.getResp().get("set-Cookie");
|
||||
List<String> cookieList = new ArrayList<>();
|
||||
for (String cookie : cookies) {
|
||||
cookieList.add(cookie.split(";")[0]);
|
||||
}
|
||||
this.cookie += TextUtils.join(";", cookieList);
|
||||
|
||||
cache.setUser(User.objectFrom(this.cookie));
|
||||
if (cache.getUser().getCookie().isEmpty()) throw new Exception(this.cookie);
|
||||
initUc(this.cookie);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
cache.getUser().clean();
|
||||
e.printStackTrace();
|
||||
stopService();
|
||||
startFlow();
|
||||
} finally {
|
||||
while (cache.getUser().getCookie().isEmpty()) SystemClock.sleep(250);
|
||||
}
|
||||
}
|
||||
|
||||
public void initUc(String cookie) throws Exception {
|
||||
this.ckey = Util.MD5(cookie);
|
||||
this.cookie = cookie;
|
||||
this.isVip = getVip();
|
||||
}
|
||||
|
||||
|
||||
public File getCache() {
|
||||
return Path.tv("uc");
|
||||
}
|
||||
|
||||
|
||||
public Vod getVod(ShareData shareData) throws Exception {
|
||||
getShareToken(shareData);
|
||||
List<Item> files = new ArrayList<>();
|
||||
List<Item> subs = new ArrayList<>();
|
||||
List<Map<String, Object>> listData = listFile(1, shareData, files, subs, shareData.getShareId(), shareData.getFolderId(), 1);
|
||||
|
||||
List<String> playFrom = UCApi.get().getPlayFormatList();
|
||||
List<String> playFromtmp = new ArrayList<>();
|
||||
playFromtmp.add("uc原画");
|
||||
/* for (String s : playFrom) {
|
||||
playFromtmp.add("uc" + s);
|
||||
}*/
|
||||
List<String> playUrl = new ArrayList<>();
|
||||
|
||||
if (files.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < files.get(files.size() - 1).getShareIndex(); i++) {
|
||||
for (int index = 0; index < playFromtmp.size(); index++) {
|
||||
List<String> vodItems = new ArrayList<>();
|
||||
for (Item video_item : files) {
|
||||
if (video_item.getShareIndex() == i + 1) {
|
||||
vodItems.add(video_item.getEpisodeUrl("电影"));// + findSubs(video_item.getName(), subs));
|
||||
}
|
||||
}
|
||||
playUrl.add(TextUtils.join("#", vodItems));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId("");
|
||||
vod.setVodContent("");
|
||||
vod.setVodPic("");
|
||||
vod.setVodName("");
|
||||
vod.setVodPlayUrl(TextUtils.join("$$$", playUrl));
|
||||
vod.setVodPlayFrom(TextUtils.join("$$$", playFromtmp));
|
||||
vod.setTypeName("uc云盘");
|
||||
return vod;
|
||||
}
|
||||
|
||||
public String playerContent(String[] split, String flag) throws Exception {
|
||||
SpiderDebug.log("flag:" + flag);
|
||||
String fileId = split[0], fileToken = split[1], shareId = split[2], stoken = split[3];
|
||||
String playUrl = "";
|
||||
SpiderDebug.log("origin playUrl:" + playUrl);
|
||||
Map<String, String> header = getHeaders();
|
||||
header.remove("Host");
|
||||
header.remove("Content-Type");
|
||||
if (flag.contains("uc原画")) {
|
||||
playUrl = this.getDownload(shareId, stoken, fileId, fileToken, true);
|
||||
return Result.get().url(playUrl).string();
|
||||
} else {
|
||||
playUrl = this.getLiveTranscoding(shareId, stoken, fileId, fileToken, flag);
|
||||
return Result.get().url(proxyVideoUrl(playUrl, new HashMap<>())).string();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private boolean testVideo(String url) {
|
||||
|
||||
OkResult okResult1 = OkHttp.get(url, new HashMap<>(), Map.of("Range", "bytes=0-0"));
|
||||
return okResult1.getCode() == 206;
|
||||
|
||||
}
|
||||
|
||||
private String proxyVideoUrl(String url, Map<String, String> header) {
|
||||
return String.format(Proxy.getUrl() + "?do=uc&type=video&url=%s&header=%s", Util.base64Encode(url.getBytes(Charset.defaultCharset())), Util.base64Encode(Json.toJson(header).getBytes(Charset.defaultCharset())));
|
||||
}
|
||||
|
||||
public Object[] proxyVideo(Map<String, String> params) throws Exception {
|
||||
String url = Util.base64Decode(params.get("url"));
|
||||
SpiderDebug.log("proxy url :" + url);
|
||||
SpiderDebug.log("proxy header :" + Util.base64Decode(params.get("header")));
|
||||
Map header = new Gson().fromJson(Util.base64Decode(params.get("header")), Map.class);
|
||||
if (header == null) header = new HashMap<>();
|
||||
List<String> arr = List.of("Range", "Accept", "Accept-Encoding", "Accept-Language", "Cookie", "Origin", "Referer", "Sec-Ch-Ua", "Sec-Ch-Ua-Mobile", "Sec-Ch-Ua-Platform", "Sec-Fetch-Dest", "Sec-Fetch-Mode", "Sec-Fetch-Site", "User-Agent");
|
||||
for (String key : params.keySet()) {
|
||||
for (String s : arr) {
|
||||
if (s.toLowerCase().equals(key.toLowerCase())) {
|
||||
header.put(key, params.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (Util.getExt(url).contains("m3u8")) {
|
||||
return getM3u8(url, header);
|
||||
}
|
||||
return ProxyVideo.proxy(url, header);
|
||||
}
|
||||
|
||||
/**
|
||||
* 代理m3u8
|
||||
*
|
||||
* @param url
|
||||
* @param header
|
||||
* @return
|
||||
*/
|
||||
private Object[] getM3u8(String url, Map header) {
|
||||
SpiderDebug.log("m3u8 url :" + url);
|
||||
OkResult result = OkHttp.get(url, new HashMap<>(), header);
|
||||
String[] m3u8Arr = result.getBody().split("\n");
|
||||
List<String> listM3u8 = new ArrayList<>();
|
||||
|
||||
String site = url.substring(0, url.lastIndexOf("/")) + "/";
|
||||
int mediaId = 0;
|
||||
for (String oneLine : m3u8Arr) {
|
||||
String thisOne = oneLine;
|
||||
|
||||
if (oneLine.contains(".ts")) {
|
||||
mediaId++;
|
||||
thisOne = proxyVideoUrl(site + thisOne, header);
|
||||
SpiderDebug.log("m3u8 line " + mediaId + ":" + oneLine);
|
||||
SpiderDebug.log("m3u8 proxyed line " + mediaId + " :" + thisOne);
|
||||
|
||||
}
|
||||
listM3u8.add(thisOne);
|
||||
}
|
||||
String m3u8Str = TextUtils.join("\n", listM3u8);
|
||||
String contentType = result.getResp().get("Content-Type").get(0);
|
||||
|
||||
Map<String, String> respHeaders = new HashMap<>();
|
||||
// respHeaders.put("Access-Control-Allow-Origin","*");
|
||||
// respHeaders.put("Access-Control-Allow-Credentials","true");
|
||||
for (String key : result.getResp().keySet()) {
|
||||
respHeaders.put(key, result.getResp().get(key).get(0));
|
||||
}
|
||||
return new Object[]{result.getCode(), contentType, new ByteArrayInputStream(m3u8Str.getBytes(Charset.defaultCharset())), respHeaders};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param url
|
||||
* @param params get 参数
|
||||
* @param data post json
|
||||
* @param retry
|
||||
* @param method
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private String api(String url, Map<String, String> params, Map<String, Object> data, Integer retry, String method) throws Exception {
|
||||
|
||||
|
||||
int leftRetry = retry != null ? retry : 3;
|
||||
if (StringUtils.isAllBlank(cookie)) {
|
||||
this.initUserInfo();
|
||||
return api(url, params, data, leftRetry - 1, method);
|
||||
}
|
||||
OkResult okResult;
|
||||
if ("GET".equals(method)) {
|
||||
okResult = OkHttp.get(this.apiUrl + url, params, getHeaders());
|
||||
} else {
|
||||
okResult = OkHttp.post(this.apiUrl + url, Json.toJson(data), getHeaders());
|
||||
}
|
||||
if (okResult.getResp().get("Set-Cookie") != null) {
|
||||
Matcher matcher = Pattern.compile("__puus=([^;]+)").matcher(StringUtils.join(okResult.getResp().get("Set-Cookie"), ";;;"));
|
||||
if (matcher.find()) {
|
||||
Matcher cookieMatcher = Pattern.compile("__puus=([^;]+)").matcher(this.cookie);
|
||||
if (cookieMatcher.find() && !cookieMatcher.group(1).equals(matcher.group(1))) {
|
||||
this.cookie = this.cookie.replaceAll("__puus=[^;]+", "__puus=" + matcher.group(1));
|
||||
} else {
|
||||
this.cookie = this.cookie + ";__puus=" + matcher.group(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (okResult.getCode() != 200 && leftRetry > 0) {
|
||||
SpiderDebug.log("api error code:" + okResult.getCode());
|
||||
Thread.sleep(1000);
|
||||
return api(url, params, data, leftRetry - 1, method);
|
||||
}
|
||||
return okResult.getBody();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取二维码登录的令牌
|
||||
*
|
||||
* @return 返回包含二维码登录令牌的字符串
|
||||
*/
|
||||
private String getTokenForQrcodeLogin() {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("client_id", "381");
|
||||
params.put("v", "1.2");
|
||||
params.put("request_id", UUID.randomUUID().toString());
|
||||
OkResult res = OkHttp.post("https://api.open.uc.cn/cas/ajax/getTokenForQrcodeLogin?__dt=" + RandomUtils.nextInt(1000, 100000) + "&__t=" + new Date().getTime(), params, new HashMap<>());
|
||||
if (this.cookie.isEmpty()) {
|
||||
List<String> cookies = res.getResp().get("set-Cookie");
|
||||
List<String> cookieList = new ArrayList<>();
|
||||
for (String cookie : cookies) {
|
||||
cookieList.add(cookie.split(";")[0]);
|
||||
}
|
||||
this.cookie = TextUtils.join(";", cookieList);
|
||||
}
|
||||
Map<String, Object> json = Json.parseSafe(res.getBody(), Map.class);
|
||||
if (Objects.equals(json.get("message"), "ok")) {
|
||||
return (String) ((Map<String, Object>) ((Map<String, Object>) json.get("data")).get("members")).get("token");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取二维码内容
|
||||
* <p>
|
||||
* 此方法用于生成二维码的URL内容该URL用于二维码登录,包含了登录所需的token和客户端信息
|
||||
*
|
||||
* @return 返回包含token的二维码URL字符串
|
||||
*/
|
||||
private String getQrCodeToken() {
|
||||
// 获取用于二维码登录的token
|
||||
String token = getTokenForQrcodeLogin();
|
||||
// 组装二维码URL,包含token和客户端标识
|
||||
return token;
|
||||
}
|
||||
|
||||
private void startFlow() {
|
||||
Init.run(this::showInput);
|
||||
}
|
||||
|
||||
private void showInput() {
|
||||
try {
|
||||
int margin = ResUtil.dp2px(16);
|
||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
FrameLayout frame = new FrameLayout(Init.context());
|
||||
params.setMargins(margin, margin, margin, margin);
|
||||
EditText input = new EditText(Init.context());
|
||||
frame.addView(input, params);
|
||||
dialog = new AlertDialog.Builder(Init.getActivity()).setTitle("请输入UC cookie").setView(frame).setNeutralButton("UC二维码", (dialog, which) -> onNeutral()).setNegativeButton(android.R.string.cancel, null).setPositiveButton(android.R.string.ok, (dialog, which) -> onPositive(input.getText().toString())).show();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void onNeutral() {
|
||||
dismiss();
|
||||
Init.execute(this::getQRCode);
|
||||
}
|
||||
|
||||
private void onPositive(String text) {
|
||||
dismiss();
|
||||
Init.execute(() -> {
|
||||
if (text.startsWith("http")) setToken(OkHttp.string(text));
|
||||
else setToken(text);
|
||||
});
|
||||
}
|
||||
|
||||
private void getQRCode() {
|
||||
String token = getQrCodeToken();
|
||||
|
||||
Init.run(() -> openApp(token));
|
||||
}
|
||||
|
||||
private void openApp(String token) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setClassName("com.alicloud.databox", "com.taobao.login4android.scan.QrScanActivity");
|
||||
intent.putExtra("key_scanParam", token);
|
||||
Init.getActivity().startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
showQRCode("https://su.uc.cn/1_n0ZCv?uc_param_str=dsdnfrpfbivesscpgimibtbmnijblauputogpintnwktprchmt&token=" + token + "&client_id=381&uc_biz_str=S%3Acustom%7CC%3Atitlebar_fix");
|
||||
} finally {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("token", token);
|
||||
Init.execute(() -> startService(map));
|
||||
}
|
||||
}
|
||||
|
||||
private void showQRCode(String content) {
|
||||
try {
|
||||
int size = ResUtil.dp2px(240);
|
||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(size, size);
|
||||
ImageView image = new ImageView(Init.context());
|
||||
image.setScaleType(ImageView.ScaleType.CENTER_CROP);
|
||||
image.setImageBitmap(QRCode.getBitmap(content, size, 2));
|
||||
FrameLayout frame = new FrameLayout(Init.context());
|
||||
params.gravity = Gravity.CENTER;
|
||||
frame.addView(image, params);
|
||||
dialog = new AlertDialog.Builder(Init.getActivity()).setView(frame).setOnCancelListener(this::dismiss).setOnDismissListener(this::dismiss).show();
|
||||
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
Notify.show("请使用uc网盘App扫描二维码");
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void startService(Map<String, String> params) {
|
||||
SpiderDebug.log("----startservice");
|
||||
params.put("client_id", "381");
|
||||
params.put("v", "1.2");
|
||||
params.put("request_id", UUID.randomUUID().toString());
|
||||
service = Executors.newScheduledThreadPool(1);
|
||||
|
||||
service.scheduleWithFixedDelay(() -> {
|
||||
SpiderDebug.log("----scheduleAtFixedRate" + new Date().toString());
|
||||
String result = OkHttp.string("https://api.open.uc.cn/cas/ajax/getServiceTicketByQrcodeToken?__dt=" + RandomUtils.nextInt(1000, 100000) + "&__t=" + new Date().getTime(), params, getWebHeaders());
|
||||
Map<String, Object> json = Json.parseSafe(result, Map.class);
|
||||
if (json.get("status").equals(new Double(2000000))) {
|
||||
setToken((String) ((Map<String, Object>) ((Map<String, Object>) json.get("data")).get("members")).get("service_ticket"));
|
||||
|
||||
}
|
||||
|
||||
}, 1, 3, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void setToken(String value) {
|
||||
this.serviceTicket = value;
|
||||
SpiderDebug.log("ServiceTicket:" + value);
|
||||
Notify.show("ServiceTicket:" + value);
|
||||
initUserInfo();
|
||||
stopService();
|
||||
}
|
||||
|
||||
private void stopService() {
|
||||
if (service != null) service.shutdownNow();
|
||||
|
||||
|
||||
Init.run(this::dismiss);
|
||||
}
|
||||
|
||||
private void dismiss(DialogInterface dialog) {
|
||||
stopService();
|
||||
}
|
||||
|
||||
private void dismiss() {
|
||||
try {
|
||||
if (dialog != null) dialog.dismiss();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getVip() throws Exception {
|
||||
Map<String, Object> listData = Json.parseSafe(api("member?pr=ucpro&fr=pc&uc_param_str=&fetch_subscribe=true&_ch=home&fetch_identity=true", null, null, 0, "GET"), Map.class);
|
||||
return false;//((Map<String, String>) listData.get("data")).get("member_type").contains("VIP");
|
||||
}
|
||||
|
||||
public List<String> getPlayFormatList() {
|
||||
if (this.isVip) {
|
||||
return Arrays.asList("4K", "超清", "高清", "普画");
|
||||
} else {
|
||||
return Collections.singletonList("普画");
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getPlayFormatUcList() {
|
||||
if (this.isVip) {
|
||||
return Arrays.asList("4k", "2k", "super", "high", "normal", "low");
|
||||
} else {
|
||||
return Collections.singletonList("low");
|
||||
}
|
||||
}
|
||||
|
||||
public ShareData getShareData(String url) {
|
||||
Pattern pattern = Pattern.compile("https://drive\\.uc\\.cn/s/([^?]+)");
|
||||
Matcher matcher = pattern.matcher(url);
|
||||
if (matcher.find()) {
|
||||
return new ShareData(matcher.group(1), "0");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private void getShareToken(ShareData shareData) throws Exception {
|
||||
if (!this.shareTokenCache.containsKey(shareData.getShareId())) {
|
||||
this.shareTokenCache.remove(shareData.getShareId());
|
||||
Map<String, Object> shareToken = Json.parseSafe(api("share/sharepage/token?" + this.pr, Collections.emptyMap(), Map.of("pwd_id", shareData.getShareId(), "passcode", shareData.getSharePwd() == null ? "" : shareData.getSharePwd()), 0, "POST"), Map.class);
|
||||
if (shareToken.containsKey("data") && ((Map<String, Object>) shareToken.get("data")).containsKey("stoken")) {
|
||||
this.shareTokenCache.put(shareData.getShareId(), (Map<String, Object>) shareToken.get("data"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> listFile(int shareIndex, ShareData shareData, List<Item> videos, List<Item> subtitles, String shareId, String folderId, Integer page) throws Exception {
|
||||
int prePage = 200;
|
||||
page = page != null ? page : 1;
|
||||
|
||||
Map<String, Object> listData = Json.parseSafe(api("share/sharepage/detail?" + this.pr + "&pwd_id=" + shareId + "&stoken=" + encodeURIComponent((String) this.shareTokenCache.get(shareId).get("stoken")) + "&pdir_fid=" + folderId + "&force=0&_page=" + page + "&_size=" + prePage + "&_sort=file_type:asc,file_name:asc", Collections.emptyMap(), Collections.emptyMap(), 0, "GET"), Map.class);
|
||||
if (listData.get("data") == null) return Collections.emptyList();
|
||||
List<Map<String, Object>> items = (List<Map<String, Object>>) ((Map<String, Object>) listData.get("data")).get("list");
|
||||
if (items == null) return Collections.emptyList();
|
||||
List<Map<String, Object>> subDir = new ArrayList<>();
|
||||
for (Map<String, Object> item : items) {
|
||||
if (Boolean.TRUE.equals(item.get("dir"))) {
|
||||
subDir.add(item);
|
||||
} else if (Boolean.TRUE.equals(item.get("file")) && "video".equals(item.get("obj_category"))) {
|
||||
if ((Double) item.get("size") < 1024 * 1024 * 5) continue;
|
||||
item.put("stoken", this.shareTokenCache.get(shareData.getShareId()).get("stoken"));
|
||||
videos.add(Item.objectFrom(item, shareData.getShareId(), shareIndex));
|
||||
} else if ("file".equals(item.get("type")) && this.subtitleExts.contains("." + Util.getExt((String) item.get("file_name")))) {
|
||||
subtitles.add(Item.objectFrom(item, shareData.getShareId(), shareIndex));
|
||||
}
|
||||
}
|
||||
if (page < Math.ceil((double) ((Map<String, Object>) listData.get("metadata")).get("_total") / prePage)) {
|
||||
List<Map<String, Object>> nextItems = listFile(shareIndex, shareData, videos, subtitles, shareId, folderId, page + 1);
|
||||
items.addAll(nextItems);
|
||||
}
|
||||
for (Map<String, Object> dir : subDir) {
|
||||
List<Map<String, Object>> subItems = listFile(shareIndex, shareData, videos, subtitles, shareId, dir.get("fid").toString(), null);
|
||||
items.addAll(subItems);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
private Map<String, Object> findBestLCS(Item mainItem, List<Item> targetItems) {
|
||||
List<Map<String, Object>> results = new ArrayList<>();
|
||||
int bestMatchIndex = 0;
|
||||
for (int i = 0; i < targetItems.size(); i++) {
|
||||
Util.LCSResult currentLCS = Util.lcs(mainItem.getName(), targetItems.get(i).getName());
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("target", targetItems.get(i));
|
||||
result.put("lcs", currentLCS);
|
||||
results.add(result);
|
||||
if (currentLCS.length > results.get(bestMatchIndex).get("lcs").toString().length()) {
|
||||
bestMatchIndex = i;
|
||||
}
|
||||
}
|
||||
Map<String, Object> bestMatch = results.get(bestMatchIndex);
|
||||
Map<String, Object> finalResult = new HashMap<>();
|
||||
finalResult.put("allLCS", results);
|
||||
finalResult.put("bestMatch", bestMatch);
|
||||
finalResult.put("bestMatchIndex", bestMatchIndex);
|
||||
return finalResult;
|
||||
}
|
||||
|
||||
public void getFilesByShareUrl(int shareIndex, String shareInfo, List<Item> videos, List<Item> subtitles) throws Exception {
|
||||
ShareData shareData = getShareData((String) shareInfo);
|
||||
if (shareData == null) return;
|
||||
getShareToken(shareData);
|
||||
if (!this.shareTokenCache.containsKey(shareData.getShareId())) return;
|
||||
listFile(shareIndex, shareData, videos, subtitles, shareData.getShareId(), shareData.getFolderId(), 1);
|
||||
if (!subtitles.isEmpty()) {
|
||||
for (Item video : videos) {
|
||||
Map<String, Object> matchSubtitle = findBestLCS(video, subtitles);
|
||||
if (matchSubtitle.get("bestMatch") != null) {
|
||||
video.setSubtitle((String) ((Map<String, Object>) matchSubtitle.get("bestMatch")).get("target"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void clean() {
|
||||
saveFileIdCaches.clear();
|
||||
}
|
||||
|
||||
private void clearSaveDir() throws Exception {
|
||||
|
||||
Map<String, Object> listData = Json.parseSafe(api("file/sort?" + this.pr + "&pdir_fid=" + this.saveDirId + "&_page=1&_size=200&_sort=file_type:asc,updated_at:desc", Collections.emptyMap(), Collections.emptyMap(), 0, "GET"), Map.class);
|
||||
if (listData.get("data") != null && ((List<Map<String, Object>>) ((Map<String, Object>) listData.get("data")).get("list")).size() > 0) {
|
||||
List<String> list = new ArrayList<>();
|
||||
for (Map<String, Object> stringStringMap : ((List<Map<String, Object>>) ((Map<String, Object>) listData.get("data")).get("list"))) {
|
||||
list.add((String) stringStringMap.get("fid"));
|
||||
}
|
||||
api("file/delete?" + this.pr, Collections.emptyMap(), Map.of("action_type", "2", "filelist", Json.toJson(list), "exclude_fids", ""), 0, "POST");
|
||||
}
|
||||
}
|
||||
|
||||
private void createSaveDir(boolean clean) throws Exception {
|
||||
if (this.saveDirId != null) {
|
||||
if (clean) clearSaveDir();
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> listData = Json.parseSafe(api("file/sort?" + this.pr + "&pdir_fid=0&_page=1&_size=200&_sort=file_type:asc,updated_at:desc", Collections.emptyMap(), Collections.emptyMap(), 0, "GET"), Map.class);
|
||||
if (listData.get("data") != null) {
|
||||
for (Map<String, Object> item : (List<Map<String, Object>>) ((Map<String, Object>) listData.get("data")).get("list")) {
|
||||
if (this.saveDirName.equals(item.get("file_name"))) {
|
||||
this.saveDirId = item.get("fid").toString();
|
||||
clearSaveDir();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.saveDirId == null) {
|
||||
Map<String, Object> create = Json.parseSafe(api("file?" + this.pr, Collections.emptyMap(), Map.of("pdir_fid", "0", "file_name", this.saveDirName, "dir_path", "", "dir_init_lock", "false"), 0, "POST"), Map.class);
|
||||
if (create.get("data") != null && ((Map<String, Object>) create.get("data")).get("fid") != null) {
|
||||
this.saveDirId = ((Map<String, Object>) create.get("data")).get("fid").toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String save(String shareId, String stoken, String fileId, String fileToken, boolean clean) throws Exception {
|
||||
createSaveDir(clean);
|
||||
if (clean) {
|
||||
clean();
|
||||
}
|
||||
if (this.saveDirId == null) return null;
|
||||
if (stoken == null) {
|
||||
getShareToken(new ShareData(shareId, null));
|
||||
if (!this.shareTokenCache.containsKey(shareId)) return null;
|
||||
}
|
||||
|
||||
Map<String, Object> saveResult = Json.parseSafe(api("share/sharepage/save?" + this.pr, null, Map.of("fid_list", List.of(fileId), "fid_token_list", List.of(fileToken), "to_pdir_fid", this.saveDirId, "pwd_id", shareId, "stoken", stoken != null ? stoken : (String) this.shareTokenCache.get(shareId).get("stoken"), "pdir_fid", "0", "scene", "link"), 0, "POST"), Map.class);
|
||||
if (saveResult.get("data") != null && ((Map<Object, Object>) saveResult.get("data")).get("task_id") != null) {
|
||||
int retry = 0;
|
||||
while (true) {
|
||||
|
||||
Map<String, Object> taskResult = Json.parseSafe(api("task?" + this.pr + "&task_id=" + ((Map<String, Object>) saveResult.get("data")).get("task_id") + "&retry_index=" + retry, Collections.emptyMap(), Collections.emptyMap(), 0, "GET"), Map.class);
|
||||
if (taskResult.get("data") != null && ((Map<Object, Object>) taskResult.get("data")).get("save_as") != null && ((Map<Object, Object>) ((Map<Object, Object>) taskResult.get("data")).get("save_as")).get("save_as_top_fids") != null && ((List<String>) ((Map<String, Object>) ((Map<String, Object>) taskResult.get("data")).get("save_as")).get("save_as_top_fids")).size() > 0) {
|
||||
return ((List<String>) ((Map<String, Object>) ((Map<Object, Object>) taskResult.get("data")).get("save_as")).get("save_as_top_fids")).get(0);
|
||||
}
|
||||
retry++;
|
||||
if (retry > 2) break;
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getLiveTranscoding(String shareId, String stoken, String fileId, String fileToken, String flag) throws Exception {
|
||||
if (!this.saveFileIdCaches.containsKey(fileId)) {
|
||||
String saveFileId = save(shareId, stoken, fileId, fileToken, true);
|
||||
if (saveFileId == null) return null;
|
||||
this.saveFileIdCaches.put(fileId, saveFileId);
|
||||
}
|
||||
|
||||
Map<String, Object> transcoding = Json.parseSafe(api("file/v2/play?" + this.pr, Collections.emptyMap(), Map.of("fid", this.saveFileIdCaches.get(fileId), "resolutions", "normal,low,high,super,2k,4k", "supports", "fmp4"), 0, "POST"), Map.class);
|
||||
if (transcoding.get("data") != null && ((Map<Object, Object>) transcoding.get("data")).get("video_list") != null) {
|
||||
String flagId = flag.split("-")[flag.split("-").length - 1];
|
||||
int index = Util.findAllIndexes(getPlayFormatList(), flagId);
|
||||
String ucFormat = getPlayFormatUcList().get(index);
|
||||
for (Map<String, Object> video : (List<Map<String, Object>>) ((Map<Object, Object>) transcoding.get("data")).get("video_list")) {
|
||||
if (video.get("resolution").equals(ucFormat)) {
|
||||
return (String) ((Map<String, Object>) video.get("video_info")).get("url");
|
||||
}
|
||||
}
|
||||
return (String) ((Map<String, Object>) ((List<Map<String, Object>>) ((Map<Object, Object>) transcoding.get("data")).get("video_list")).get(index).get("video_info")).get("url");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getDownload(String shareId, String stoken, String fileId, String fileToken, boolean clean) throws Exception {
|
||||
if (!this.saveFileIdCaches.containsKey(fileId)) {
|
||||
String saveFileId = save(shareId, stoken, fileId, fileToken, clean);
|
||||
if (saveFileId == null) return null;
|
||||
this.saveFileIdCaches.put(fileId, saveFileId);
|
||||
}
|
||||
|
||||
//token不为空
|
||||
if (StringUtils.isNoneBlank(cookieToken)) {
|
||||
SpiderDebug.log("cookieToken不为空: " + cookieToken + ";开始下载");
|
||||
return qrCodeHandler.download(cookieToken, this.saveFileIdCaches.get(fileId));
|
||||
} else {
|
||||
Map<String, Object> down = Json.parseSafe(api("file/download?" + this.pr + "&uc_param_str=", Collections.emptyMap(), Map.of("fids", List.of(this.saveFileIdCaches.get(fileId))), 0, "POST"), Map.class);
|
||||
if (down.get("data") != null) {
|
||||
return ((List<Map<String, Object>>) down.get("data")).get(0).get("download_url").toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Helper method to convert bytes to hex string
|
||||
private String bytesToHex(byte[] bytes) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
sb.append(String.format("%02x", b));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// Encoding helper method
|
||||
private String encodeURIComponent(String value) {
|
||||
try {
|
||||
return java.net.URLEncoder.encode(value, "UTF-8");
|
||||
} catch (Exception e) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,383 +0,0 @@
|
|||
package com.github.catvod.api;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.view.Gravity;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import com.github.catvod.bean.uc.Cache;
|
||||
import com.github.catvod.bean.uc.User;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.net.OkResult;
|
||||
import com.github.catvod.spider.Init;
|
||||
import com.github.catvod.utils.*;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class UCTokenHandler {
|
||||
private static final String CLIENT_ID = "5acf882d27b74502b7040b0c65519aa7";
|
||||
private static final String SIGN_KEY = "l3srvtd7p42l0d0x1u8d7yc8ye9kki4d";
|
||||
private static final String API_URL = "https://open-api-drive.uc.cn";
|
||||
private static final String CODE_API_URL = "http://api.extscreen.com/ucdrive";
|
||||
|
||||
|
||||
private Map<String, Object> platformStates = new HashMap<>();
|
||||
private Map<String, String> addition = new HashMap<>();
|
||||
private Map<String, String> conf = new HashMap<>();
|
||||
|
||||
|
||||
private ScheduledExecutorService service;
|
||||
private AlertDialog dialog;
|
||||
private final Cache cache;
|
||||
|
||||
public File getCache() {
|
||||
return Path.tv("uctoken");
|
||||
}
|
||||
|
||||
public UCTokenHandler() {
|
||||
addition.put("DeviceID", "07b48aaba8a739356ab8107b5e230ad4");
|
||||
conf.put("api", API_URL);
|
||||
conf.put("clientID", CLIENT_ID);
|
||||
conf.put("signKey", SIGN_KEY);
|
||||
conf.put("appVer", "1.6.8");
|
||||
conf.put("channel", "UCTVOFFICIALWEB");
|
||||
conf.put("codeApi", CODE_API_URL);
|
||||
cache = Cache.objectFrom(Path.read(getCache()));
|
||||
}
|
||||
|
||||
private String generateUUID() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
private String generateDeviceID(String timestamp) {
|
||||
|
||||
return Util.MD5(timestamp).substring(0, 16);
|
||||
}
|
||||
|
||||
private String generateReqId(String deviceID, String timestamp) {
|
||||
|
||||
return Util.MD5(deviceID + timestamp).substring(0, 16);
|
||||
}
|
||||
|
||||
private String generateXPanToken(String method, String pathname, String timestamp, String key) {
|
||||
|
||||
return Util.sha256Hex(method + "&" + pathname + "&" + timestamp + "&" + key);
|
||||
}
|
||||
|
||||
public String startUC_TOKENScan() throws Exception {
|
||||
String pathname = "/oauth/authorize";
|
||||
String timestamp = String.valueOf(new Date().getTime() / 1000 + 1) + "000";
|
||||
String deviceID = StringUtils.isNoneBlank((String) addition.get("DeviceID")) ? (String) addition.get("DeviceID") : generateDeviceID(timestamp);
|
||||
String reqId = generateReqId(deviceID, timestamp);
|
||||
String token = generateXPanToken("GET", pathname, timestamp, (String) conf.get("signKey"));
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Accept", "application/json, text/plain, */*");
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Linux; U; Android 13; zh-cn; M2004J7AC Build/UKQ1.231108.001) AppleWebKit/533.1 (KHTML, like Gecko) Mobile Safari/533.1");
|
||||
headers.put("x-pan-tm", timestamp);
|
||||
headers.put("x-pan-token", token);
|
||||
headers.put("x-pan-client-id", (String) conf.get("clientID"));
|
||||
headers.put("Host", "open-api-drive.uc.cn");
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("req_id", reqId);
|
||||
params.put("access_token", StringUtils.isNoneBlank((String) addition.get("AccessToken")) ? (String) addition.get("AccessToken") : "");
|
||||
params.put("app_ver", (String) conf.get("appVer"));
|
||||
params.put("device_id", deviceID);
|
||||
params.put("device_brand", "Xiaomi");
|
||||
params.put("platform", "tv");
|
||||
params.put("device_name", "M2004J7AC");
|
||||
params.put("device_model", "M2004J7AC");
|
||||
params.put("build_device", "M2004J7AC");
|
||||
params.put("build_product", "M2004J7AC");
|
||||
params.put("device_gpu", "Adreno (TM) 550");
|
||||
params.put("activity_rect", URLEncoder.encode("{}", "UTF-8"));
|
||||
params.put("channel", (String) conf.get("channel"));
|
||||
params.put("auth_type", "code");
|
||||
params.put("client_id", (String) conf.get("clientID"));
|
||||
params.put("scope", "netdisk");
|
||||
params.put("qrcode", "1");
|
||||
params.put("qr_width", "460");
|
||||
params.put("qr_height", "460");
|
||||
OkResult okResult = OkHttp.get(API_URL + pathname, params, headers);
|
||||
|
||||
|
||||
JsonObject resData = Json.safeObject(okResult.getBody());
|
||||
String queryToken = resData.get("query_token").getAsString();
|
||||
String qrCode = resData.get("qr_data").getAsString();
|
||||
|
||||
platformStates.put("UC_TOKEN", new HashMap<String, String>() {{
|
||||
put("query_token", queryToken);
|
||||
put("request_id", reqId);
|
||||
}});
|
||||
Init.run(() -> showQRCode(qrCode));
|
||||
|
||||
Init.execute(this::startService);
|
||||
/*Map<String, Object> result = new HashMap<>();
|
||||
result.put("qrcode", "data:image/png;base64," + qrCode);
|
||||
result.put("status", "NEW");*/
|
||||
return qrCode;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public Map<String, Object> checkUC_TOKENStatus() throws UnsupportedEncodingException {
|
||||
Map<String, String> state = (Map<String, String>) platformStates.get("UC_TOKEN");
|
||||
if (state == null) {
|
||||
return Map.of("status", "EXPIRED");
|
||||
}
|
||||
|
||||
String pathname = "/oauth/code";
|
||||
String timestamp = String.valueOf(new Date().getTime() / 1000 + 1) + "000";
|
||||
String deviceID = StringUtils.isAllBlank((String) addition.get("DeviceID")) ? (String) addition.get("DeviceID") : generateDeviceID(timestamp);
|
||||
String reqId = generateReqId(deviceID, timestamp);
|
||||
String xPanToken = generateXPanToken("GET", pathname, timestamp, (String) conf.get("signKey"));
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Accept", "application/json, text/plain, */*");
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Linux; U; Android 13; zh-cn; M2004J7AC Build/UKQ1.231108.001) AppleWebKit/533.1 (KHTML, like Gecko) Mobile Safari/533.1");
|
||||
headers.put("x-pan-tm", timestamp);
|
||||
headers.put("x-pan-token", xPanToken);
|
||||
headers.put("x-pan-client-id", (String) conf.get("clientID"));
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("req_id", reqId);
|
||||
params.put("access_token", (String) addition.get("AccessToken"));
|
||||
params.put("app_ver", (String) conf.get("appVer"));
|
||||
params.put("device_id", deviceID);
|
||||
params.put("device_brand", "Xiaomi");
|
||||
params.put("platform", "tv");
|
||||
params.put("device_name", "M2004J7AC");
|
||||
params.put("device_model", "M2004J7AC");
|
||||
params.put("build_device", "M2004J7AC");
|
||||
params.put("build_product", "M2004J7AC");
|
||||
params.put("device_gpu", "Adreno (TM) 550");
|
||||
params.put("activity_rect", URLEncoder.encode("{}", "UTF-8"));
|
||||
params.put("channel", (String) conf.get("channel"));
|
||||
params.put("client_id", (String) conf.get("clientID"));
|
||||
params.put("scope", "netdisk");
|
||||
params.put("query_token", state.get("query_token"));
|
||||
|
||||
OkResult okResult = OkHttp.get(API_URL + pathname, params, headers);
|
||||
|
||||
//扫码成功
|
||||
if (okResult.getCode() == 200) {
|
||||
JsonObject resData = Json.safeObject(okResult.getBody());
|
||||
String code = resData.get("code").getAsString();
|
||||
|
||||
OkResult okResult1 = getAccessToken(code, false);
|
||||
|
||||
|
||||
if (okResult1.getCode() == 200) {
|
||||
JsonObject tokenResData = Json.safeObject(okResult1.getBody());
|
||||
platformStates.remove("UC_TOKEN");
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("status", "CONFIRMED");
|
||||
result.put("cookie", tokenResData.get("data").getAsJsonObject().get("access_token").getAsString());
|
||||
SpiderDebug.log("uc Token获取成功:" + tokenResData.get("data").getAsJsonObject().get("access_token").getAsString());
|
||||
|
||||
//保存到本地
|
||||
cache.setTokenUser(User.objectFrom(Json.toJson(tokenResData.get("data").getAsJsonObject())));
|
||||
//停止检验线程,关闭弹窗
|
||||
stopService();
|
||||
return result;
|
||||
}
|
||||
|
||||
} else if (okResult.getCode() == 400) {
|
||||
SpiderDebug.log("uc Token获取失败:" + okResult.getBody());
|
||||
|
||||
return Map.of("status", "NEW");
|
||||
|
||||
}
|
||||
|
||||
|
||||
platformStates.remove("UC_TOKEN");
|
||||
return Map.of("status", "EXPIRED");
|
||||
}
|
||||
/**
|
||||
* 获取访问令牌或者刷新令牌
|
||||
*
|
||||
* @param code
|
||||
* @param refresh 是否刷新,如果是,code为refresh_token
|
||||
* @return
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public OkResult getAccessToken(String code, boolean refresh) {
|
||||
|
||||
String timestamp = String.valueOf(new Date().getTime() / 1000 + 1) + "000";
|
||||
String deviceID = StringUtils.isAllBlank((String) addition.get("DeviceID")) ? (String) addition.get("DeviceID") : generateDeviceID(timestamp);
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Accept", "application/json, text/plain, */*");
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Linux; U; Android 13; zh-cn; M2004J7AC Build/UKQ1.231108.001) AppleWebKit/533.1 (KHTML, like Gecko) Mobile Safari/533.1");
|
||||
|
||||
String pathname = "/token";
|
||||
String reqId = generateReqId(deviceID, timestamp);
|
||||
|
||||
Map<String, String> postData = new HashMap<>();
|
||||
postData.put("req_id", reqId);
|
||||
postData.put("app_ver", (String) conf.get("appVer"));
|
||||
postData.put("device_id", deviceID);
|
||||
postData.put("device_brand", "Xiaomi");
|
||||
postData.put("platform", "tv");
|
||||
postData.put("device_name", "M2004J7AC");
|
||||
postData.put("device_model", "M2004J7AC");
|
||||
postData.put("build_device", "M2004J7AC");
|
||||
postData.put("build_product", "M2004J7AC");
|
||||
postData.put("device_gpu", "Adreno (TM) 550");
|
||||
try {
|
||||
postData.put("activity_rect", URLEncoder.encode("{}", "UTF-8"));
|
||||
} catch (Exception e) {
|
||||
|
||||
SpiderDebug.log("encode出错" + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
postData.put("channel", conf.get("channel"));
|
||||
if (refresh) {
|
||||
postData.put("refresh_token", code);
|
||||
SpiderDebug.log("开始刷新uc accesstoken");
|
||||
} else {
|
||||
postData.put("code", code);
|
||||
SpiderDebug.log("开始获取uc accesstoken");
|
||||
}
|
||||
|
||||
|
||||
return OkHttp.post(conf.get("codeApi") + pathname, Json.toJson(postData), headers);
|
||||
}
|
||||
/**
|
||||
* 刷新refresh token
|
||||
*
|
||||
* @param refreshToken 刷新token
|
||||
* @return 防火新的accesstoken
|
||||
*/
|
||||
public String refreshToken(String refreshToken) {
|
||||
OkResult okResult1 = this.getAccessToken(refreshToken, true);
|
||||
|
||||
if (okResult1.getCode() == 200) {
|
||||
JsonObject tokenResData = Json.safeObject(okResult1.getBody());
|
||||
SpiderDebug.log("uc Token刷新成功:" + tokenResData.get("data").getAsJsonObject().get("access_token").getAsString());
|
||||
//保存到本地
|
||||
cache.setTokenUser(User.objectFrom(Json.toJson(tokenResData.get("data").getAsJsonObject())));
|
||||
return tokenResData.get("data").getAsJsonObject().get("access_token").getAsString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public String download(String token, String saveFileId) throws Exception {
|
||||
SpiderDebug.log("开始下载:" + saveFileId + ";token:" + token);
|
||||
String pathname = "/file";
|
||||
String timestamp = String.valueOf(new Date().getTime() / 1000 + 1) + "000";
|
||||
String deviceID = StringUtils.isAllBlank((String) addition.get("DeviceID")) ? (String) addition.get("DeviceID") : generateDeviceID(timestamp);
|
||||
String reqId = generateReqId(deviceID, timestamp);
|
||||
String xPanToken = generateXPanToken("GET", pathname, timestamp, (String) conf.get("signKey"));
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
//headers.put("Accept-Encoding", "gzip");
|
||||
headers.put("content-type", "text/plain;charset=UTF-8");
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Linux; U; Android 13; zh-cn; M2004J7AC Build/UKQ1.231108.001) AppleWebKit/533.1 (KHTML, like Gecko) Mobile Safari/533.1");
|
||||
headers.put("x-pan-tm", timestamp);
|
||||
headers.put("x-pan-token", xPanToken);
|
||||
headers.put("x-pan-client-id", (String) conf.get("clientID"));
|
||||
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("req_id", reqId);
|
||||
params.put("access_token", token);
|
||||
params.put("app_ver", (String) conf.get("appVer"));
|
||||
params.put("device_id", deviceID);
|
||||
params.put("device_brand", "Xiaomi");
|
||||
params.put("platform", "tv");
|
||||
params.put("device_name", "M2004J7AC");
|
||||
params.put("device_model", "M2004J7AC");
|
||||
params.put("build_device", "M2004J7AC");
|
||||
params.put("build_product", "M2004J7AC");
|
||||
params.put("device_gpu", "Adreno (TM) 550");
|
||||
params.put("activity_rect", URLEncoder.encode("{}", "UTF-8"));
|
||||
params.put("channel", (String) conf.get("channel"));
|
||||
params.put("method", "streaming");
|
||||
params.put("group_by", "source");
|
||||
params.put("fid", saveFileId);
|
||||
params.put("resolution", "low,normal,high,super,2k,4k");
|
||||
params.put("support", "dolby_vision");
|
||||
|
||||
OkResult okResult1 = OkHttp.get(API_URL + pathname, params, headers);
|
||||
JsonObject obj = Json.safeObject(okResult1.getBody());
|
||||
if (okResult1.getCode() != 200) {
|
||||
Notify.show(obj.get("error_info").getAsString());
|
||||
SpiderDebug.log("uc TV 错误信息:" + obj.get("error_info").getAsString());
|
||||
return null;
|
||||
}
|
||||
String downloadUrl = obj.get("data").getAsJsonObject().get("video_info").getAsJsonArray().get(0).getAsJsonObject().get("url").getAsString();
|
||||
SpiderDebug.log("uc TV 下载文件内容:" + downloadUrl);
|
||||
return downloadUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示qrcode
|
||||
*
|
||||
* @param base64Str
|
||||
*/
|
||||
public void showQRCode(String base64Str) {
|
||||
try {
|
||||
int size = ResUtil.dp2px(240);
|
||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(size, size);
|
||||
ImageView image = new ImageView(Init.context());
|
||||
image.setScaleType(ImageView.ScaleType.CENTER_CROP);
|
||||
image.setImageBitmap(QRCode.base64StringToImage(base64Str));
|
||||
FrameLayout frame = new FrameLayout(Init.context());
|
||||
params.gravity = Gravity.CENTER;
|
||||
frame.addView(image, params);
|
||||
dialog = new AlertDialog.Builder(Init.getActivity()).setView(frame).setOnCancelListener(this::dismiss).setOnDismissListener(this::dismiss).show();
|
||||
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
Notify.show("请使用uc网盘App扫描二维码");
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void dismiss() {
|
||||
try {
|
||||
if (dialog != null) dialog.dismiss();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void dismiss(DialogInterface dialog) {
|
||||
stopService();
|
||||
}
|
||||
|
||||
private void stopService() {
|
||||
if (service != null) service.shutdownNow();
|
||||
Init.run(this::dismiss);
|
||||
}
|
||||
|
||||
public void startService() {
|
||||
SpiderDebug.log("----start UC token service");
|
||||
|
||||
service = Executors.newScheduledThreadPool(1);
|
||||
|
||||
service.scheduleWithFixedDelay(() -> {
|
||||
try {
|
||||
SpiderDebug.log("----checkUC_TOKENStatus中");
|
||||
|
||||
checkUC_TOKENStatus();
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}, 1, 3, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,315 +0,0 @@
|
|||
package com.github.catvod.api;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.net.OkResult;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.ProxyServer;
|
||||
import com.github.catvod.utils.ProxyVideo;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class YunDrive {
|
||||
private final Pattern regex = Pattern.compile("https://yun\\.139\\.com/shareweb/#/w/i/([^&]+)");
|
||||
private final SecretKeySpec secretKey;
|
||||
private final String baseUrl = "https://share-kd-njs.yun.139.com/yun-share/richlifeApp/devapp/IOutLink/";
|
||||
private final Map<String, String> baseHeaders = new HashMap<>();
|
||||
|
||||
private final Map<String, JsonObject> cache = new HashMap<>();
|
||||
|
||||
private static class Loader {
|
||||
static volatile YunDrive INSTANCE = new YunDrive();
|
||||
}
|
||||
|
||||
public static YunDrive get() {
|
||||
return Loader.INSTANCE;
|
||||
}
|
||||
|
||||
public YunDrive() {
|
||||
|
||||
this.secretKey = new SecretKeySpec("PVGDwmcvfs1uV3d1".getBytes(Charset.defaultCharset()), "AES");
|
||||
baseHeaders.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36");
|
||||
baseHeaders.put("Content-Type", "application/json");
|
||||
baseHeaders.put("hcy-cool-flag", "1");
|
||||
baseHeaders.put("x-deviceinfo", "||3|12.27.0|chrome|131.0.0.0|5c7c68368f048245e1ce47f1c0f8f2d0||windows 10|1536X695|zh-CN|||");
|
||||
|
||||
}
|
||||
|
||||
private String encrypt(String data) throws GeneralSecurityException {
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
|
||||
byte[] ivBytes = new byte[16];
|
||||
new SecureRandom().nextBytes(ivBytes);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(ivBytes));
|
||||
byte[] encrypted = cipher.doFinal(data.getBytes(Charset.defaultCharset()));
|
||||
byte[] combined = new byte[ivBytes.length + encrypted.length];
|
||||
System.arraycopy(ivBytes, 0, combined, 0, ivBytes.length);
|
||||
System.arraycopy(encrypted, 0, combined, ivBytes.length, encrypted.length);
|
||||
return Base64.encodeBase64String(combined);
|
||||
|
||||
}
|
||||
|
||||
private String decrypt(String data) throws GeneralSecurityException {
|
||||
byte[] combined = Base64.decodeBase64(data);
|
||||
byte[] ivBytes = Arrays.copyOfRange(combined, 0, 16);
|
||||
byte[] encrypted = Arrays.copyOfRange(combined, 16, combined.length);
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(ivBytes));
|
||||
return new String(cipher.doFinal(encrypted), Charset.defaultCharset());
|
||||
}
|
||||
|
||||
public String extractLinkID(String url) {
|
||||
String linkID = "";
|
||||
Matcher matcher = regex.matcher(url);
|
||||
boolean finded = matcher.find();
|
||||
if (!finded) {
|
||||
matcher = Pattern.compile("https://caiyun\\.139\\.com/m/i\\?([^&]+)").matcher(url);
|
||||
finded = matcher.find();
|
||||
}
|
||||
if (!finded) {
|
||||
matcher = Pattern.compile("https://yun.139.com/shareweb/#/w/i/([\\w-]+)").matcher(url);
|
||||
finded = matcher.find();
|
||||
}
|
||||
if (!finded) {
|
||||
matcher = Pattern.compile("https://caiyun.139.com/w/i/([\\w-]+)").matcher(url);
|
||||
finded = matcher.find();
|
||||
}
|
||||
|
||||
if (finded) linkID = matcher.group(1);
|
||||
return linkID;
|
||||
}
|
||||
|
||||
public JsonObject fetchShareInfo(String pCaID, String linkID) throws IOException, GeneralSecurityException {
|
||||
if (linkID.isEmpty()) throw new IllegalStateException("linkID not initialized");
|
||||
|
||||
String cacheKey = linkID + "-" + pCaID;
|
||||
if (cache.containsKey(cacheKey)) return cache.get(cacheKey);
|
||||
|
||||
Map<String, Object> requestBody = Map.of("getOutLinkInfoReq", Map.of("account", "", "linkID", linkID, "passwd", "", "caSrt", 1, "coSrt", 1, "srtDr", 0, "bNum", 1, "pCaID", pCaID, "eNum", 200), "commonAccountInfo", Map.of("account", "", "accountType", 1));
|
||||
|
||||
|
||||
OkResult okResult = OkHttp.post(baseUrl + "getOutLinkInfoV6", encrypt(Json.toJson(requestBody)), baseHeaders);
|
||||
JsonObject result = Json.safeObject(decrypt(okResult.getBody())).getAsJsonObject("data");
|
||||
cache.put(cacheKey, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<String, List<Map<String, String>>> processShareData(String url) throws Exception {
|
||||
if (url == null || url.isEmpty()) return Collections.emptyMap();
|
||||
|
||||
boolean isUrl = url.startsWith("http");
|
||||
String pCaID = isUrl ? "root" : url;
|
||||
String linkID = "";
|
||||
if (isUrl) linkID = extractLinkID(url);
|
||||
|
||||
List<Map<String, String>> fileList = fetchFileList(pCaID, linkID);
|
||||
Map<String, List<Map<String, String>>> result = new LinkedHashMap<>();
|
||||
|
||||
for (Map<String, String> item : fileList) {
|
||||
String name = item.get("name");
|
||||
List<Map<String, String>> subItems = fetchUrlList(item.get("path"), linkID);
|
||||
if (!subItems.isEmpty()) {
|
||||
|
||||
List<Map<String, String>> list = result.get(name);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
result.put(name, list);
|
||||
}
|
||||
list.addAll(subItems);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (result.isEmpty()) {
|
||||
List<Map<String, String>> rootItems = fetchFileList(url, linkID);
|
||||
List<Map<String, String>> filteredList = new ArrayList<>();
|
||||
for (Map<String, String> m : rootItems) {
|
||||
if (!m.isEmpty()) {
|
||||
filteredList.add(m);
|
||||
}
|
||||
}
|
||||
result.put("root", filteredList);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<Map<String, String>> fetchFileList(String pCaID, String linkID) throws Exception {
|
||||
if (pCaID == null) return Collections.emptyList();
|
||||
|
||||
String actualID = pCaID.startsWith("http") ? "root" : pCaID;
|
||||
JsonObject response = fetchShareInfo(actualID, linkID);
|
||||
if (!response.has("caLst")) return Collections.emptyList();
|
||||
|
||||
List<Map<String, String>> items = new ArrayList<>();
|
||||
Pattern filter = Pattern.compile("App|活动中心|免费|1T空间|免流");
|
||||
JsonElement array = response.get("caLst");
|
||||
if (!array.isJsonNull()) {
|
||||
for (JsonElement element : array.getAsJsonArray()) {
|
||||
JsonObject entry = element.getAsJsonObject();
|
||||
String name = entry.get("caName").getAsString();
|
||||
String path = entry.get("path").getAsString();
|
||||
|
||||
if (!filter.matcher(name).find()) {
|
||||
items.add(Map.of("name", name, "path", path));
|
||||
items.addAll(fetchFileList(path, linkID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private List<Map<String, String>> fetchUrlList(String pCaID, String linkID) throws Exception {
|
||||
JsonObject response = fetchShareInfo(pCaID, linkID);
|
||||
List<Map<String, String>> items = new ArrayList<>();
|
||||
|
||||
if (response.has("coLst")) {
|
||||
for (JsonElement element : response.getAsJsonArray("coLst")) {
|
||||
JsonObject entry = element.getAsJsonObject();
|
||||
if (entry.get("coType").getAsInt() == 3) {
|
||||
items.add(Map.of("name", entry.get("coName").getAsString(), "contentId", entry.get("coID").getAsString(), "linkID", linkID, "path", entry.get("path").getAsString()));
|
||||
}
|
||||
}
|
||||
} else if (response.has("caLst")) {
|
||||
for (JsonElement element : response.getAsJsonArray("caLst")) {
|
||||
items.addAll(fetchUrlList(element.getAsJsonObject().get("path").getAsString(), linkID));
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
public String fetchPlayUrl(String contentId, String linkID) throws Exception {
|
||||
Map<String, Object> requestBody = Map.of("getContentInfoFromOutLinkReq", Map.of("contentId", contentId, "linkID", linkID, "account", ""), "commonAccountInfo", Map.of("account", "", "accountType", 1));
|
||||
|
||||
|
||||
OkResult okResult = OkHttp.post(baseUrl + "getContentInfoFromOutLink", Json.toJson(requestBody), Map.of("Accept-Encoding", "gzip, deflate, br, zstd", "User-Agent", baseHeaders.get("User-Agent")));
|
||||
String m3u8 = Json.safeObject(okResult.getBody()).getAsJsonObject("data").getAsJsonObject("contentInfo").get("presentURL").getAsString();
|
||||
|
||||
String m3u8Str = OkHttp.string(m3u8);
|
||||
String resultUrl = m3u8;
|
||||
for (String s : m3u8Str.split("\n")) {
|
||||
if (s.contains("index.m3u8")) {
|
||||
resultUrl = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return m3u8.split("playlist.m3u8")[0] + resultUrl;
|
||||
}
|
||||
|
||||
public String get4kVideoInfo(String fid, String linkID) throws Exception {
|
||||
String auth = getAuth();
|
||||
String phone = getPhone();
|
||||
|
||||
// 构建 JSON 请求体
|
||||
Map<String, Object> requestBody = new HashMap<>();
|
||||
Map<String, Object> dlFromOutLinkReqV3 = new HashMap<>();
|
||||
Map<String, Object> commonAccountInfo = new HashMap<>();
|
||||
|
||||
dlFromOutLinkReqV3.put("linkID", linkID);
|
||||
dlFromOutLinkReqV3.put("account", phone);
|
||||
|
||||
Map<String, Object> coIDLst = new HashMap<>();
|
||||
coIDLst.put("item", Collections.singletonList(fid));
|
||||
dlFromOutLinkReqV3.put("coIDLst", coIDLst);
|
||||
|
||||
commonAccountInfo.put("account", phone);
|
||||
commonAccountInfo.put("accountType", 1);
|
||||
|
||||
requestBody.put("dlFromOutLinkReqV3", dlFromOutLinkReqV3);
|
||||
requestBody.put("commonAccountInfo", commonAccountInfo);
|
||||
|
||||
/* {
|
||||
"dlFromOutLinkReqV3" : {
|
||||
"linkID" : "105CpbaJQFYc6",
|
||||
"account" : "18896781601",
|
||||
"coIDLst" : {
|
||||
"item" : [ "DFTOdJkuAEwA1011ZpAcj1pl039202404112124392cb/Fkco6TgMKlnJwKbVul0ZKeYT5p2hIioVy" ]
|
||||
}
|
||||
},
|
||||
"commonAccountInfo" : {
|
||||
"account" : "18896781601",
|
||||
"accountType" : 1
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
// 构建请求
|
||||
Map<String, String> header = getHeader();
|
||||
|
||||
|
||||
OkResult okResult = OkHttp.post(baseUrl + "dlFromOutLinkV3", encrypt(Json.toJson(requestBody)), header);
|
||||
JsonObject resultJson = Json.safeObject(decrypt(okResult.getBody()));
|
||||
if (resultJson.get("resultCode").getAsInt() == 0) {
|
||||
return resultJson.getAsJsonObject("data").get("redrUrl").getAsString();
|
||||
|
||||
}
|
||||
|
||||
// 解析 JSON 响应
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getPhone() {
|
||||
String phone = StringUtils.split(Util.base64Decode(getAuth()), ":")[1];
|
||||
SpiderDebug.log("phone:" + phone);
|
||||
return phone;
|
||||
}
|
||||
|
||||
private static String getAuth() {
|
||||
String auth = YunTokenHandler.get().getToken();
|
||||
SpiderDebug.log("auth:" + auth);
|
||||
return auth;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Map<String, String> getHeader() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
|
||||
header.put("X-Deviceinfo", "||3|12.27.0|safari|13.1.2|1||macos 10.15.6|1324X381|zh-cn|||");
|
||||
header.put("hcy-cool-flag", "1");
|
||||
header.put("Authorization", "Basic " + getAuth());
|
||||
header.put("Content-Type", "application/json");
|
||||
return header;
|
||||
}
|
||||
|
||||
|
||||
public String playerContent(String[] split, String flag) throws Exception {
|
||||
String playUrl = "";
|
||||
if (flag.contains("原画")) {
|
||||
String contentId = split[0];
|
||||
String linkID = split[1];
|
||||
playUrl = YunDrive.get().get4kVideoInfo(contentId, linkID);
|
||||
playUrl = ProxyServer.INSTANCE.buildProxyUrl(playUrl, new HashMap<>());
|
||||
|
||||
} else {
|
||||
String contentId = split[0];
|
||||
String linkID = split[1];
|
||||
playUrl = YunDrive.get().fetchPlayUrl(contentId, linkID);
|
||||
}
|
||||
return Result.get().url(playUrl).octet().header(getHeader()).string();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package com.github.catvod.api;
|
||||
|
||||
|
||||
import com.github.catvod.bean.yun.Cache;
|
||||
import com.github.catvod.bean.yun.User;
|
||||
import com.github.catvod.utils.Path;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class YunTokenHandler {
|
||||
|
||||
private final Cache cache;
|
||||
|
||||
public File getCache() {
|
||||
return Path.tv("yun139");
|
||||
}
|
||||
|
||||
private YunTokenHandler() {
|
||||
cache = Cache.objectFrom(Path.read(getCache()));
|
||||
}
|
||||
|
||||
private static class Loader {
|
||||
static volatile YunTokenHandler INSTANCE = new YunTokenHandler();
|
||||
}
|
||||
|
||||
public static YunTokenHandler get() {
|
||||
return YunTokenHandler.Loader.INSTANCE;
|
||||
}
|
||||
|
||||
|
||||
public String getToken() {
|
||||
User user = cache.getUser();
|
||||
return user.getCookie();
|
||||
//return "cGM6MTg4OTY3ODE2MDE6eTM1Tjd1dG58MXxSQ1N8MTc1NDQ2OTgwNzEyOXxzMlN0T1VEV3lOVmF5V3pNbGFfM2tJbVp1ZmlqSHBqaEhTSzVyNHZqVXNRLmlhV3loSUxHNDFkMUI5N1BqXzhWN0dtVWtKLnBTclhpNGpZU1EuTGZWMTV3MVFoZmNpcEVoZkxUV2tvYjB0bkFTYV9RTUhhaHhveWx6YkdmcEhQdjNCS1lrbnp1LkxaWDdKOE40YkNNRjkzT3piNmx2Y0d3TWdVUkl5b18ubVUt";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
package com.github.catvod.bean.BD;
|
||||
|
||||
|
||||
import com.github.catvod.api.BaiDuYunHandler;
|
||||
import com.github.catvod.bean.yun.User;
|
||||
import com.github.catvod.spider.Init;
|
||||
import com.github.catvod.utils.Path;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Cache {
|
||||
|
||||
@SerializedName("user")
|
||||
private User user;
|
||||
|
||||
|
||||
public static Cache objectFrom(String str) {
|
||||
Cache item = new Gson().fromJson(str, Cache.class);
|
||||
return item == null ? new Cache() : item;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user == null ? new User("") : user;
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
this.save();
|
||||
}
|
||||
|
||||
|
||||
public void save() {
|
||||
Init.execute(() -> Path.write(BaiDuYunHandler.get().getCache(), toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new Gson().toJson(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -58,9 +58,7 @@ public class Result {
|
|||
public static String string(List<Class> classes, List<Vod> list, LinkedHashMap<String, List<Filter>> filters) {
|
||||
return Result.get().classes(classes).vod(list).filters(filters).string();
|
||||
}
|
||||
public static String string(Integer page,Integer pagecount,Integer limit,Integer total,List<Vod> list){
|
||||
return Result.get().page(page,pagecount,limit,total).vod(list).string();
|
||||
}
|
||||
|
||||
public static String string(List<Class> classes, List<Vod> list, JSONObject filters) {
|
||||
return Result.get().classes(classes).vod(list).filters(filters).string();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,6 @@ package com.github.catvod.bean;
|
|||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Vod {
|
||||
|
||||
@SerializedName("type_name")
|
||||
|
|
@ -203,46 +200,4 @@ public class Vod {
|
|||
this.ratio = ratio;
|
||||
}
|
||||
}
|
||||
public static class VodPlayBuilder{
|
||||
private List<String> vodPlayFrom = new ArrayList<String>();
|
||||
private List<String> vodPlayUrl = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* 格式: from name1$$$name2$$$name3
|
||||
* url name$url#name2$url2$$$(分类2)$$分类3
|
||||
* @param playFrom
|
||||
* @param playUrl
|
||||
*/
|
||||
public VodPlayBuilder append(String playFrom, List<PlayUrl> playUrl){
|
||||
vodPlayFrom.add(playFrom);
|
||||
vodPlayUrl.add(toPlayUrlStr(playUrl));
|
||||
return this;
|
||||
}
|
||||
|
||||
public BuildResult build(){
|
||||
BuildResult buildResult = new BuildResult();
|
||||
buildResult.vodPlayFrom = String.join("$$$", vodPlayFrom);
|
||||
buildResult.vodPlayUrl = String.join("$$$", vodPlayUrl);
|
||||
return buildResult;
|
||||
}
|
||||
|
||||
private String toPlayUrlStr(List<PlayUrl> playUrl) {
|
||||
List<String> list = new ArrayList<>();
|
||||
for (PlayUrl url : playUrl) {
|
||||
list.add(url.name.replace("m3u8", "") + '$' + url.url);
|
||||
}
|
||||
return String.join("#", list);
|
||||
}
|
||||
|
||||
public static class BuildResult{
|
||||
public String vodPlayFrom;
|
||||
public String vodPlayUrl;
|
||||
}
|
||||
|
||||
public static class PlayUrl {
|
||||
public String flag; // 线路标志
|
||||
public String name;
|
||||
public String url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,16 +6,13 @@ import com.github.catvod.bean.Vod;
|
|||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Data {
|
||||
|
||||
@SerializedName("jump_id")
|
||||
@SerializedName(value = "jump_id", alternate = "id")
|
||||
private String jumpId;
|
||||
@SerializedName("id")
|
||||
private String id;
|
||||
@SerializedName(value = "thumbnail", alternate = "path")
|
||||
private String thumbnail;
|
||||
@SerializedName("title")
|
||||
|
|
@ -27,30 +24,24 @@ public class Data {
|
|||
@SerializedName("playlist")
|
||||
private Value playlist;
|
||||
@SerializedName("year")
|
||||
private String year;
|
||||
private Value year;
|
||||
@SerializedName("area")
|
||||
private String area;
|
||||
private Value area;
|
||||
@SerializedName("types")
|
||||
private List<Value> types;
|
||||
@SerializedName("actors")
|
||||
private List<Value> actors;
|
||||
@SerializedName("directors")
|
||||
private List<Value> directors;
|
||||
@SerializedName("source_list_source")
|
||||
private List<SourceListSource> source;
|
||||
@SerializedName("dataList")
|
||||
private List<Data> dataList;
|
||||
@SerializedName("btbo_downlist")
|
||||
private List<BtboDown> btboDownlist;
|
||||
|
||||
public String getJumpId() {
|
||||
return TextUtils.isEmpty(jumpId) ? "" : jumpId;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return TextUtils.isEmpty(id) ? "" : id;
|
||||
}
|
||||
|
||||
public String getThumbnail(String imgDomain) {
|
||||
return TextUtils.isEmpty(thumbnail) ? "" : "http://" + imgDomain + thumbnail;
|
||||
public String getThumbnail() {
|
||||
return TextUtils.isEmpty(thumbnail) ? "" : thumbnail + "@Referer=www.jianpianapp.com@User-Agent=jianpian-version362";
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
|
|
@ -70,11 +61,11 @@ public class Data {
|
|||
}
|
||||
|
||||
public String getYear() {
|
||||
return year == null ? "" : year;
|
||||
return year == null ? "" : year.getTitle();
|
||||
}
|
||||
|
||||
public String getArea() {
|
||||
return area == null ? "" : area;
|
||||
return area == null ? "" : area.getTitle();
|
||||
}
|
||||
|
||||
public String getTypes() {
|
||||
|
|
@ -89,20 +80,12 @@ public class Data {
|
|||
return directors == null ? "" : getValues(directors, true);
|
||||
}
|
||||
|
||||
public List<SourceListSource> getSource() {
|
||||
return source == null ? Collections.emptyList() : source;
|
||||
public List<BtboDown> getBtboDownlist() {
|
||||
return btboDownlist == null ? Collections.emptyList() : btboDownlist;
|
||||
}
|
||||
|
||||
public List<Data> getDataList() {
|
||||
return dataList == null ? Collections.emptyList() : dataList;
|
||||
}
|
||||
|
||||
public Vod homeVod(String imgDomain) {
|
||||
return new Vod(getJumpId(), getTitle(), getThumbnail(imgDomain));
|
||||
}
|
||||
|
||||
public Vod vod(String imgDomain) {
|
||||
return new Vod(getId(), getTitle(), getThumbnail(imgDomain), getMask());
|
||||
public Vod vod() {
|
||||
return new Vod(getJumpId(), getTitle(), getThumbnail(), getMask());
|
||||
}
|
||||
|
||||
public String getValues(List<Value> items, boolean link) {
|
||||
|
|
@ -111,6 +94,12 @@ public class Data {
|
|||
return Util.substring(sb.toString());
|
||||
}
|
||||
|
||||
public String getPlayUrl() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (BtboDown value : getBtboDownlist()) sb.append(value.getVal()).append("#");
|
||||
return Util.substring(sb.toString());
|
||||
}
|
||||
|
||||
public static class Value {
|
||||
|
||||
@SerializedName(value = "title", alternate = "name")
|
||||
|
|
@ -129,51 +118,13 @@ public class Data {
|
|||
}
|
||||
}
|
||||
|
||||
public static class SourceListSource {
|
||||
public static class BtboDown {
|
||||
|
||||
@SerializedName("name")
|
||||
private String name;
|
||||
@SerializedName("source_list")
|
||||
private List<SourceList> list;
|
||||
@SerializedName("val")
|
||||
private String val;
|
||||
|
||||
public String getName() {
|
||||
return TextUtils.isEmpty(name) ? "" : name;
|
||||
}
|
||||
|
||||
public List<SourceList> getList() {
|
||||
return list == null ? Collections.emptyList() : list;
|
||||
public String getVal() {
|
||||
return TextUtils.isEmpty(val) ? "" : val.replaceAll("ftp", "tvbox-xg:ftp");
|
||||
}
|
||||
}
|
||||
|
||||
public static class SourceList {
|
||||
|
||||
@SerializedName("source_name")
|
||||
private String name;
|
||||
@SerializedName("url")
|
||||
private String url;
|
||||
|
||||
public String getName() {
|
||||
return TextUtils.isEmpty(name) ? "" : name;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return TextUtils.isEmpty(url) ? "" : url.replaceAll("ftp", "tvbox-xg:ftp");
|
||||
}
|
||||
}
|
||||
|
||||
public String getVodFrom() {
|
||||
List<String> items = new ArrayList<>();
|
||||
for (SourceListSource source : getSource()) items.add(source.getName());
|
||||
return TextUtils.join("$$$", items);
|
||||
}
|
||||
|
||||
public String getVodUrl() {
|
||||
List<String> items = new ArrayList<>();
|
||||
for (SourceListSource source : getSource()) {
|
||||
List<String> urls = new ArrayList<>();
|
||||
for (SourceList item : source.getList()) urls.add(item.getName() + "$" + item.getUrl());
|
||||
items.add(TextUtils.join("#", urls));
|
||||
}
|
||||
return TextUtils.join("$$$", items);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
package com.github.catvod.bean.jianpian;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Search {
|
||||
|
||||
@SerializedName("data")
|
||||
private List<Search> data;
|
||||
@SerializedName("id")
|
||||
private String id;
|
||||
@SerializedName(value = "thumbnail", alternate = "path")
|
||||
private String thumbnail;
|
||||
@SerializedName("title")
|
||||
private String title;
|
||||
@SerializedName("mask")
|
||||
private String mask;
|
||||
|
||||
public static Search objectFrom(String str) {
|
||||
return new Gson().fromJson(str, Search.class);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return TextUtils.isEmpty(id) ? "" : id;
|
||||
}
|
||||
|
||||
public String getThumbnail(String imgDomain) {
|
||||
return TextUtils.isEmpty(thumbnail) ? "" : "http://" + imgDomain + thumbnail;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return TextUtils.isEmpty(title) ? "" : title;
|
||||
}
|
||||
|
||||
public String getMask() {
|
||||
return TextUtils.isEmpty(mask) ? "" : mask;
|
||||
}
|
||||
|
||||
public Vod vod(String imgDomain) {
|
||||
return new Vod(getId(), getTitle(), getThumbnail(imgDomain), getMask());
|
||||
}
|
||||
|
||||
public List<Search> getData() {
|
||||
return data == null ? Collections.emptyList() : data;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
package com.github.catvod.bean.pan123;
|
||||
|
||||
import com.github.catvod.api.Pan123Handler;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.spider.Init;
|
||||
import com.github.catvod.utils.Path;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Cache {
|
||||
|
||||
@SerializedName("user")
|
||||
private User user;
|
||||
|
||||
|
||||
public static Cache objectFrom(String str) {
|
||||
if(str.isEmpty()) return new Cache();
|
||||
SpiderDebug.log("Cache.objectFrom: " + str);
|
||||
Cache item = new Gson().fromJson(str, Cache.class);
|
||||
return item == null ? new Cache() : item;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user == null ? new User() : user;
|
||||
}
|
||||
|
||||
|
||||
public void setUserInfo(User user) {
|
||||
this.user = user;
|
||||
this.saveUser();
|
||||
}
|
||||
|
||||
public void saveUser() {
|
||||
SpiderDebug.log("Cache.saveUser: " + toString());
|
||||
SpiderDebug.log("Cache.path: " + Pan123Handler.INSTANCE.getCache().getAbsolutePath());
|
||||
Init.execute(() -> Path.write(Pan123Handler.INSTANCE.getCache(), toString()));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new Gson().toJson(this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package com.github.catvod.bean.pan123
|
||||
|
||||
data class ShareInfo(
|
||||
val filename: String,
|
||||
val shareKey: String,
|
||||
val sharePwd: String,
|
||||
val next: Int,
|
||||
val fileId: Long,
|
||||
val S3KeyFlag: String,
|
||||
val Size: Long,
|
||||
val Etag: String
|
||||
)
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
package com.github.catvod.bean.pan123;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class User {
|
||||
|
||||
@SerializedName("expire")
|
||||
private long expire;
|
||||
@SerializedName("cookie")
|
||||
private String cookie;
|
||||
|
||||
@SerializedName("userName")
|
||||
private String userName;
|
||||
@SerializedName("password")
|
||||
private String password;
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getCookie() {
|
||||
return cookie;
|
||||
}
|
||||
|
||||
public void setCookie(String cookie) {
|
||||
this.cookie = cookie;
|
||||
}
|
||||
|
||||
public long getExpire() {
|
||||
return expire;
|
||||
}
|
||||
|
||||
public void setExpire(long expire) {
|
||||
this.expire = expire;
|
||||
}
|
||||
|
||||
public static User objectFrom(String str) {
|
||||
User item = new Gson().fromJson(str, User.class);
|
||||
return item == null ? new User() : item;
|
||||
}
|
||||
|
||||
|
||||
public void clean() {
|
||||
this.cookie = "";
|
||||
this.userName = "";
|
||||
this.password = "";
|
||||
this.expire = 0L;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package com.github.catvod.bean.quark;
|
||||
|
||||
import com.github.catvod.api.QuarkApi;
|
||||
import com.github.catvod.spider.Init;
|
||||
import com.github.catvod.utils.Path;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Cache {
|
||||
|
||||
@SerializedName("user")
|
||||
private User user;
|
||||
|
||||
|
||||
public static Cache objectFrom(String str) {
|
||||
Cache item = new Gson().fromJson(str, Cache.class);
|
||||
return item == null ? new Cache() : item;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user == null ? new User("") : user;
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
this.save();
|
||||
}
|
||||
|
||||
|
||||
public void save() {
|
||||
Init.execute(() -> Path.write(QuarkApi.get().getCache(), toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new Gson().toJson(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
package com.github.catvod.bean.quark;
|
||||
|
||||
import com.github.catvod.utils.Util;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Item {
|
||||
private String fileId;
|
||||
private String shareId;
|
||||
private String shareToken;
|
||||
private String shareFileToken;
|
||||
private String seriesId;
|
||||
private String name;
|
||||
private String type;
|
||||
private String formatType;
|
||||
private Double size;
|
||||
private String parent;
|
||||
private String shareData;
|
||||
private int shareIndex;
|
||||
private Double lastUpdateAt;
|
||||
private String subtitle;
|
||||
|
||||
public Item() {
|
||||
this.fileId = "";
|
||||
this.shareId = "";
|
||||
this.shareToken = "";
|
||||
this.shareFileToken = "";
|
||||
this.seriesId = "";
|
||||
this.name = "";
|
||||
this.type = "";
|
||||
this.formatType = "";
|
||||
this.size = 0d;
|
||||
this.parent = "";
|
||||
this.shareData = null;
|
||||
this.shareIndex = 0;
|
||||
this.lastUpdateAt = 0d;
|
||||
}
|
||||
|
||||
public static Item objectFrom(Map<String, Object> item_json, String shareId, int shareIndex) {
|
||||
Item item = new Item();
|
||||
item.fileId = item_json.get("fid") != null ? (String) item_json.get("fid") : "";
|
||||
item.shareId = shareId;
|
||||
item.shareToken = item_json.get("stoken") != null ? (String) item_json.get("stoken") : "";
|
||||
item.shareFileToken = item_json.get("share_fid_token") != null ? (String) item_json.get("share_fid_token") : "";
|
||||
item.seriesId = item_json.get("series_id") != null ? (String) item_json.get("series_id") : "";
|
||||
item.name = item_json.get("file_name") != null ? (String) item_json.get("file_name") : "";
|
||||
item.type = item_json.get("obj_category") != null ? (String) item_json.get("obj_category") : "";
|
||||
item.formatType = item_json.get("format_type") != null ? (String) item_json.get("format_type") : "";
|
||||
item.size = item_json.get("size") != null ? (Double) item_json.get("size") : 0d;
|
||||
item.parent = item_json.get("pdir_fid") != null ? (String) item_json.get("pdir_fid") : "";
|
||||
item.lastUpdateAt = item_json.get("last_update_at") != null ? (Double) item_json.get("last_update_at") : Double.valueOf(0d);
|
||||
item.shareIndex = shareIndex;
|
||||
return item;
|
||||
}
|
||||
|
||||
public String getFileExtension() {
|
||||
String[] arr = name.split("\\.");
|
||||
return arr[arr.length - 1];
|
||||
}
|
||||
|
||||
public String getSubtitle() {
|
||||
return subtitle;
|
||||
}
|
||||
|
||||
public void setSubtitle(String subtitle) {
|
||||
this.subtitle = subtitle;
|
||||
}
|
||||
|
||||
public String getFileId() {
|
||||
return fileId.isEmpty() ? "" : fileId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name.isEmpty() ? "" : name;
|
||||
}
|
||||
|
||||
public String getParent() {
|
||||
return parent.isEmpty() ? "" : "[" + parent + "]";
|
||||
}
|
||||
|
||||
public String getSize() {
|
||||
return size.equals("0") ? "" : "[" + size + "]";
|
||||
}
|
||||
|
||||
|
||||
public int getShareIndex() {
|
||||
return shareIndex;
|
||||
}
|
||||
|
||||
public String getDisplayName(String type_name) {
|
||||
String name = getName();
|
||||
if (type_name.equals("电视剧")) {
|
||||
String[] replaceNameList = {"4k", "4K"};
|
||||
name = name.replaceAll("\\." + getFileExtension(), "");
|
||||
for (String replaceName : replaceNameList) {
|
||||
name = name.replaceAll(replaceName, "");
|
||||
}
|
||||
name = Pattern.compile("/\\.S01E(.*?)\\./").matcher(name).find() ? name.split("/\\.S01E(.*?)\\./")[1] : name;
|
||||
String[] numbers = name.split("\\d+");
|
||||
if (numbers.length > 0) {
|
||||
name = numbers[0];
|
||||
}
|
||||
}
|
||||
return name + " " + Util.getSize(size);
|
||||
}
|
||||
|
||||
public String getEpisodeUrl(String type_name) {
|
||||
return getDisplayName(type_name) + "$" + getFileId() + "++" + shareFileToken + "++" + shareId + "++" + shareToken;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package com.github.catvod.bean.quark;
|
||||
|
||||
public class ShareData {
|
||||
private String shareId;
|
||||
private String folderId;
|
||||
private String sharePwd ;
|
||||
|
||||
public ShareData(String shareId, String folderId) {
|
||||
this.shareId = shareId;
|
||||
this.folderId = folderId;
|
||||
}
|
||||
|
||||
public String getSharePwd() {
|
||||
return sharePwd;
|
||||
}
|
||||
|
||||
public void setSharePwd(String sharePwd) {
|
||||
this.sharePwd = sharePwd;
|
||||
}
|
||||
|
||||
public String getShareId() {
|
||||
return shareId;
|
||||
}
|
||||
|
||||
public void setShareId(String shareId) {
|
||||
this.shareId = shareId;
|
||||
}
|
||||
|
||||
public String getFolderId() {
|
||||
return folderId;
|
||||
}
|
||||
|
||||
public void setFolderId(String folderId) {
|
||||
this.folderId = folderId;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package com.github.catvod.bean.quark;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class User {
|
||||
public User(String cookie) {
|
||||
this.cookie = cookie;
|
||||
}
|
||||
|
||||
@SerializedName("cookie")
|
||||
private String cookie;
|
||||
|
||||
public String getCookie() {
|
||||
return cookie;
|
||||
}
|
||||
|
||||
public void setCookie(String cookie) {
|
||||
this.cookie = cookie;
|
||||
}
|
||||
|
||||
public static User objectFrom(String cookie) {
|
||||
return new User(cookie);
|
||||
}
|
||||
|
||||
|
||||
public void clean() {
|
||||
this.cookie = "";
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
package com.github.catvod.bean.tianyi;
|
||||
|
||||
import com.github.catvod.api.TianYiHandler;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.spider.Init;
|
||||
import com.github.catvod.utils.Path;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Cache {
|
||||
|
||||
@SerializedName("user")
|
||||
private User user;
|
||||
|
||||
|
||||
public static Cache objectFrom(String str) {
|
||||
SpiderDebug.log("Cache.objectFrom: " + str);
|
||||
Cache item = new Gson().fromJson(str, Cache.class);
|
||||
return item == null ? new Cache() : item;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user == null ? new User("") : user;
|
||||
}
|
||||
|
||||
|
||||
public void setTianyiUser(User user) {
|
||||
this.user = user;
|
||||
this.saveTianyiUser();
|
||||
}
|
||||
|
||||
public void saveTianyiUser() {
|
||||
Init.execute(() -> Path.write( TianYiHandler.get().getCache(), toString()));
|
||||
}
|
||||
|
||||
public void saveTianyieUser() {
|
||||
Init.execute(() -> Path.write( TianYiHandler.get().geteCache(), toString()));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new Gson().toJson(this);
|
||||
}
|
||||
|
||||
|
||||
public void setTianyieUser(User user) {
|
||||
this.user = user;
|
||||
this.saveTianyieUser();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
package com.github.catvod.bean.tianyi;
|
||||
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Item {
|
||||
private String fileId;
|
||||
private String shareId;
|
||||
private String shareToken;
|
||||
private String shareFileToken;
|
||||
private String seriesId;
|
||||
private String name;
|
||||
private String type;
|
||||
private String formatType;
|
||||
private Double size;
|
||||
private String parent;
|
||||
private String shareData;
|
||||
private int shareIndex;
|
||||
private Double lastUpdateAt;
|
||||
private String subtitle;
|
||||
|
||||
public Item() {
|
||||
this.fileId = "";
|
||||
this.shareId = "";
|
||||
this.shareToken = "";
|
||||
this.shareFileToken = "";
|
||||
this.seriesId = "";
|
||||
this.name = "";
|
||||
this.type = "";
|
||||
this.formatType = "";
|
||||
this.size = 0d;
|
||||
this.parent = "";
|
||||
this.shareData = null;
|
||||
this.shareIndex = 0;
|
||||
this.lastUpdateAt = 0d;
|
||||
}
|
||||
|
||||
public static Item objectFrom(JsonObject item_json, String shareId, int shareIndex) {
|
||||
Item item = new Item();
|
||||
item.fileId = item_json.get("id") != null ? item_json.get("id").getAsString() : "";
|
||||
item.shareId = shareId;
|
||||
item.name = item_json.get("name") != null ? item_json.get("name").getAsString() : "";
|
||||
item.size = item_json.get("size") != null ? item_json.get("size").getAsDouble() : 0d;
|
||||
/* item.shareToken = item_json.get("stoken") != null ? (String) item_json.get("stoken") : "";
|
||||
item.shareFileToken = item_json.get("share_fid_token") != null ? (String) item_json.get("share_fid_token") : "";
|
||||
item.seriesId = item_json.get("series_id") != null ? (String) item_json.get("series_id") : "";
|
||||
|
||||
item.type = item_json.get("obj_category") != null ? (String) item_json.get("obj_category") : "";
|
||||
item.formatType = item_json.get("format_type") != null ? (String) item_json.get("format_type") : "";
|
||||
item.size = item_json.get("size") != null ? (Double) item_json.get("size") : 0d;
|
||||
item.parent = item_json.get("pdir_fid") != null ? (String) item_json.get("pdir_fid") : "";
|
||||
item.lastUpdateAt = item_json.get("last_update_at") != null ? (Double) item_json.get("last_update_at") : Double.valueOf(0d);
|
||||
item.shareIndex = shareIndex;*/
|
||||
return item;
|
||||
}
|
||||
|
||||
public String getFileExtension() {
|
||||
String[] arr = name.split("\\.");
|
||||
return arr[arr.length - 1];
|
||||
}
|
||||
|
||||
public String getSubtitle() {
|
||||
return subtitle;
|
||||
}
|
||||
|
||||
public void setSubtitle(String subtitle) {
|
||||
this.subtitle = subtitle;
|
||||
}
|
||||
|
||||
public String getFileId() {
|
||||
return fileId.isEmpty() ? "" : fileId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name.isEmpty() ? "" : name;
|
||||
}
|
||||
|
||||
public String getParent() {
|
||||
return parent.isEmpty() ? "" : "[" + parent + "]";
|
||||
}
|
||||
|
||||
public String getSize() {
|
||||
return size.equals("0") ? "" : "[" + size + "]";
|
||||
}
|
||||
|
||||
|
||||
public int getShareIndex() {
|
||||
return shareIndex;
|
||||
}
|
||||
|
||||
public String getDisplayName(String type_name) {
|
||||
String name = getName();
|
||||
if (type_name.equals("电视剧")) {
|
||||
String[] replaceNameList = {"4k", "4K"};
|
||||
name = name.replaceAll("\\." + getFileExtension(), "");
|
||||
for (String replaceName : replaceNameList) {
|
||||
name = name.replaceAll(replaceName, "");
|
||||
}
|
||||
name = Pattern.compile("/\\.S01E(.*?)\\./").matcher(name).find() ? name.split("/\\.S01E(.*?)\\./")[1] : name;
|
||||
String[] numbers = name.split("\\d+");
|
||||
if (numbers.length > 0) {
|
||||
name = numbers[0];
|
||||
}
|
||||
}
|
||||
return name + " " + Util.getSize(size);
|
||||
}
|
||||
|
||||
public String getEpisodeUrl(String type_name) {
|
||||
return getDisplayName(type_name) + "$" + getFileId() + "++" + shareId ;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
package com.github.catvod.bean.tianyi;
|
||||
|
||||
public class ShareData {
|
||||
|
||||
private String shareId;
|
||||
private String folderId;
|
||||
private String sharePwd;
|
||||
private String fileId;
|
||||
private Integer shareMode;
|
||||
private Boolean isFolder;
|
||||
|
||||
|
||||
public String getFileId() {
|
||||
return fileId;
|
||||
}
|
||||
|
||||
public void setFileId(String fileId) {
|
||||
this.fileId = fileId;
|
||||
}
|
||||
|
||||
public Integer getShareMode() {
|
||||
return shareMode;
|
||||
}
|
||||
|
||||
public void setShareMode(Integer shareMode) {
|
||||
this.shareMode = shareMode;
|
||||
}
|
||||
|
||||
public Boolean getFolder() {
|
||||
return isFolder;
|
||||
}
|
||||
|
||||
public void setFolder(Boolean folder) {
|
||||
isFolder = folder;
|
||||
}
|
||||
|
||||
public ShareData(String shareId, String folderId) {
|
||||
this.shareId = shareId;
|
||||
this.folderId = folderId;
|
||||
}
|
||||
|
||||
public String getSharePwd() {
|
||||
return sharePwd;
|
||||
}
|
||||
|
||||
public void setSharePwd(String sharePwd) {
|
||||
this.sharePwd = sharePwd;
|
||||
}
|
||||
|
||||
public String getShareId() {
|
||||
return shareId;
|
||||
}
|
||||
|
||||
public void setShareId(String shareId) {
|
||||
this.shareId = shareId;
|
||||
}
|
||||
|
||||
public String getFolderId() {
|
||||
return folderId;
|
||||
}
|
||||
|
||||
public void setFolderId(String folderId) {
|
||||
this.folderId = folderId;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
package com.github.catvod.bean.tianyi;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class User {
|
||||
public User(String cookie) {
|
||||
this.cookie = cookie;
|
||||
}
|
||||
|
||||
@SerializedName("cookie")
|
||||
private String cookie;
|
||||
|
||||
|
||||
|
||||
|
||||
public String getCookie() {
|
||||
return cookie;
|
||||
}
|
||||
|
||||
public void setCookie(String cookie) {
|
||||
this.cookie = cookie;
|
||||
}
|
||||
|
||||
public static User objectFrom(String cookie) {
|
||||
return new User(cookie);
|
||||
}
|
||||
|
||||
|
||||
public void clean() {
|
||||
this.cookie = "";
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
package com.github.catvod.bean.uc;
|
||||
|
||||
import com.github.catvod.api.TianYiHandler;
|
||||
import com.github.catvod.api.UCApi;
|
||||
import com.github.catvod.api.UCTokenHandler;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.spider.Init;
|
||||
import com.github.catvod.utils.Path;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Cache {
|
||||
|
||||
@SerializedName("user")
|
||||
private User user;
|
||||
|
||||
|
||||
public static Cache objectFrom(String str) {
|
||||
SpiderDebug.log("Cache.objectFrom: " + str);
|
||||
Cache item = new Gson().fromJson(str, Cache.class);
|
||||
return item == null ? new Cache() : item;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user == null ? new User("") : user;
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
this.save();
|
||||
}
|
||||
|
||||
public void setTokenUser(User user) {
|
||||
this.user = user;
|
||||
this.saveToken();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void saveToken() {
|
||||
Init.execute(() -> Path.write(new UCTokenHandler().getCache(), toString()));
|
||||
}
|
||||
|
||||
|
||||
public void save() {
|
||||
Init.execute(() -> Path.write(UCApi.get().getCache(), toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new Gson().toJson(this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
package com.github.catvod.bean.uc;
|
||||
|
||||
import com.github.catvod.utils.Util;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Item {
|
||||
private String fileId;
|
||||
private String shareId;
|
||||
private String shareToken;
|
||||
private String shareFileToken;
|
||||
private String seriesId;
|
||||
private String name;
|
||||
private String type;
|
||||
private String formatType;
|
||||
private Double size;
|
||||
private String parent;
|
||||
private String shareData;
|
||||
private int shareIndex;
|
||||
private Double lastUpdateAt;
|
||||
private String subtitle;
|
||||
|
||||
public Item() {
|
||||
this.fileId = "";
|
||||
this.shareId = "";
|
||||
this.shareToken = "";
|
||||
this.shareFileToken = "";
|
||||
this.seriesId = "";
|
||||
this.name = "";
|
||||
this.type = "";
|
||||
this.formatType = "";
|
||||
this.size = 0d;
|
||||
this.parent = "";
|
||||
this.shareData = null;
|
||||
this.shareIndex = 0;
|
||||
this.lastUpdateAt = 0d;
|
||||
}
|
||||
|
||||
public static Item objectFrom(Map<String, Object> item_json, String shareId, int shareIndex) {
|
||||
Item item = new Item();
|
||||
item.fileId = item_json.get("fid") != null ? (String) item_json.get("fid") : "";
|
||||
item.shareId = shareId;
|
||||
item.shareToken = item_json.get("stoken") != null ? (String) item_json.get("stoken") : "";
|
||||
item.shareFileToken = item_json.get("share_fid_token") != null ? (String) item_json.get("share_fid_token") : "";
|
||||
item.seriesId = item_json.get("series_id") != null ? (String) item_json.get("series_id") : "";
|
||||
item.name = item_json.get("file_name") != null ? (String) item_json.get("file_name") : "";
|
||||
item.type = item_json.get("obj_category") != null ? (String) item_json.get("obj_category") : "";
|
||||
item.formatType = item_json.get("format_type") != null ? (String) item_json.get("format_type") : "";
|
||||
item.size = item_json.get("size") != null ? (Double) item_json.get("size") : 0d;
|
||||
item.parent = item_json.get("pdir_fid") != null ? (String) item_json.get("pdir_fid") : "";
|
||||
item.lastUpdateAt = item_json.get("last_update_at") != null ? (Double) item_json.get("last_update_at") : Double.valueOf(0d);
|
||||
item.shareIndex = shareIndex;
|
||||
return item;
|
||||
}
|
||||
|
||||
public String getFileExtension() {
|
||||
String[] arr = name.split("\\.");
|
||||
return arr[arr.length - 1];
|
||||
}
|
||||
|
||||
public String getSubtitle() {
|
||||
return subtitle;
|
||||
}
|
||||
|
||||
public void setSubtitle(String subtitle) {
|
||||
this.subtitle = subtitle;
|
||||
}
|
||||
|
||||
public String getFileId() {
|
||||
return fileId.isEmpty() ? "" : fileId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name.isEmpty() ? "" : name;
|
||||
}
|
||||
|
||||
public String getParent() {
|
||||
return parent.isEmpty() ? "" : "[" + parent + "]";
|
||||
}
|
||||
|
||||
public String getSize() {
|
||||
return size.equals("0") ? "" : "[" + size + "]";
|
||||
}
|
||||
|
||||
|
||||
public int getShareIndex() {
|
||||
return shareIndex;
|
||||
}
|
||||
|
||||
public String getDisplayName(String type_name) {
|
||||
String name = getName();
|
||||
if (type_name.equals("电视剧")) {
|
||||
String[] replaceNameList = {"4k", "4K"};
|
||||
name = name.replaceAll("\\." + getFileExtension(), "");
|
||||
for (String replaceName : replaceNameList) {
|
||||
name = name.replaceAll(replaceName, "");
|
||||
}
|
||||
name = Pattern.compile("/\\.S01E(.*?)\\./").matcher(name).find() ? name.split("/\\.S01E(.*?)\\./")[1] : name;
|
||||
String[] numbers = name.split("\\d+");
|
||||
if (numbers.length > 0) {
|
||||
name = numbers[0];
|
||||
}
|
||||
}
|
||||
return name + " " + Util.getSize(size);
|
||||
}
|
||||
|
||||
public String getEpisodeUrl(String type_name) {
|
||||
return getDisplayName(type_name) + "$" + getFileId() + "++" + shareFileToken + "++" + shareId + "++" + shareToken;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package com.github.catvod.bean.uc;
|
||||
|
||||
public class ShareData {
|
||||
private String shareId;
|
||||
private String folderId;
|
||||
private String sharePwd ;
|
||||
|
||||
public ShareData(String shareId, String folderId) {
|
||||
this.shareId = shareId;
|
||||
this.folderId = folderId;
|
||||
}
|
||||
|
||||
public String getSharePwd() {
|
||||
return sharePwd;
|
||||
}
|
||||
|
||||
public void setSharePwd(String sharePwd) {
|
||||
this.sharePwd = sharePwd;
|
||||
}
|
||||
|
||||
public String getShareId() {
|
||||
return shareId;
|
||||
}
|
||||
|
||||
public void setShareId(String shareId) {
|
||||
this.shareId = shareId;
|
||||
}
|
||||
|
||||
public String getFolderId() {
|
||||
return folderId;
|
||||
}
|
||||
|
||||
public void setFolderId(String folderId) {
|
||||
this.folderId = folderId;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
package com.github.catvod.bean.uc;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class User {
|
||||
public User(String cookie) {
|
||||
this.cookie = cookie;
|
||||
}
|
||||
|
||||
@SerializedName("cookie")
|
||||
private String cookie;
|
||||
|
||||
|
||||
|
||||
|
||||
public String getCookie() {
|
||||
return cookie;
|
||||
}
|
||||
|
||||
public void setCookie(String cookie) {
|
||||
this.cookie = cookie;
|
||||
}
|
||||
|
||||
public static User objectFrom(String cookie) {
|
||||
return new User(cookie);
|
||||
}
|
||||
|
||||
|
||||
public void clean() {
|
||||
this.cookie = "";
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
package com.github.catvod.bean.yun;
|
||||
|
||||
|
||||
import com.github.catvod.api.YunTokenHandler;
|
||||
import com.github.catvod.spider.Init;
|
||||
import com.github.catvod.utils.Path;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Cache {
|
||||
|
||||
@SerializedName("user")
|
||||
private User user;
|
||||
|
||||
|
||||
public static Cache objectFrom(String str) {
|
||||
Cache item = new Gson().fromJson(str, Cache.class);
|
||||
return item == null ? new Cache() : item;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user == null ? new User("") : user;
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
this.save();
|
||||
}
|
||||
|
||||
|
||||
public void save() {
|
||||
Init.execute(() -> Path.write(YunTokenHandler.get().getCache(), toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new Gson().toJson(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package com.github.catvod.bean.yun;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class User {
|
||||
public User(String cookie) {
|
||||
this.cookie = cookie;
|
||||
}
|
||||
|
||||
@SerializedName("cookie")
|
||||
private String cookie;
|
||||
|
||||
public String getCookie() {
|
||||
return cookie;
|
||||
}
|
||||
|
||||
public void setCookie(String cookie) {
|
||||
this.cookie = cookie;
|
||||
}
|
||||
|
||||
public static User objectFrom(String cookie) {
|
||||
return new User(cookie);
|
||||
}
|
||||
|
||||
|
||||
public void clean() {
|
||||
this.cookie = "";
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,6 @@ public class SpiderDebug {
|
|||
}
|
||||
|
||||
public static void log(String msg) {
|
||||
System.out.println(msg);
|
||||
Log.d(TAG, msg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,10 @@ import android.widget.Button;
|
|||
|
||||
import com.github.catvod.R;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.spider.*;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.github.catvod.spider.Init;
|
||||
import com.github.catvod.spider.PTT;
|
||||
import com.orhanobut.logger.AndroidLogAdapter;
|
||||
import com.orhanobut.logger.Logger;
|
||||
import com.whl.quickjs.android.QuickJSLoader;
|
||||
import com.whl.quickjs.wrapper.QuickJSContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
|
@ -25,11 +22,9 @@ public class MainActivity extends Activity {
|
|||
private ExecutorService executor;
|
||||
private Spider spider;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_main);
|
||||
Button homeContent = findViewById(R.id.homeContent);
|
||||
Button homeVideoContent = findViewById(R.id.homeVideoContent);
|
||||
|
|
@ -46,15 +41,12 @@ public class MainActivity extends Activity {
|
|||
Logger.addLogAdapter(new AndroidLogAdapter());
|
||||
executor = Executors.newCachedThreadPool();
|
||||
executor.execute(this::initSpider);
|
||||
//String content = OkHttp.string("https://androidcatvodspider.netlify.app/json/js/newvision.js");
|
||||
// byte[] bytes = context.compileModule(content, "newvision.js");
|
||||
// String result = "//bb" + Util.base64Encode(bytes);
|
||||
}
|
||||
|
||||
private void initSpider() {
|
||||
try {
|
||||
Init.init(getApplicationContext());
|
||||
spider = new Wogg();
|
||||
spider = new PTT();
|
||||
spider.init(this, "");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
|
|
@ -82,7 +74,7 @@ public class MainActivity extends Activity {
|
|||
HashMap<String, String> extend = new HashMap<>();
|
||||
extend.put("c", "19");
|
||||
extend.put("year", "2024");
|
||||
Logger.t("categoryContent").d(spider.categoryContent("1", "2", true, extend));
|
||||
Logger.t("categoryContent").d(spider.categoryContent("3", "2", true, extend));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
@ -90,8 +82,7 @@ public class MainActivity extends Activity {
|
|||
|
||||
public void detailContent() {
|
||||
try {
|
||||
// Logger.t("detailContent").d(spider.detailContent(Arrays.asList("https://drive.uc.cn/s/1bc52309b62f4?public=1")));
|
||||
Logger.t("detailContent").d(spider.detailContent(Arrays.asList("/voddetail/88220.html")));
|
||||
Logger.t("detailContent").d(spider.detailContent(Arrays.asList("434686")));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
@ -99,7 +90,7 @@ public class MainActivity extends Activity {
|
|||
|
||||
public void playerContent() {
|
||||
try {
|
||||
Logger.t("playerContent").d(spider.playerContent("Uc4K", "c346b2883f0346d793b2aab7dbf6c08c++6924b088a6f624fd5baa769bf48ae337++1bc52309b62f4++YmXbBVC2f9W1Frq2ji2l0p0TxSaJhSr7HjrKRat1E6c=", new ArrayList<>()));
|
||||
Logger.t("playerContent").d(spider.playerContent("", "382044/1/78", new ArrayList<>()));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ public class OkHttp {
|
|||
|
||||
private OkHttpClient client;
|
||||
|
||||
|
||||
private static class Loader {
|
||||
static volatile OkHttp INSTANCE = new OkHttp();
|
||||
}
|
||||
|
|
@ -54,10 +53,6 @@ public class OkHttp {
|
|||
return url.startsWith("http") ? new OkRequest(GET, url, params, header).execute(client()).getBody() : "";
|
||||
}
|
||||
|
||||
public static OkResult get(String url, Map<String, String> params, Map<String, String> header) {
|
||||
return new OkRequest(GET, url, params, header).execute(client());
|
||||
}
|
||||
|
||||
public static String post(String url, Map<String, String> params) {
|
||||
return post(url, params, null).getBody();
|
||||
}
|
||||
|
|
@ -77,9 +72,6 @@ public class OkHttp {
|
|||
public static String getLocation(String url, Map<String, String> header) throws IOException {
|
||||
return getLocation(client().newBuilder().followRedirects(false).followSslRedirects(false).build().newCall(new Request.Builder().url(url).headers(Headers.of(header)).build()).execute().headers().toMultimap());
|
||||
}
|
||||
public static Map<String, List<String>> getLocationHeader(String url, Map<String, String> header) throws IOException {
|
||||
return client().newBuilder().followRedirects(false).followSslRedirects(false).build().newCall(new Request.Builder().url(url).headers(Headers.of(header)).build()).execute().headers().toMultimap();
|
||||
}
|
||||
|
||||
public static String getLocation(Map<String, List<String>> headers) {
|
||||
if (headers == null) return null;
|
||||
|
|
|
|||
|
|
@ -1,111 +0,0 @@
|
|||
package com.github.catvod.net;
|
||||
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import okhttp3.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class OkHttpWithCookie {
|
||||
|
||||
public static final String POST = "POST";
|
||||
public static final String GET = "GET";
|
||||
|
||||
private OkHttpClient client;
|
||||
|
||||
|
||||
private static class Loader {
|
||||
static volatile OkHttpWithCookie INSTANCE = new OkHttpWithCookie();
|
||||
}
|
||||
|
||||
private static OkHttpWithCookie get() {
|
||||
return Loader.INSTANCE;
|
||||
}
|
||||
|
||||
public static Response newCall(Request request, CookieJar cookieJar) throws IOException {
|
||||
return client(cookieJar).newCall(request).execute();
|
||||
}
|
||||
|
||||
public static Response newCall(String url, CookieJar cookieJar) throws IOException {
|
||||
return client(cookieJar).newCall(new Request.Builder().url(url).build()).execute();
|
||||
}
|
||||
|
||||
public static Response newCall(String url, Map<String, String> header, CookieJar cookieJar) throws IOException {
|
||||
return client(cookieJar).newCall(new Request.Builder().url(url).headers(Headers.of(header)).build()).execute();
|
||||
}
|
||||
|
||||
public static String string(String url, CookieJar cookieJar) {
|
||||
return string(url, null, cookieJar);
|
||||
}
|
||||
|
||||
public static String string(String url, Map<String, String> header, CookieJar cookieJar) {
|
||||
return string(url, null, header, cookieJar);
|
||||
}
|
||||
|
||||
public static String string(String url, Map<String, String> params, Map<String, String> header, CookieJar cookieJar) {
|
||||
return url.startsWith("http") ? new OkRequest(GET, url, params, header).execute(client(cookieJar)).getBody() : "";
|
||||
}
|
||||
|
||||
public static OkResult get(String url, Map<String, String> params, Map<String, String> header, CookieJar cookieJar) {
|
||||
return new OkRequest(GET, url, params, header).execute(client(cookieJar));
|
||||
}
|
||||
|
||||
public static String post(String url, Map<String, String> params, CookieJar cookieJar) {
|
||||
return post(url, params, null, cookieJar).getBody();
|
||||
}
|
||||
|
||||
public static OkResult post(String url, Map<String, String> params, Map<String, String> header, CookieJar cookieJar) {
|
||||
return new OkRequest(POST, url, params, header).execute(client(cookieJar));
|
||||
}
|
||||
|
||||
public static String post(String url, String json, CookieJar cookieJar) {
|
||||
return post(url, json, null, cookieJar).getBody();
|
||||
}
|
||||
|
||||
public static OkResult post(String url, String json, Map<String, String> header, CookieJar cookieJar) {
|
||||
return new OkRequest(POST, url, json, header).execute(client(cookieJar));
|
||||
}
|
||||
|
||||
public static String getLocation(String url, Map<String, String> header, CookieJar cookieJar) throws IOException {
|
||||
return getLocation(client(cookieJar).newBuilder().followRedirects(false).followSslRedirects(false).build().newCall(new Request.Builder().url(url).headers(Headers.of(header)).build()).execute().headers().toMultimap());
|
||||
}
|
||||
|
||||
public static Map<String, List<String>> getLocationHeader(String url, Map<String, String> header, CookieJar cookieJar) throws IOException {
|
||||
return client(cookieJar).newBuilder().followRedirects(false).followSslRedirects(false).build().newCall(new Request.Builder().url(url).headers(Headers.of(header)).build()).execute().headers().toMultimap();
|
||||
}
|
||||
|
||||
public static String getLocation(Map<String, List<String>> headers) {
|
||||
if (headers == null) return null;
|
||||
if (headers.containsKey("location")) return headers.get("location").get(0);
|
||||
if (headers.containsKey("Location")) return headers.get("Location").get(0);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static OkHttpClient build(CookieJar cookieJar) {
|
||||
if (get().client != null) return get().client;
|
||||
return get().client = getBuilder(cookieJar).build();
|
||||
}
|
||||
|
||||
private static OkHttpClient.Builder getBuilder(CookieJar cookieJar) {
|
||||
return new OkHttpClient.Builder().cookieJar(cookieJar).dns(safeDns()).connectTimeout(30, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS).hostnameVerifier((hostname, session) -> true).sslSocketFactory(new SSLCompat(), SSLCompat.TM);
|
||||
}
|
||||
|
||||
private static OkHttpClient client(CookieJar cookieJar) {
|
||||
try {
|
||||
return Objects.requireNonNull(Spider.client());
|
||||
} catch (Throwable e) {
|
||||
return build(cookieJar);
|
||||
}
|
||||
}
|
||||
|
||||
private static Dns safeDns() {
|
||||
try {
|
||||
return Objects.requireNonNull(Spider.safeDns());
|
||||
} catch (Throwable e) {
|
||||
return Dns.SYSTEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -50,16 +50,15 @@ public class Ali extends Spider {
|
|||
* 獲取詳情內容視頻播放來源(多 shared_link)
|
||||
*
|
||||
* @param ids share_link 集合
|
||||
* @param i
|
||||
* @return 詳情內容視頻播放來源
|
||||
*/
|
||||
public String detailContentVodPlayFrom(List<String> ids, int index) {
|
||||
public String detailContentVodPlayFrom(List<String> ids) {
|
||||
List<String> playFrom = new ArrayList<>();
|
||||
// if (ids.size() < 2) return TextUtils.join("$$$", Arrays.asList("轉存原畫", "分享原畫", "代理普畫"));
|
||||
if (ids.size() < 2) return TextUtils.join("$$$", Arrays.asList("轉存原畫", "分享原畫", "代理普畫"));
|
||||
for (int i = 1; i <= ids.size(); i++) {
|
||||
playFrom.add(String.format(Locale.getDefault(), "轉存原畫#%02d%02d", i,index));
|
||||
playFrom.add(String.format(Locale.getDefault(), "分享原畫#%02d%02d", i,index));
|
||||
playFrom.add(String.format(Locale.getDefault(), "代理普畫#%02d%02d", i,index));
|
||||
playFrom.add(String.format(Locale.getDefault(), "轉存原畫#%02d", i));
|
||||
playFrom.add(String.format(Locale.getDefault(), "分享原畫#%02d", i));
|
||||
playFrom.add(String.format(Locale.getDefault(), "代理普畫#%02d", i));
|
||||
}
|
||||
return TextUtils.join("$$$", playFrom);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,23 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Util;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
|
@ -25,7 +29,7 @@ public class AppYsV2 extends Spider {
|
|||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
super.init(context,extend);
|
||||
super.init(context, extend);
|
||||
try {
|
||||
extInfos = extend.split("###");
|
||||
} catch (Exception ignored) {
|
||||
|
|
@ -361,7 +365,7 @@ public class AppYsV2 extends Spider {
|
|||
for (int i = 0; i < array.length(); i++) {
|
||||
strings.add(array.getString(i));
|
||||
}
|
||||
return StringUtils.join(strings, ",");
|
||||
return TextUtils.join(",", strings);
|
||||
} catch (JSONException e) {
|
||||
return "";
|
||||
}
|
||||
|
|
@ -550,7 +554,11 @@ public class AppYsV2 extends Spider {
|
|||
playFlags.add(flag);
|
||||
playUrls.add(from.getString("url"));
|
||||
String purl = from.optString("parse_api").trim();
|
||||
ArrayList<String> parseUrls = parseUrlMap.get(flag)==null?new ArrayList<>():parseUrlMap.get(flag);
|
||||
ArrayList<String> parseUrls = parseUrlMap.get(flag);
|
||||
if (parseUrls == null) {
|
||||
parseUrls = new ArrayList<>();
|
||||
parseUrlMap.put(flag, parseUrls);
|
||||
}
|
||||
if (!purl.isEmpty() && !parseUrls.contains(purl)) parseUrls.add(purl);
|
||||
}
|
||||
} else if (URL.contains("xgapp")) {
|
||||
|
|
@ -573,7 +581,11 @@ public class AppYsV2 extends Spider {
|
|||
playFlags.add(flag);
|
||||
playUrls.add(from.getString("url"));
|
||||
String purl = from.optString("parse_api").trim();
|
||||
ArrayList<String> parseUrls = parseUrlMap.get(flag)==null?new ArrayList<>():parseUrlMap.get(flag);
|
||||
ArrayList<String> parseUrls = parseUrlMap.get(flag);
|
||||
if (parseUrls == null) {
|
||||
parseUrls = new ArrayList<>();
|
||||
parseUrlMap.put(flag, parseUrls);
|
||||
}
|
||||
if (!purl.isEmpty() && !parseUrls.contains(purl)) parseUrls.add(purl);
|
||||
}
|
||||
} else if (/*urlPattern2.matcher(URL).find()*/URL.contains(".vod")) {
|
||||
|
|
@ -601,7 +613,12 @@ public class AppYsV2 extends Spider {
|
|||
String[] parse2 = from.getJSONObject("player_info").optString("parse2").split(",");
|
||||
parses.addAll(Arrays.asList(parse1));
|
||||
parses.addAll(Arrays.asList(parse2));
|
||||
ArrayList<String> parseUrls = parseUrlMap.get(flag)==null?new ArrayList<>():parseUrlMap.get(flag); for (String purl : parses) {
|
||||
ArrayList<String> parseUrls = parseUrlMap.get(flag);
|
||||
if (parseUrls == null) {
|
||||
parseUrls = new ArrayList<>();
|
||||
parseUrlMap.put(flag, parseUrls);
|
||||
}
|
||||
for (String purl : parses) {
|
||||
if (purl.contains("http")) {
|
||||
Matcher matcher = parsePattern1.matcher(purl);
|
||||
if (matcher.find()) {
|
||||
|
|
@ -664,11 +681,11 @@ public class AppYsV2 extends Spider {
|
|||
}
|
||||
}
|
||||
playFlags.add(flag);
|
||||
playUrls.add(StringUtils.join(urls, "#"));
|
||||
playUrls.add(TextUtils.join("#", urls));
|
||||
}
|
||||
}
|
||||
vod.put("vod_play_from", StringUtils.join(playFlags, "$$$"));
|
||||
vod.put("vod_play_url", StringUtils.join(playUrls, "$$$"));
|
||||
vod.put("vod_play_from", TextUtils.join("$$$", playFlags));
|
||||
vod.put("vod_play_url", TextUtils.join("$$$", playUrls));
|
||||
}
|
||||
|
||||
// ######视频地址
|
||||
|
|
@ -765,7 +782,7 @@ public class AppYsV2 extends Spider {
|
|||
} else if (jsonPlayData.has("User-Agent")) {
|
||||
ua = jsonPlayData.optString("User-Agent", "");
|
||||
}
|
||||
if (!ua.trim().isEmpty()) {
|
||||
if (ua.trim().length() > 0) {
|
||||
headers.put("User-Agent", " " + ua);
|
||||
}
|
||||
String referer = "";
|
||||
|
|
@ -774,7 +791,7 @@ public class AppYsV2 extends Spider {
|
|||
} else if (jsonPlayData.has("Referer")) {
|
||||
referer = jsonPlayData.optString("Referer", "");
|
||||
}
|
||||
if (!referer.trim().isEmpty()) {
|
||||
if (referer.trim().length() > 0) {
|
||||
headers.put("Referer", " " + referer);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,107 +0,0 @@
|
|||
package com.github.catvod.spider
|
||||
|
||||
import android.content.Context
|
||||
import android.text.TextUtils
|
||||
import com.github.catvod.api.BaiduDrive
|
||||
import com.github.catvod.api.BaiduDrive.getPlayFormatList
|
||||
import com.github.catvod.api.BaiduDrive.getVod
|
||||
import com.github.catvod.api.BaiduDrive.playerContent
|
||||
import com.github.catvod.api.BaiduDrive.setCookie
|
||||
import com.github.catvod.bean.Result
|
||||
import com.github.catvod.bean.Vod
|
||||
import com.github.catvod.crawler.Spider
|
||||
import com.github.catvod.crawler.SpiderDebug
|
||||
import com.github.catvod.utils.Json
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author ColaMint & Adam & FongMi
|
||||
*/
|
||||
class BaiDuPan : Spider() {
|
||||
@Throws(Exception::class)
|
||||
override fun init(context: Context?, extend: String) {
|
||||
setCookie(extend)
|
||||
}
|
||||
|
||||
/**
|
||||
* ids 為 share_link
|
||||
* @param ids
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Throws(Exception::class)
|
||||
override fun detailContent(ids: MutableList<String>): String? {
|
||||
var vod: Vod? = null;
|
||||
runBlocking {
|
||||
vod = getVod(ids[0])
|
||||
}
|
||||
return Result.string(vod);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun playerContent(flag: String, id: String, vipFlags: MutableList<String?>?): String {
|
||||
var content = ""
|
||||
runBlocking {
|
||||
content = playerContent(Json.safeObject(com.github.catvod.utils.Util.base64Decode(id)), flag)
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
/**
|
||||
* 獲取詳情內容視頻播放來源(多 shared_link)
|
||||
*
|
||||
* @param ids share_link 集合
|
||||
* @param i
|
||||
* @return 詳情內容視頻播放來源
|
||||
*/
|
||||
fun detailContentVodPlayFrom(ids: MutableList<String?>, index: Int): String? {
|
||||
val playFrom: MutableList<String?> = ArrayList<String?>()
|
||||
|
||||
/* if (ids.size() < 2){
|
||||
return TextUtils.join("$$$", BaiduDrive.get().getPlayFormatList());
|
||||
}*/
|
||||
for (i in 1..ids.size) {
|
||||
playFrom.add( String.format(Locale.getDefault(), "BD原画" + "#%02d_%02d", i, index))
|
||||
/* for (s in getPlayFormatList()) {
|
||||
playFrom.add(String.format(Locale.getDefault(), "BD" + s + "#%02d%02d", i, index))
|
||||
}*/
|
||||
}
|
||||
return TextUtils.join("$$$", playFrom)
|
||||
}
|
||||
|
||||
/**
|
||||
* 獲取詳情內容視頻播放地址(多 share_link)
|
||||
*
|
||||
* @param ids share_link 集合
|
||||
* @return 詳情內容視頻播放地址
|
||||
*/
|
||||
|
||||
fun detailContentVodPlayUrl(ids: List<String>): String? {
|
||||
val playUrl: MutableList<String?> = ArrayList<String?>()
|
||||
for (id in ids) {
|
||||
try {
|
||||
playUrl.add(getVod(id).getVodPlayUrl())
|
||||
} catch (e: Exception) {
|
||||
SpiderDebug.log("获取播放地址出错:" + e.message)
|
||||
playUrl.add("")
|
||||
}
|
||||
}
|
||||
return TextUtils.join("$$$", playUrl)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
var URL_START = "https://pan.baidu.com"
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun proxy(params: MutableMap<String, String>): Array<Any> {
|
||||
val type = params["type"]
|
||||
if ("video" == type) return BaiduDrive.proxyVideo(params)
|
||||
//if ("sub".equals(type)) return AliYun.get().proxySub(params);
|
||||
return arrayOf<Any>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class BiXin extends Cloud {
|
||||
private static final String siteUrl = "https://www.bixbiy.com/";
|
||||
|
||||
private final String hostUrl = siteUrl;
|
||||
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
return header;
|
||||
}
|
||||
|
||||
private Map<String, String> getHeaderWithCookie() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
header.put("cookie", "esc_search_captcha=1; result=43");
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
|
||||
super.init(context, extend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
String temp = siteUrl + "api/discussions?include=user%2ClastPostedUser%2Ctags%2Ctags.parent%2CfirstPost&sort&page%5Boffset%5D=0";
|
||||
|
||||
String resultStr = OkHttp.string(temp, getHeader());
|
||||
|
||||
classes.add(new Class("mv", "影视"));
|
||||
|
||||
return Result.string(classes, parseVodListFromDoc(resultStr));
|
||||
}
|
||||
|
||||
private List<Vod> parseVodListFromDoc(String resultStr) {
|
||||
JsonObject json = Json.safeObject(resultStr);
|
||||
JsonArray arrays = json.get("data").getAsJsonArray();
|
||||
|
||||
List<Vod> list = new ArrayList<>();
|
||||
for (JsonElement array : arrays) {
|
||||
JsonObject data = array.getAsJsonObject();
|
||||
String vodId = data.get("id").getAsString();
|
||||
String vodPic = "";
|
||||
JsonObject attributes = data.get("attributes").getAsJsonObject();
|
||||
String title = attributes.get("title").getAsString();
|
||||
String vodRemarks = "";
|
||||
String vodName = "";
|
||||
if (title.contains("(")) {
|
||||
vodName = title.split("(")[0];
|
||||
vodRemarks = title.split("(")[1];
|
||||
} else {
|
||||
vodName = title;
|
||||
vodRemarks = title;
|
||||
}
|
||||
|
||||
list.add(new Vod(vodId, vodName, vodPic, vodRemarks));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
int pageSize = 20;
|
||||
String temp = siteUrl +//+ "api/discussions?include=user%2ClastPostedUser%2Ctags%2Ctags.parent%2CfirstPost&filter%5Btag%5D=" + tid + "&sort&page%5Boffset%5D=" + (Integer.parseInt(pg) - 1) * pageSize;
|
||||
"api/discussions?include=user%2ClastPostedUser%2Ctags%2Ctags.parent%2CfirstPost%2Cuser.userBadges%2Cuser.userBadges.badge&filter%5Btag%5D=" + tid + "&sort&page%5Boffset%5D=" + (Integer.parseInt(pg) - 1) * pageSize;
|
||||
String resultStr = OkHttp.string(temp, getHeader());
|
||||
List<Vod> list = parseVodListFromDoc(resultStr);
|
||||
int total = (Integer.parseInt(pg) + 1) * 20;
|
||||
return Result.get().vod(list).page(Integer.parseInt(pg), Integer.parseInt(pg) + 1, pageSize, total).string();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
String vodId = ids.get(0);
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl + "d/" + vodId, getHeader()));
|
||||
|
||||
Vod item = new Vod();
|
||||
item.setVodId(vodId);
|
||||
item.setVodName(doc.selectFirst(" div.container > h1").text());
|
||||
// item.setVodPic(doc.selectFirst(" div.Post-body > p > img").attr("src"));
|
||||
|
||||
|
||||
List<String> shareLinks = new ArrayList<>();
|
||||
for (Element element : doc.select("div.Post-body > p > a")) {
|
||||
if (element.attr("href").contains(YiDongYun.URL_START)) {
|
||||
shareLinks.add(element.attr("href").trim());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
item.setVodPlayUrl(super.detailContentVodPlayUrl(shareLinks));
|
||||
item.setVodPlayFrom(super.detailContentVodPlayFrom(shareLinks));
|
||||
|
||||
return Result.string(item);
|
||||
}
|
||||
|
||||
private String getStrByRegex(Pattern pattern, String str) {
|
||||
Matcher matcher = pattern.matcher(str);
|
||||
if (matcher.find()) return matcher.group(1).trim();
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
return searchContent(key, "1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick, String pg) throws Exception {
|
||||
return searchContent(key, pg);
|
||||
}
|
||||
|
||||
private String searchContent(String key, String pg) {
|
||||
int pageSize = 20;
|
||||
String temp = siteUrl + "api/discussions?include=user%2ClastPostedUser%2CmostRelevantPost%2CmostRelevantPost.user%2Ctags%2Ctags.parent%2CfirstPost&filter%5Bq%5D=" + URLEncoder.encode(key) + "&sort&page%5Boffset%5D=" + (Integer.parseInt(pg) - 1) * pageSize;
|
||||
|
||||
String resultStr = OkHttp.string(temp, getHeader());
|
||||
|
||||
|
||||
return Result.string(parseVodListFromDoc(resultStr));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,259 +0,0 @@
|
|||
package com.github.catvod.spider;/*
|
||||
* @File : changzhang.js
|
||||
* @Author : jade
|
||||
* @Date : 2024/2/2 16:02
|
||||
* @Email : jadehh@1ive.com
|
||||
* @Software : Samples
|
||||
* @Desc :
|
||||
*/
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Filter;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.AESEncryption;
|
||||
import com.github.catvod.utils.Notify;
|
||||
import com.github.catvod.utils.ProxyVideo;
|
||||
import com.github.catvod.utils.Util;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.json.JSONObject;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ChangZhang extends Spider {
|
||||
|
||||
private String siteUrl = "https://www.czys.pro";
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
super.init(context, extend);
|
||||
Document doc = Jsoup.parse(OkHttp.string(extend));
|
||||
|
||||
siteUrl = doc.select("h2 > a").attr("href");
|
||||
|
||||
}
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("Cookie", "myannoun=1; Hm_lvt_0653ba1ead8a9aabff96252e70492497=2718862211; Hm_lvt_06341c948291d8e90aac72f9d64905b3=2718862211; Hm_lvt_07305e6f6305a01dd93218c7fe6bc9c3=2718862211; Hm_lpvt_07305e6f6305a01dd93218c7fe6bc9c3=2718867254; Hm_lpvt_06341c948291d8e90aac72f9d64905b3=2718867254; Hm_lpvt_0653ba1ead8a9aabff96252e70492497=2718867254");
|
||||
header.put("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");
|
||||
header.put("Connection", "keep-alive");
|
||||
URI uri = URI.create(siteUrl);
|
||||
header.put("Host", uri.getHost());
|
||||
header.put("Referer", siteUrl + "/");
|
||||
return header;
|
||||
}
|
||||
|
||||
private Map<String, String> getIframeHeader(String url) {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("Cookie", "myannoun=1; Hm_lvt_0653ba1ead8a9aabff96252e70492497=2718862211; Hm_lvt_06341c948291d8e90aac72f9d64905b3=2718862211; Hm_lvt_07305e6f6305a01dd93218c7fe6bc9c3=2718862211; Hm_lpvt_07305e6f6305a01dd93218c7fe6bc9c3=2718867254; Hm_lpvt_06341c948291d8e90aac72f9d64905b3=2718867254; Hm_lpvt_0653ba1ead8a9aabff96252e70492497=2718867254");
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
header.put("Connection", "keep-alive");
|
||||
URI uri = URI.create(url);
|
||||
header.put("Host", uri.getHost());
|
||||
header.put("Sec-Fetch-Dest", "iframe");
|
||||
header.put("sec-fetch-mode", "navigate");
|
||||
header.put("Referer", siteUrl + "/");
|
||||
return header;
|
||||
}
|
||||
|
||||
private Map<String, String> getVideoHeader(String url) {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
|
||||
header.put("Accept", "*/*");
|
||||
header.put("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7,de;q=0.6");
|
||||
header.put("Cache-Control", "no-cache");
|
||||
header.put("Connection", "keep-alive");
|
||||
header.put("Pragma", "no-cache");
|
||||
URI uri = URI.create(url);
|
||||
header.put("Host", uri.getHost());
|
||||
header.put("Sec-Fetch-Dest", "video");
|
||||
header.put("Sec-Fetch-Mode", "no-cors");
|
||||
header.put("Sec-Fetch-Site", "cross-site");
|
||||
header.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36");
|
||||
/* header.put("sec-ch-ua", "\"Chromium\";v=\"124\", \"Google Chrome\";v=\"124\", \"Not-A.Brand\";v=\"99\"");
|
||||
header.put("sec-ch-ua-mobile", "?0");
|
||||
header.put("sec-ch-ua-platform", "\"Windows\"");*/
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) throws Exception {
|
||||
|
||||
List<Vod> list = new ArrayList<>();
|
||||
List<Class> classes = new ArrayList<>();
|
||||
LinkedHashMap<String, List<Filter>> filters = new LinkedHashMap<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl));
|
||||
|
||||
for (Element div : doc.select(".navlist > li ")) {
|
||||
classes.add(new Class(div.select(" a").attr("href"), div.select(" a").text()));
|
||||
}
|
||||
|
||||
getVods(list, doc);
|
||||
return Result.string(classes, list);
|
||||
}
|
||||
|
||||
private void getVods(List<Vod> list, Document doc) {
|
||||
for (Element div : doc.select(".bt_img.mi_ne_kd > ul >li")) {
|
||||
String id = div.select(".dytit > a").attr("href");
|
||||
String name = div.select(".dytit > a").text();
|
||||
String pic = div.select("img").attr("data-original");
|
||||
if (pic.isEmpty()) pic = div.select("img").attr("src");
|
||||
String remark = div.select(".hdinfo > span").text();
|
||||
|
||||
list.add(new Vod(id, name, pic, remark));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
String target = siteUrl + tid + "/page/" + pg;
|
||||
//String filters = extend.get("filters");
|
||||
String html = OkHttp.string(target);
|
||||
Document doc = Jsoup.parse(html);
|
||||
getVods(list, doc);
|
||||
String total = "" + Integer.MAX_VALUE;
|
||||
return Result.get().vod(list).page(Integer.parseInt(pg), Integer.parseInt(total) / 25 + 1, 25, Integer.parseInt(total)).string();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
|
||||
Document doc = Jsoup.parse(OkHttp.string(ids.get(0), getHeader()));
|
||||
|
||||
Elements sources = doc.select("div.paly_list_btn > a");
|
||||
StringBuilder vod_play_url = new StringBuilder();
|
||||
String vod_play_from = "厂长" + "$$$";
|
||||
|
||||
for (int i = 0; i < sources.size(); i++) {
|
||||
String href = sources.get(i).attr("href");
|
||||
String text = sources.get(i).text();
|
||||
vod_play_url.append(text).append("$").append(href);
|
||||
boolean notLastEpisode = i < sources.size() - 1;
|
||||
vod_play_url.append(notLastEpisode ? "#" : "$$$");
|
||||
}
|
||||
|
||||
String title = doc.select(" div.dytext.fl > div > h1").text();
|
||||
String classifyName = doc.select(".moviedteail_list > li:nth-child(1) > a").text();
|
||||
String year = doc.select(".moviedteail_list > li:nth-child(3) > a").text();
|
||||
String area = doc.select(".moviedteail_list > li:nth-child(2) > a").text();
|
||||
String remark = doc.select(".yp_context").text();
|
||||
String vodPic = doc.select(" div.dyxingq > div > div.dyimg.fl > img").attr("src");
|
||||
|
||||
String director = doc.select(".moviedteail_list > li:nth-child(6) > a").text();
|
||||
|
||||
String actor = doc.select(".moviedteail_list > li:nth-child(8) > a").text();
|
||||
|
||||
String brief = doc.select(".yp_context").text();
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(ids.get(0));
|
||||
vod.setVodYear(year);
|
||||
vod.setVodName(title);
|
||||
vod.setVodArea(area);
|
||||
vod.setVodActor(actor);
|
||||
vod.setVodPic(vodPic);
|
||||
vod.setVodRemarks(remark);
|
||||
vod.setVodContent(brief);
|
||||
vod.setVodDirector(director);
|
||||
vod.setTypeName(classifyName);
|
||||
vod.setVodPlayFrom(vod_play_from);
|
||||
vod.setVodPlayUrl(vod_play_url.toString());
|
||||
return Result.string(vod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
String searchUrl = siteUrl + "/daoyongjiekoshibushiyoubing?q=";
|
||||
String html = OkHttp.string(searchUrl + key);
|
||||
if (html.contains("Just a moment")) {
|
||||
Notify.show("厂长资源需要人机验证");
|
||||
}
|
||||
Document document = Jsoup.parse(html);
|
||||
List<Vod> list = new ArrayList<>();
|
||||
getVods(list, document);
|
||||
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
String content = OkHttp.string(id, getHeader());
|
||||
Document document = Jsoup.parse(content);
|
||||
Elements iframe = document.select("iframe");
|
||||
if (!iframe.isEmpty()) {
|
||||
String videoContent = OkHttp.string(iframe.get(0).attr("src"), getIframeHeader(iframe.get(0).attr("src")));
|
||||
|
||||
|
||||
Matcher matcher2 = Pattern.compile("result_v2 =(.*?);").matcher(videoContent);
|
||||
String json2 = matcher2.find() ? matcher2.group(1) : "";
|
||||
org.json.JSONObject jsonObject = new JSONObject(json2);
|
||||
String encodedStr = jsonObject.getString("data");
|
||||
String realUrl = new String(new BigInteger(StringUtils.reverse(encodedStr), 16).toByteArray());
|
||||
|
||||
String temp = decodeStr(realUrl);
|
||||
Map<String, String> header = getVideoHeader(temp);
|
||||
return Result.get().url(ProxyVideo.buildCommonProxyUrl(temp, header)).string();
|
||||
} else {
|
||||
for (Element script : document.select("script")) {
|
||||
String scriptText = script.html();
|
||||
if (scriptText.contains("wp_nonce")) {
|
||||
String reg = "var(.*?)=\"(.*?)\"";
|
||||
Pattern pattern = Pattern.compile(reg);
|
||||
Matcher matcher = pattern.matcher(scriptText);
|
||||
|
||||
if (matcher.find()) {
|
||||
String data = matcher.group(2);
|
||||
String result = dncry(data);
|
||||
String regex = "url:.*?['\"](.*?)['\"]";
|
||||
Pattern pattern1 = Pattern.compile(regex);
|
||||
Matcher matcher1 = pattern1.matcher(result);
|
||||
if (matcher1.find()) {
|
||||
String playUrl = matcher1.group(0).replace("\"", "").replace("url:", "").trim();
|
||||
return Result.get().url(playUrl).string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String dncry(String data) {
|
||||
String kc8a64 = "336460fdcb76a597";
|
||||
String iv = "1234567890983456";
|
||||
|
||||
return AESEncryption.decrypt(data, kc8a64, iv,AESEncryption.CBC_PKCS_7_PADDING);
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
String decodeStr(String _0x267828) {
|
||||
int _0x5cd2b5 = (_0x267828.length() - 7) / 2;
|
||||
String _0x2191ed = _0x267828.substring(0, _0x5cd2b5);
|
||||
String _0x35a256 = _0x267828.substring(_0x5cd2b5 + 7);
|
||||
return _0x2191ed + _0x35a256;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,192 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import com.github.catvod.api.Pan123Api;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import static com.github.catvod.api.TianyiApi.URL_CONTAIN;
|
||||
|
||||
/**
|
||||
* @author ColaMint & Adam & FongMi
|
||||
*/
|
||||
public class Cloud extends Spider {
|
||||
private Quark quark = null;
|
||||
/* private Ali ali = null;*/
|
||||
private UC uc = null;
|
||||
private TianYi tianYi = null;
|
||||
private YiDongYun yiDongYun = null;
|
||||
private BaiDuPan baiDuPan = null;
|
||||
private Pan123 pan123 = null;
|
||||
private static final Map<String, ImmutablePair<List<String>, List<String>>> resultMap = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
JsonObject ext = Json.safeObject(extend);
|
||||
quark = new Quark();
|
||||
uc = new UC();
|
||||
/* ali = new Ali();*/
|
||||
tianYi = new TianYi();
|
||||
yiDongYun = new YiDongYun();
|
||||
baiDuPan = new BaiDuPan();
|
||||
pan123 = new Pan123();
|
||||
boolean first = Objects.nonNull(ext);
|
||||
quark.init(context, first && ext.has("cookie") ? ext.get("cookie").getAsString() : "");
|
||||
uc.init(context, first && ext.has("uccookie") ? ext.get("uccookie").getAsString() : "");
|
||||
/* ali.init(context, first && ext.has("token") ? ext.get("token").getAsString() : "");*/
|
||||
tianYi.init(context, first && ext.has("tianyicookie") ? ext.get("tianyicookie").getAsString() : "");
|
||||
yiDongYun.init(context, "");
|
||||
baiDuPan.init(context, "");
|
||||
pan123.init(context, "");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> shareUrl) throws Exception {
|
||||
SpiderDebug.log("cloud detailContent shareUrl:" + Json.toJson(shareUrl));
|
||||
|
||||
/* if (shareUrl.get(0).matches(Util.patternAli)) {
|
||||
return ali.detailContent(shareUrl);
|
||||
} else */
|
||||
if (shareUrl.get(0).matches(Util.patternQuark)) {
|
||||
return quark.detailContent(shareUrl);
|
||||
} else if (shareUrl.get(0).matches(Util.patternUC)) {
|
||||
return uc.detailContent(shareUrl);
|
||||
} else if (shareUrl.get(0).contains(URL_CONTAIN)) {
|
||||
return tianYi.detailContent(shareUrl);
|
||||
} else if (shareUrl.get(0).contains(YiDongYun.URL_START)) {
|
||||
return yiDongYun.detailContent(shareUrl);
|
||||
} else if (shareUrl.get(0).contains(BaiDuPan.URL_START)) {
|
||||
return baiDuPan.detailContent(shareUrl);
|
||||
} else if (shareUrl.get(0).matches(Pan123Api.regex)) {
|
||||
SpiderDebug.log("Pan123Api shareUrl:" + Json.toJson(shareUrl));
|
||||
return pan123.detailContent(shareUrl);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
SpiderDebug.log("cloud playerContent flag:" + flag + " id:" + id);
|
||||
|
||||
if (flag.contains("quark")) {
|
||||
return quark.playerContent(flag, id, vipFlags);
|
||||
} else if (flag.contains("uc")) {
|
||||
return uc.playerContent(flag, id, vipFlags);
|
||||
} else if (flag.contains("天意")) {
|
||||
return tianYi.playerContent(flag, id, vipFlags);
|
||||
} else if (flag.contains("移动")) {
|
||||
return yiDongYun.playerContent(flag, id, vipFlags);
|
||||
}/* else {
|
||||
return ali.playerContent(flag, id, vipFlags);
|
||||
}*/ else if (flag.contains("BD")) {
|
||||
return baiDuPan.playerContent(flag, id, vipFlags);
|
||||
} else if (flag.contains("pan123")) {
|
||||
return pan123.playerContent(flag, id, vipFlags);
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
protected String detailContentVodPlayFrom(List<String> shareLinks) {
|
||||
ImmutablePair<List<String>, List<String>> pairs = resultMap.get(Util.MD5(Json.toJson(shareLinks)));
|
||||
if (pairs != null && pairs.left != null && !pairs.left.isEmpty()) {
|
||||
return TextUtils.join("$$$", pairs.right);
|
||||
}
|
||||
|
||||
getPlayFromAndUrl(shareLinks);
|
||||
pairs = resultMap.get(Util.MD5(Json.toJson(shareLinks)));
|
||||
if (pairs != null && pairs.left != null && !pairs.left.isEmpty()) {
|
||||
return TextUtils.join("$$$", pairs.right);
|
||||
}
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
protected String detailContentVodPlayUrl(List<String> shareLinks) {
|
||||
ImmutablePair<List<String>, List<String>> pairs = resultMap.get(Util.MD5(Json.toJson(shareLinks)));
|
||||
if (pairs != null && pairs.left != null && !pairs.left.isEmpty()) {
|
||||
return TextUtils.join("$$$", pairs.left);
|
||||
}
|
||||
|
||||
getPlayFromAndUrl(shareLinks);
|
||||
pairs = resultMap.get(Util.MD5(Json.toJson(shareLinks)));
|
||||
if (pairs != null && pairs.left != null && !pairs.left.isEmpty()) {
|
||||
return TextUtils.join("$$$", pairs.left);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
//同時获取from 和url ,放入缓存,只要一个函数执行就行,避免重复执行
|
||||
private void getPlayFromAndUrl(List<String> shareLinks) {
|
||||
ExecutorService service = Executors.newFixedThreadPool(4);
|
||||
try { //首先清空缓存,避免太多缓存
|
||||
resultMap.clear();
|
||||
List<String> urls = new ArrayList<>();
|
||||
List<String> froms = new ArrayList<>();
|
||||
|
||||
List<Future<ImmutablePair<String, String>>> futures = new ArrayList<>();
|
||||
int i = 0;
|
||||
for (String shareLink : shareLinks) {
|
||||
|
||||
int finalI = ++i;
|
||||
futures.add(service.submit(() -> {
|
||||
|
||||
String url = "";
|
||||
String from = "";
|
||||
if (shareLink.matches(Util.patternUC)) {
|
||||
url = uc.detailContentVodPlayUrl(List.of(shareLink));
|
||||
from = uc.detailContentVodPlayFrom(List.of(shareLink), finalI);
|
||||
} else if (shareLink.matches(Util.patternQuark)) {
|
||||
url = quark.detailContentVodPlayUrl(List.of(shareLink));
|
||||
from = quark.detailContentVodPlayFrom(List.of(shareLink), finalI);
|
||||
}/* else if (shareLink.matches(Util.patternAli)) {
|
||||
urls.add(ali.detailContentVodPlayUrl(List.of(shareLink)));
|
||||
} */ else if (shareLink.contains(URL_CONTAIN)) {
|
||||
url = tianYi.detailContentVodPlayUrl(List.of(shareLink));
|
||||
from = tianYi.detailContentVodPlayFrom(List.of(shareLink), finalI);
|
||||
} else if (shareLink.contains(YiDongYun.URL_START)) {
|
||||
url = yiDongYun.detailContentVodPlayUrl(List.of(shareLink));
|
||||
from = yiDongYun.detailContentVodPlayFrom(List.of(shareLink), finalI);
|
||||
} else if (shareLink.contains(BaiDuPan.URL_START)) {
|
||||
url = baiDuPan.detailContentVodPlayUrl(List.of(shareLink));
|
||||
from = baiDuPan.detailContentVodPlayFrom(List.of(shareLink), finalI);
|
||||
} else if (shareLink.matches(Pan123Api.regex)) {
|
||||
url = pan123.detailContentVodPlayUrl(List.of(shareLink));
|
||||
from = pan123.detailContentVodPlayFrom(List.of(shareLink), finalI);
|
||||
}
|
||||
return new ImmutablePair<>(url, from);
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
for (Future<ImmutablePair<String, String>> future : futures) {
|
||||
//只有连接不为空才放入进去
|
||||
if (StringUtils.isNoneBlank(future.get().left)) {
|
||||
urls.add(future.get().left);
|
||||
froms.add(future.get().right);
|
||||
}
|
||||
|
||||
}
|
||||
resultMap.put(Util.MD5(Json.toJson(shareLinks)), new ImmutablePair<>(urls, froms));
|
||||
|
||||
SpiderDebug.log("---urls:" + Json.toJson(urls));
|
||||
SpiderDebug.log("---froms:" + Json.toJson(froms));
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log("获取异步结果出错:" + e);
|
||||
} finally {
|
||||
service.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.AESEncryption;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class DaGongRen extends Spider {
|
||||
|
||||
private static final String siteUrl = "https://dagongren1.com";
|
||||
private static final String cateUrl = siteUrl + "/list/";
|
||||
private static final String detailUrl = siteUrl + "/play/";
|
||||
private static final String playUrl = siteUrl + "/play/";
|
||||
private static final String searchUrl = siteUrl + "/search--------------.html?wd=";
|
||||
|
||||
private HashMap<String, String> getHeaders() {
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", Util.CHROME);
|
||||
headers.put("Host", "dagongren1.com");
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
List<Class> classes = new ArrayList<>();
|
||||
String[] typeIdList = {"dianying","dianshiju","zongyi","dongman","jilupian","lunlipian"};
|
||||
String[] typeNameList = {"电影","连续剧","综艺","动漫","纪录片","福利"};
|
||||
for (int i = 0; i < typeNameList.length; i++) {
|
||||
classes.add(new Class(typeIdList[i], typeNameList[i]));
|
||||
}
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeaders()));
|
||||
for (Element element : doc.select("a.vodlist_thumb")) {
|
||||
try {
|
||||
String pic = element.attr("data-original");
|
||||
String url = element.attr("href");
|
||||
String name = element.attr("title");
|
||||
if (!pic.startsWith("http")) {
|
||||
pic = siteUrl + pic;
|
||||
}
|
||||
String id = url.split("/")[2];
|
||||
list.add(new Vod(id, name, pic));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
return Result.string(classes, list);
|
||||
}
|
||||
|
||||
public String MD5(String string) {
|
||||
// 创建 MD5 实例
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
// 计算 MD5 哈希值
|
||||
byte[] hashBytes = md.digest(string.getBytes());
|
||||
|
||||
// 将字节数组转换为十六进制字符串表示
|
||||
StringBuilder hexString = new StringBuilder();
|
||||
for (byte hashByte : hashBytes) {
|
||||
String hex = Integer.toHexString(0xff & hashByte);
|
||||
if (hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
|
||||
// 输出加密后的 MD5 字符串
|
||||
System.out.println("MD5 加密: " + hexString.toString());
|
||||
return hexString.toString();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
tid = "/show-" + tid + "--------" + pg + "---.html";
|
||||
String target = siteUrl + tid;
|
||||
Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
|
||||
for (Element element : doc.select("a.vodlist_thumb")) {
|
||||
try {
|
||||
String pic = element.attr("data-original");
|
||||
String url = element.attr("href");
|
||||
String name = element.attr("title");
|
||||
if (!pic.startsWith("http")) {
|
||||
pic = siteUrl + pic;
|
||||
}
|
||||
String id = url.split("/")[2];
|
||||
list.add(new Vod(id, name, pic));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
Integer total = (Integer.parseInt(pg) + 1) * 20;
|
||||
return Result.string(Integer.parseInt(pg), Integer.parseInt(pg) + 1, 20, total, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
Document doc = Jsoup.parse(OkHttp.string(detailUrl.concat(ids.get(0)), getHeaders()));
|
||||
String name = doc.select("h2.title.margin_0").text();
|
||||
String pic = doc.select("div.play_vlist_thumb").get(0).attr("data-original");
|
||||
// 播放源
|
||||
Elements tabs = doc.select("li.tab-play");
|
||||
Elements list = doc.select("ul.content_playlist");
|
||||
String PlayFrom = "";
|
||||
String PlayUrl = "";
|
||||
for (int i = 0; i < tabs.size(); i++) {
|
||||
String tabName = tabs.get(i).text();
|
||||
if (!"".equals(PlayFrom)) {
|
||||
PlayFrom = PlayFrom + "$$$" + tabName;
|
||||
} else {
|
||||
PlayFrom = PlayFrom + tabName;
|
||||
}
|
||||
Elements li = list.get(i).select("a");
|
||||
String liUrl = "";
|
||||
for (int i1 = 0; i1 < li.size(); i1++) {
|
||||
if (!"".equals(liUrl)) {
|
||||
liUrl = liUrl + "#" + li.get(i1).text() + "$" + li.get(i1).attr("href").replace("/play/","");
|
||||
} else {
|
||||
liUrl = liUrl + li.get(i1).text() + "$" + li.get(i1).attr("href").replace("/play/","");
|
||||
}
|
||||
}
|
||||
if (!"".equals(PlayUrl)) {
|
||||
PlayUrl = PlayUrl + "$$$" + liUrl;
|
||||
} else {
|
||||
PlayUrl = PlayUrl + liUrl;
|
||||
}
|
||||
}
|
||||
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(ids.get(0));
|
||||
vod.setVodPic(siteUrl + pic);
|
||||
vod.setVodName(name);
|
||||
vod.setVodPlayFrom(PlayFrom);
|
||||
vod.setVodPlayUrl(PlayUrl);
|
||||
return Result.string(vod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(searchUrl.concat(URLEncoder.encode(key)), getHeaders()));
|
||||
for (Element element : doc.select("div.searchlist_img")) {
|
||||
try {
|
||||
String pic = element.select("a").attr("data-original");
|
||||
String url = element.select("a").attr("href");
|
||||
String name = element.select("a").attr("title");
|
||||
if (!pic.startsWith("http")) {
|
||||
pic = siteUrl + pic;
|
||||
}
|
||||
String id = url.replace("/video/","").replace(".html","-1-1.html");
|
||||
list.add(new Vod(id, name, pic));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
String target = playUrl.concat(id);
|
||||
Document doc = Jsoup.parse(OkHttp.string(target));
|
||||
String regex = "\"url\\\":\\\"(.*?)\\\",\\\"url_next\\\":";
|
||||
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(doc.html());
|
||||
String url = "";
|
||||
if (matcher.find()) {
|
||||
url = URLDecoder.decode(matcher.group(1), "UTF-8").split("&")[0];
|
||||
}
|
||||
return Result.get().url(url).header(getHeaders()).string();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,439 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.ProxyVideo;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.JsonElement;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Demo for self study
|
||||
* <p>
|
||||
* Source from Author: CatVod
|
||||
*/
|
||||
|
||||
public class Ddrk extends Cloud {
|
||||
|
||||
private static String siteUrl = "https://ddys.pro";
|
||||
|
||||
|
||||
protected JSONObject filterConfig;
|
||||
|
||||
protected Pattern regexCategory = Pattern.compile("/category/(\\S+)/");
|
||||
protected Pattern regexVid = Pattern.compile("https://ddys.pro/(\\S+)/");
|
||||
|
||||
protected Pattern regexPage = Pattern.compile("\\S+/page/(\\S+)\\S+");
|
||||
protected Pattern m = Pattern.compile("\\S+(http\\S+g)");
|
||||
protected Pattern mark = Pattern.compile("\\S+(.*)");
|
||||
|
||||
// protected Pattern t = Pattern.compile("(\\S+)");
|
||||
|
||||
protected static HashMap<String, String> Headers() {
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
headers.put("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");
|
||||
headers.put("Referer", siteUrl);
|
||||
return headers;
|
||||
}
|
||||
|
||||
private static String doReplaceRegex(Pattern pattern, String src) {
|
||||
if (pattern == null) return src;
|
||||
try {
|
||||
Matcher matcher = pattern.matcher(src);
|
||||
if (matcher.find()) {
|
||||
return matcher.group(1).trim();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
return src;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
super.init(context, extend);
|
||||
JsonElement json = Json.parse(extend);
|
||||
String html = OkHttp.string(json.getAsJsonObject().get("site").getAsString());
|
||||
Document doc = Jsoup.parse(html);
|
||||
for (Element element : doc.select("a")) {
|
||||
if (element.text().contains("https")) {
|
||||
siteUrl = element.attr("href");
|
||||
break;
|
||||
}
|
||||
}
|
||||
SpiderDebug.log("ddys =====>" + siteUrl); // js_debug.log
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 爬虫headers
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
protected HashMap<String, String> getHeaders(String url) {
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.62 Safari/537.36");
|
||||
headers.put("Referer", siteUrl);
|
||||
return headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分类数据 + 首页最近更新视频列表数据
|
||||
*
|
||||
* @param filter 是否开启筛选 关联的是 软件设置中 首页数据源里的筛选开关
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
|
||||
List<Vod> vods = new ArrayList<>();
|
||||
String url = siteUrl + '/';
|
||||
Document doc = Jsoup.parse(OkHttp.string(url, getHeaders(url)));
|
||||
Elements elements = doc.select("li.menu-item a");
|
||||
List<Class> classes = new ArrayList<>();
|
||||
|
||||
for (Element ele : elements) {
|
||||
String name = ele.attr("title");
|
||||
String id = ele.attr("href");
|
||||
if (ele.attr("href").contains("category") || ele.attr("href").contains("tag")) {
|
||||
classes.add(new Class(id, name));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 取首页推荐视频列表
|
||||
Elements list = doc.select("div.post-box-container");
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Element vod = list.get(i);
|
||||
String title = vod.selectFirst(".post-box-title > a").text();
|
||||
String id = vod.selectFirst(".post-box-title > a").attr("href");
|
||||
String imageHtml = vod.selectFirst("div.post-box-image").attr("style");
|
||||
String image = "";
|
||||
String regex = "url\\((.*?)\\)";
|
||||
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(imageHtml);
|
||||
if (matcher.find()) {
|
||||
image = matcher.group(1);
|
||||
}
|
||||
vods.add(new Vod(id, title, image));
|
||||
}
|
||||
|
||||
|
||||
return Result.string(classes, vods, filterConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分类信息数据
|
||||
*
|
||||
* @param tid 分类id
|
||||
* @param pg 页数
|
||||
* @param filter 同homeContent方法中的filter
|
||||
* @param extend 筛选参数{k:v, k1:v1}
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
String url = "";
|
||||
try {
|
||||
if (extend != null && extend.size() > 0) {
|
||||
for (Iterator<String> it = extend.keySet().iterator(); it.hasNext(); ) {
|
||||
String key = it.next();
|
||||
String value = extend.get(key);
|
||||
if (value != null && value.length() != 0 && value != " ") {
|
||||
url = siteUrl + "/category/" + tid + "/" + value;
|
||||
} else {
|
||||
url = siteUrl + "/category/" + tid;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
url = tid;
|
||||
}
|
||||
if (pg.equals("1")) {
|
||||
url = url + "/";
|
||||
} else {
|
||||
url = url + "/page/" + pg + "/";
|
||||
}
|
||||
//System.out.println(url);
|
||||
String html = OkHttp.string(url, getHeaders(url));
|
||||
Document doc = Jsoup.parse(html);
|
||||
JSONObject result = new JSONObject();
|
||||
int pageCount = 0;
|
||||
int page = -1;
|
||||
|
||||
// 取页码相关信息
|
||||
Elements pageInfo = doc.select("div.nav-links");
|
||||
if (pageInfo.size() == 0) {
|
||||
page = Integer.parseInt(pg);
|
||||
pageCount = page;
|
||||
} else {
|
||||
for (int i = 0; i < pageInfo.size(); i++) {
|
||||
Element li = pageInfo.get(i);
|
||||
Element a = li.selectFirst("a");
|
||||
if (a == null) continue;
|
||||
String wy = doc.select("div.nav-links a").last().attr("href");
|
||||
String span = doc.select("span.current").text().trim();
|
||||
if (page == -1) {
|
||||
page = Integer.parseInt(span);
|
||||
} else {
|
||||
|
||||
page = 0;
|
||||
}
|
||||
Matcher matcher = regexPage.matcher(wy);
|
||||
if (matcher.find()) {
|
||||
//System.out.println("尾页" + matcher.group(1));
|
||||
pageCount = Integer.parseInt(matcher.group(1));
|
||||
} else {
|
||||
pageCount = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
JSONArray videos = new JSONArray();
|
||||
if (!html.contains("没有找到您想要的结果哦")) {
|
||||
// 取当前分类页的视频列表
|
||||
Elements list = doc.select("div.post-box-container");
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Element vod = list.get(i);
|
||||
String a = vod.selectFirst(".post-box-title a").text();
|
||||
if (a.contains("(")) {
|
||||
String[] item = a.split("\\(");
|
||||
String title = item[0];
|
||||
String remark = item[1].replace(")", "");
|
||||
String cover = doReplaceRegex(m, vod.selectFirst(".post-box-image").attr("style"));
|
||||
|
||||
String id = vod.selectFirst(".post-box-title a").attr("href");
|
||||
JSONObject v = new JSONObject();
|
||||
v.put("vod_id", id);
|
||||
v.put("vod_name", title);
|
||||
v.put("vod_pic", cover);
|
||||
v.put("vod_remarks", remark);
|
||||
videos.put(v);
|
||||
} else {
|
||||
String title = a;
|
||||
String cover = doReplaceRegex(m, vod.selectFirst(".post-box-image").attr("style"));
|
||||
String remark = doReplaceRegex(mark, vod.selectFirst(".post-box-title a").text());
|
||||
Matcher matcher = regexVid.matcher(vod.selectFirst(".post-box-title a").attr("href"));
|
||||
if (!matcher.find()) continue;
|
||||
String id = matcher.group(1);
|
||||
JSONObject v = new JSONObject();
|
||||
v.put("vod_id", id);
|
||||
v.put("vod_name", title);
|
||||
v.put("vod_pic", cover);
|
||||
v.put("vod_remarks", remark);
|
||||
videos.put(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
result.put("page", page);
|
||||
result.put("pagecount", pageCount);
|
||||
result.put("limit", 24);
|
||||
result.put("total", pageCount <= 1 ? videos.length() : pageCount * 24);
|
||||
|
||||
result.put("list", videos);
|
||||
return result.toString();
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频详情信息
|
||||
*
|
||||
* @param ids 视频id
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String detailContent(List<String> ids) {
|
||||
try {
|
||||
// 视频详情url
|
||||
String url = ids.get(0);
|
||||
if (!url.startsWith("http")) {
|
||||
url = siteUrl +"/"+ url + "/";
|
||||
}
|
||||
Document doc = Jsoup.parse(OkHttp.string(url, getHeaders(url)));
|
||||
JSONObject result = new JSONObject();
|
||||
JSONObject vodList = new JSONObject();
|
||||
|
||||
// 取基本数据
|
||||
String cover = doc.select("div.post img").attr("src");
|
||||
String ab = doc.select("h1.post-title").text();
|
||||
if (ab.contains("(")) {
|
||||
String[] b = ab.split("\\(");
|
||||
String title = b[0];
|
||||
String remark = b[1].replace("(", "");
|
||||
vodList.put("vod_name", title);
|
||||
vodList.put("vod_remarks", remark);
|
||||
} else {
|
||||
vodList.put("vod_name", ab);
|
||||
String remark = doc.select("time").text().trim();
|
||||
vodList.put("vod_remarks", "全");
|
||||
}
|
||||
String str2 = doc.select("div.abstract").text().replace(" ", "");
|
||||
String replace = str2.replace("<br>", "");
|
||||
String text = replace.replace("<p></p>", "");
|
||||
Pattern categorys = Pattern.compile("类型:(.*)制");
|
||||
String category = doReplaceRegex(categorys, text);
|
||||
Pattern a = Pattern.compile("年份:(.*)简");
|
||||
String year = doReplaceRegex(a, text);
|
||||
Pattern b = Pattern.compile("地区:(.*)年份");
|
||||
String area = doReplaceRegex(b, text);
|
||||
Pattern c = Pattern.compile("演员:(.*)类");
|
||||
String actor = doReplaceRegex(c, text);
|
||||
Pattern d = Pattern.compile("导演:(.*)演");
|
||||
String director = doReplaceRegex(d, text);
|
||||
Pattern e = Pattern.compile("简介:(.*)");
|
||||
String desc = doReplaceRegex(e, text);
|
||||
|
||||
|
||||
vodList.put("vod_id", ids.get(0));
|
||||
vodList.put("vod_pic", cover);
|
||||
vodList.put("type_name", category);
|
||||
vodList.put("vod_year", year);
|
||||
vodList.put("vod_area", area);
|
||||
vodList.put("vod_actor", actor);
|
||||
vodList.put("vod_director", director);
|
||||
vodList.put("vod_content", desc);
|
||||
Vod.VodPlayBuilder builder = new Vod.VodPlayBuilder();
|
||||
List<String> shareLinks = new ArrayList<>();
|
||||
getVodDetail(doc, builder, "1");
|
||||
|
||||
//多季剧集处理
|
||||
Elements sources = doc.select(".post-page-numbers");
|
||||
if (!sources.isEmpty()) {
|
||||
for (Element source : sources) {
|
||||
if (!source.select("a").isEmpty()) {
|
||||
|
||||
String Purl = source.select("a").attr("href");
|
||||
Document docs = Jsoup.parse(OkHttp.string(Purl, getHeaders(Purl)));
|
||||
getVodDetail(docs, builder, source.text());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Elements clouds = doc.select("p > a");
|
||||
if (!clouds.isEmpty()) {
|
||||
for (Element cloud : clouds) {
|
||||
String cloudUrl = cloud.attr("href");
|
||||
if (!Util.findByRegex(Util.patternQuark, cloudUrl, 0).isBlank() || !Util.findByRegex(Util.patternUC, cloudUrl, 0).isBlank()) {
|
||||
shareLinks.add(cloudUrl);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
String quarkNames = "";
|
||||
String quarkUrls = "";
|
||||
if (!shareLinks.isEmpty()) {
|
||||
quarkUrls = super.detailContentVodPlayUrl(shareLinks);
|
||||
quarkNames = super.detailContentVodPlayFrom(shareLinks);
|
||||
|
||||
}
|
||||
|
||||
Vod.VodPlayBuilder.BuildResult buildResult = builder.build();
|
||||
vodList.put("vod_play_from", buildResult.vodPlayFrom + "$$$" + quarkNames);
|
||||
vodList.put("vod_play_url", buildResult.vodPlayUrl + "$$$" + quarkUrls);
|
||||
|
||||
JSONArray list = new JSONArray();
|
||||
list.put(vodList);
|
||||
result.put("list", list);
|
||||
return result.toString();
|
||||
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log(e);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private void getVodDetail(Document doc, Vod.VodPlayBuilder builder, String index) throws JSONException {
|
||||
Elements allScript = doc.select(".wp-playlist-script");
|
||||
String sourceName = "第" + index + "季";
|
||||
for (Element element : allScript) {
|
||||
String scContent = element.html().trim();
|
||||
int start = scContent.indexOf('{');
|
||||
int end = scContent.lastIndexOf('}') + 1;
|
||||
String json = scContent.substring(start, end);
|
||||
JSONObject UJson = new JSONObject(json);
|
||||
JSONArray Track = UJson.getJSONArray("tracks");
|
||||
List<Vod.VodPlayBuilder.PlayUrl> list = new ArrayList<>();
|
||||
for (int k = 0; k < Track.length(); k++) {
|
||||
JSONObject src = Track.getJSONObject(k);
|
||||
String adk = src.getString("src0");
|
||||
String vodName = src.getString("caption");
|
||||
String pzm = getPlayUrl(adk);
|
||||
Vod.VodPlayBuilder.PlayUrl playUrl = new Vod.VodPlayBuilder.PlayUrl();
|
||||
playUrl.name = vodName;
|
||||
playUrl.url = ProxyVideo.buildCommonProxyUrl(pzm, Util.webHeaders(siteUrl));
|
||||
list.add(playUrl);
|
||||
}
|
||||
builder.append(sourceName, list);
|
||||
}
|
||||
}
|
||||
|
||||
public String getPlayUrl(String source) {
|
||||
if (source.endsWith("m3u8")) {
|
||||
return source;
|
||||
} else if (source.startsWith("https")) {
|
||||
return source;
|
||||
} else {
|
||||
return "https://v.ddys.pro" + source;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取视频播放信息
|
||||
*
|
||||
* @param flag 播放源
|
||||
* @param id 视频id
|
||||
* @param vipFlags 所有可能需要vip解析的源
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
if (flag.contains("quark")||flag.contains("uc")) {
|
||||
return super.playerContent(flag, id, vipFlags);
|
||||
} else {
|
||||
return Result.get().url(ProxyVideo.buildCommonProxyUrl(id, Util.webHeaders(siteUrl))).string();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) {
|
||||
|
||||
String url = siteUrl + "?s=" + URLEncoder.encode(key) + "&post_type=post";
|
||||
Document doc = Jsoup.parse(OkHttp.string(url, getHeaders(url)));
|
||||
List<Vod> vods = new ArrayList<>();
|
||||
Elements elements = doc.select("h2.post-title > a");
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
String id = elements.get(i).attr("href");
|
||||
String name = elements.get(i).text();
|
||||
vods.add(new Vod(id, name, ""));
|
||||
}
|
||||
return Result.string(vods);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,180 +0,0 @@
|
|||
package com.github.catvod.spider
|
||||
|
||||
import com.github.catvod.bean.Class
|
||||
import com.github.catvod.bean.Result
|
||||
import com.github.catvod.bean.Vod
|
||||
import com.github.catvod.bean.Vod.VodPlayBuilder
|
||||
import com.github.catvod.net.OkHttp
|
||||
import com.github.catvod.utils.ProxyVideo
|
||||
import com.github.catvod.utils.Util
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.select.Elements
|
||||
import java.net.URLEncoder
|
||||
|
||||
class DiDa : Cloud() {
|
||||
private val headers: HashMap<String?, String?>
|
||||
get() {
|
||||
val headers = java.util.HashMap<String?, String?>()
|
||||
headers.put("User-Agent", Util.CHROME)
|
||||
return headers
|
||||
}
|
||||
|
||||
private fun parseVodFromDoc(doc: Document): MutableList<Vod?> {
|
||||
val list: MutableList<Vod?> = ArrayList<Vod?>()
|
||||
for (element in doc.select("div.myui-vodlist__box")) {
|
||||
var pic = element.selectFirst("img")?.attr("src")
|
||||
if (pic.isNullOrBlank()) {
|
||||
pic = element.selectFirst("a")?.attr("data-original")
|
||||
}
|
||||
val url = element.selectFirst("a")?.attr("href")
|
||||
val name = element.select("h4 > a").text()
|
||||
|
||||
|
||||
list.add(Vod(url, name, pic))
|
||||
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun homeContent(filter: Boolean): String? {
|
||||
|
||||
val doc = Jsoup.parse(
|
||||
OkHttp.string(
|
||||
siteUrl, this.headers
|
||||
)
|
||||
)
|
||||
var classes: List<Class?>
|
||||
val menuList = doc.select("ul.nav-menu > li > a")
|
||||
classes = menuList.map {
|
||||
val url = it.attr("href")
|
||||
val title = it.text()
|
||||
Class(url, title)
|
||||
}
|
||||
|
||||
val list: MutableList<Vod?> = parseVodFromDoc(doc)
|
||||
return Result.string(classes, list)
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun categoryContent(
|
||||
tid: String, pg: String, filter: Boolean, extend: java.util.HashMap<String?, String?>?
|
||||
): String? {
|
||||
|
||||
val type = tid.replace("/type/", "").replace(".html", "")
|
||||
val target: String = siteUrl + "/show/${type}--------${pg}---.html"
|
||||
|
||||
val doc = Jsoup.parse(OkHttp.string(target, this.headers))
|
||||
val list = parseVodFromDoc(doc)
|
||||
val total = (pg.toInt() + 1) * 24
|
||||
return Result.get().vod(list).page(pg.toInt(), pg.toInt() + 1, 48, total).string()
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun detailContent(ids: MutableList<String?>): String? {
|
||||
val doc = Jsoup.parse(
|
||||
OkHttp.string(
|
||||
siteUrl + ids.get(0), this.headers
|
||||
)
|
||||
)
|
||||
val name = doc.select("h1").text()
|
||||
val img = doc.select("a.myui-vodlist__thumb > img")
|
||||
val pic = img.attr("src") ?: img.attr("data-original")
|
||||
|
||||
val desc = doc.select("p.data").text()
|
||||
val year = Util.findByRegex("年份:(.*)又名", desc, 1).trim()
|
||||
val area = Util.findByRegex("地区:(.*)语言", desc, 1).trim()
|
||||
val actor = Util.findByRegex("主演:(.*)导演", desc, 1).trim()
|
||||
|
||||
val builder = VodPlayBuilder()
|
||||
val playFromTab = doc.selectFirst("div.myui-panel__head > ul.nav ")
|
||||
val playFromEles = playFromTab?.select("ul > li > a") ?: Elements()
|
||||
for (ele in playFromEles) {
|
||||
val playUrlList = mutableListOf<Vod.VodPlayBuilder.PlayUrl>()
|
||||
|
||||
val id = ele.attr("href")
|
||||
val playFrom = ele.text()
|
||||
if (playFrom.contains("网盘")) {
|
||||
continue
|
||||
}
|
||||
val playElement = doc.select("$id")
|
||||
for (element in playElement.select("ul > li > a")) {
|
||||
val playUrl = VodPlayBuilder.PlayUrl()
|
||||
playUrl.url = element.attr("href")
|
||||
playUrl.name = element.text()
|
||||
playUrlList.add(playUrl)
|
||||
|
||||
}
|
||||
builder.append(playFrom, playUrlList)
|
||||
}
|
||||
var panFrom = ""
|
||||
var panURl = ""
|
||||
|
||||
for (element in doc.select(" div.myui-panel_bd.clearfix > p > a")) {
|
||||
if (element.attr("href").matches(Util.patternQuark.toRegex())) {
|
||||
panFrom = super.detailContentVodPlayFrom(listOf<String>(element.attr("href")))
|
||||
panURl = super.detailContentVodPlayUrl(listOf<String>(element.attr("href")))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val result = builder.build()
|
||||
val vod = Vod()
|
||||
vod.setVodId(ids[0])
|
||||
vod.setVodPic(ProxyVideo.buildCommonProxyUrl(pic, Util.webHeaders(pic)))
|
||||
vod.setVodYear(year)
|
||||
vod.setVodActor(actor)
|
||||
vod.setVodArea(area)
|
||||
vod.setVodName(name)
|
||||
vod.setVodPlayFrom(result.vodPlayFrom + "$$$" + panFrom)
|
||||
vod.setVodPlayUrl(result.vodPlayUrl + "$$$" + panURl)
|
||||
return Result.string(vod)
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun searchContent(key: String?, quick: Boolean): String? {
|
||||
val doc = Jsoup.parse(
|
||||
OkHttp.string(
|
||||
searchUrl + URLEncoder.encode(key), this.headers
|
||||
)
|
||||
)
|
||||
val list: MutableList<Vod?> = ArrayList<Vod?>()
|
||||
for (element in doc.select("a.cover-link")) {
|
||||
val pic = element.select("img").attr("data-src")
|
||||
val url = element.attr("href")
|
||||
val name = element.select("img").attr("alt")
|
||||
val id: String? = url.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[2]
|
||||
|
||||
list.add(Vod(id, name, ProxyVideo.buildCommonProxyUrl(pic, Util.webHeaders(pic))))
|
||||
}
|
||||
return Result.string(list)
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun playerContent(flag: String?, id: String?, vipFlags: MutableList<String?>?): String? {
|
||||
if (flag == null) {
|
||||
return Result.get().url("").header(this.headers).string()
|
||||
} else if (flag.contains("quark")) {
|
||||
super.playerContent(flag, id, vipFlags)
|
||||
} else {
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return Result.get().url(id).header(this.headers).string()
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private const val siteUrl = "https://www.didahd.pro"
|
||||
|
||||
private val searchUrl: String = siteUrl + "/search?q="
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Util;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 电影云集
|
||||
*
|
||||
* @author lushunming
|
||||
* @createdate 2024-12-03
|
||||
*/
|
||||
public class DianYingYunJi extends Cloud {
|
||||
|
||||
private final String siteUrl = "https://dyyjpro.com";
|
||||
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
return header;
|
||||
}
|
||||
|
||||
private Map<String, String> getHeaderWithCookie() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
header.put("cookie", "esc_search_captcha=1; result=43");
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
|
||||
super.init(context, extend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeader()));
|
||||
Elements elements = doc.select(" #header-navbar > li.menu-item > a");
|
||||
for (Element e : elements) {
|
||||
String url = e.attr("href");
|
||||
String name = e.text();
|
||||
if (url.contains(siteUrl)) {
|
||||
classes.add(new Class(url, name));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Result.string(classes, parseVodListFromDoc(doc));
|
||||
}
|
||||
|
||||
private List<Vod> parseVodListFromDoc(Document doc) {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Elements elements = doc.select(" article.post-item");
|
||||
for (Element e : elements) {
|
||||
String vodId = e.selectFirst("h2.entry-title > a").attr("href");
|
||||
String vodPic = e.selectFirst(" div.entry-media > a").attr("data-bg");
|
||||
if (!vodPic.startsWith("http")) {
|
||||
vodPic = siteUrl + vodPic;
|
||||
}
|
||||
String vodName = e.selectFirst("h2.entry-title > a").text();
|
||||
String vodRemarks = "";
|
||||
list.add(new Vod(vodId, vodName, vodPic, vodRemarks));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
|
||||
Document doc = Jsoup.parse(OkHttp.string(String.format("%s/page/%s", tid, pg), getHeader()));
|
||||
List<Vod> list = parseVodListFromDoc(doc);
|
||||
int total = (Integer.parseInt(pg) + 1) * 19;
|
||||
return Result.get().vod(list).page(Integer.parseInt(pg), Integer.parseInt(pg) + 1, 19, total).string();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
String vodId = ids.get(0);
|
||||
Document doc = Jsoup.parse(OkHttp.string(vodId, getHeader()));
|
||||
|
||||
Vod item = new Vod();
|
||||
item.setVodId(vodId);
|
||||
item.setVodName(doc.selectFirst(" h1.post-title").text());
|
||||
item.setVodPic(doc.selectFirst("article.post-content img").attr("src"));
|
||||
String html= doc.select("article.post-content > p").text();
|
||||
item.setVodDirector(getStrByRegex(Pattern.compile("导演:(.*?)编剧:"), html));
|
||||
item.setVodArea(getStrByRegex(Pattern.compile("地区:(.*?)语言:"), html));
|
||||
item.setVodActor(getStrByRegex(Pattern.compile("主演:(.*?)类型:"), html));
|
||||
item.setVodYear(getStrByRegex(Pattern.compile("上映日期:(.*?)片长:"), html));
|
||||
item.setVodRemarks("");
|
||||
item.setVodContent(getStrByRegex(Pattern.compile("剧情简介(.*?)获奖情况"), html));
|
||||
|
||||
List<String> shareLinks = new ArrayList<>();
|
||||
|
||||
for (Element element : doc.select("article.post-content p a")) {
|
||||
if (element.attr("href").matches(Util.patternQuark)) {
|
||||
shareLinks.add(element.attr("href").trim());
|
||||
}
|
||||
}
|
||||
|
||||
item.setTypeName(doc.selectFirst(" span.meta-cat-dot").text());
|
||||
|
||||
item.setVodPlayUrl(super.detailContentVodPlayUrl(shareLinks));
|
||||
item.setVodPlayFrom(super.detailContentVodPlayFrom(shareLinks));
|
||||
|
||||
return Result.string(item);
|
||||
}
|
||||
|
||||
private String getStrByRegex(Pattern pattern, String str) {
|
||||
Matcher matcher = pattern.matcher(str);
|
||||
if (matcher.find()) return matcher.group(1).trim();
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
return searchContent(key, "1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick, String pg) throws Exception {
|
||||
return searchContent(key, pg);
|
||||
}
|
||||
|
||||
private String searchContent(String key, String pg) {
|
||||
String searchURL = siteUrl + String.format("?cat=&s=%s", URLEncoder.encode(key));
|
||||
String html = OkHttp.string(searchURL, getHeaderWithCookie());
|
||||
Document doc = Jsoup.parse(html);
|
||||
|
||||
return Result.string(parseVodListFromDoc(doc));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author zhixc
|
||||
*/
|
||||
public class DuoDuo extends Cloud {
|
||||
|
||||
private String siteUrl = "https://tv.yydsys.top/";
|
||||
private final Pattern regexCategory = Pattern.compile("index.php/vod/type/id/(\\w+).html");
|
||||
private final Pattern regexPageTotal = Pattern.compile("\\$\\(\"\\.mac_total\"\\)\\.text\\('(\\d+)'\\);");
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
// JsonObject ext = Json.safeObject(extend);
|
||||
super.init(context, extend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeader()));
|
||||
Elements elements = doc.select(".nav-link");
|
||||
for (Element e : elements) {
|
||||
Matcher mather = regexCategory.matcher(e.attr("href"));
|
||||
if (mather.find()) {
|
||||
classes.add(new Class(mather.group(1), e.text().trim()));
|
||||
}
|
||||
}
|
||||
return Result.string(classes, parseVodListFromDoc(doc));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
String[] urlParams = new String[]{tid, "", "", "", "", "", "", "", pg, "", "", ""};
|
||||
if (extend != null && extend.size() > 0) {
|
||||
for (String key : extend.keySet()) {
|
||||
urlParams[Integer.parseInt(key)] = extend.get(key);
|
||||
}
|
||||
}
|
||||
Document doc = Jsoup.parse(OkHttp.string(String.format("%s/index.php/vod/show/id/%s/page/%s.html", siteUrl, tid, pg), getHeader()));
|
||||
int page = Integer.parseInt(pg), limit = 72, total = 0;
|
||||
Matcher matcher = regexPageTotal.matcher(doc.html());
|
||||
if (matcher.find()) total = Integer.parseInt(matcher.group(1));
|
||||
int count = total <= limit ? 1 : ((int) Math.ceil(total / (double) limit));
|
||||
return Result.get().vod(parseVodListFromDoc(doc)).page(page, count, limit, total).string();
|
||||
}
|
||||
|
||||
private List<Vod> parseVodListFromDoc(Document doc) {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Elements elements = doc.select(".module-item");
|
||||
for (Element e : elements) {
|
||||
String vodId = e.selectFirst(".video-name a").attr("href");
|
||||
String vodPic = e.selectFirst(".module-item-pic > img").attr("data-src");
|
||||
String vodName = e.selectFirst(".video-name").text();
|
||||
String vodRemarks = e.selectFirst(".module-item-text").text();
|
||||
list.add(new Vod(vodId, vodName, vodPic, vodRemarks));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
String vodId = ids.get(0);
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl + vodId, getHeader()));
|
||||
|
||||
Vod item = new Vod();
|
||||
item.setVodId(vodId);
|
||||
item.setVodName(doc.selectFirst(".video-info-header > .page-title").text());
|
||||
item.setVodPic(doc.selectFirst(".module-item-pic img").attr("data-src"));
|
||||
item.setVodArea(doc.select(".video-info-header a.tag-link").last().text());
|
||||
item.setTypeName(String.join(",", doc.select(".video-info-header div.tag-link a").eachText()));
|
||||
|
||||
List<String> shareLinks = doc.select(".module-row-text").eachAttr("data-clipboard-text");
|
||||
for (int i = 0; i < shareLinks.size(); i++) {
|
||||
shareLinks.set(i, shareLinks.get(i).trim());
|
||||
//String detailContent = super.detailContent(List.of(shareLinks.get(i)));
|
||||
}
|
||||
item.setVodPlayUrl(super.detailContentVodPlayUrl(shareLinks));
|
||||
item.setVodPlayFrom(super.detailContentVodPlayFrom(shareLinks));
|
||||
|
||||
Elements elements = doc.select(".video-info-item");
|
||||
for (Element e : elements) {
|
||||
String title = e.previousElementSibling().text();
|
||||
if (title.contains("导演")) {
|
||||
item.setVodDirector(String.join(",", e.select("a").eachText()));
|
||||
} else if (title.contains("主演")) {
|
||||
item.setVodActor(String.join(",", e.select("a").eachText()));
|
||||
} else if (title.contains("年代")) {
|
||||
item.setVodYear(e.selectFirst("a").text().trim());
|
||||
} else if (title.contains("备注")) {
|
||||
item.setVodRemarks(e.text().trim());
|
||||
} else if (title.contains("剧情")) {
|
||||
item.setVodContent(e.selectFirst(".sqjj_a").text().replace("[收起部分]", "").trim());
|
||||
}
|
||||
}
|
||||
|
||||
return Result.string(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
return searchContent(key, "1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick, String pg) throws Exception {
|
||||
return searchContent(key, pg);
|
||||
}
|
||||
|
||||
|
||||
private String searchContent(String key, String pg) {
|
||||
String searchURL = siteUrl + String.format("/index.php/vod/search/page/%s/wd/%s.html", pg,URLEncoder.encode(key));
|
||||
String html = OkHttp.string(searchURL, getHeader());
|
||||
Elements items = Jsoup.parse(html).select(".module-search-item");
|
||||
List<Vod> list = new ArrayList<>();
|
||||
for (Element item : items) {
|
||||
String vodId = item.select(".video-serial").attr("href");
|
||||
String name = item.select(".video-serial").attr("title");
|
||||
String pic = item.select(".module-item-pic > img").attr("data-src");
|
||||
String remark = item.select(".video-tag-icon").text();
|
||||
list.add(new Vod(vodId, name, pic, remark));
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,184 +0,0 @@
|
|||
package com.github.catvod.spider
|
||||
|
||||
|
||||
import com.github.catvod.bean.Class
|
||||
import com.github.catvod.bean.Result
|
||||
import com.github.catvod.bean.Vod
|
||||
|
||||
import com.github.catvod.crawler.Spider
|
||||
import com.github.catvod.crawler.SpiderDebug
|
||||
import com.github.catvod.net.OkHttp
|
||||
import com.github.catvod.utils.Json
|
||||
import com.github.catvod.utils.Util
|
||||
import com.google.gson.JsonArray
|
||||
import org.apache.commons.lang3.time.DateFormatUtils
|
||||
import org.apache.commons.lang3.time.DateUtils
|
||||
import org.jsoup.Jsoup
|
||||
import java.util.*
|
||||
|
||||
class Glod : Spider() {
|
||||
private val host = Util.base64Decode("aHR0cHM6Ly93d3cuY2Zrajg2LmNvbS8=")
|
||||
|
||||
private val epUrl = "/api/mw-movie/anonymous/v1/video/episode/url?id=%s&nid=%s"
|
||||
|
||||
private val deviceId = UUID.randomUUID().toString();
|
||||
|
||||
private val classList = listOf(Class("1", "电影"), Class("2", "电视剧"), Class("4", "动漫"), Class("3", "综艺"))
|
||||
|
||||
override fun homeContent(filter: Boolean): String {
|
||||
val string = OkHttp.string(host, Util.webHeaders("https://www.bing.com"))
|
||||
val vodList = parseFromJson(string, "home")
|
||||
// val vodList = parseVodList(string)
|
||||
return Result.string(classList, vodList)
|
||||
}
|
||||
|
||||
override fun detailContent(ids: MutableList<String>): String {
|
||||
val url = host + ids[0]
|
||||
val string = OkHttp.string(url, Util.webHeaders(host))
|
||||
val parse = Jsoup.parse(string)
|
||||
val name = parse.select("h1.title").text()
|
||||
val img = parse.select("div[class^=detail__CardImg] img").attr("src")
|
||||
val tag = parse.select("div.tags > a.tag").eachText().joinToString(" ")
|
||||
val vod = Vod(ids[0], name, img, tag)
|
||||
val director = parse.select("div.director")
|
||||
val d = director[0].select("a").text()
|
||||
val actor = director[1].select("a").eachText().joinToString(" ")
|
||||
vod.setVodActor(actor)
|
||||
vod.setVodDirector(d)
|
||||
val desc = parse.select("div.intro div.wrapper_more_text").text()
|
||||
vod.vodContent = desc
|
||||
|
||||
val linkList = parse.select("div.listitem > a")
|
||||
|
||||
val playUrlList = mutableListOf<Vod.VodPlayBuilder.PlayUrl>()
|
||||
for (element in linkList) {
|
||||
val u = element.attr("href")
|
||||
val n = element.text()
|
||||
playUrlList.add(Vod.VodPlayBuilder.PlayUrl().also {
|
||||
it.name = n
|
||||
it.url = u
|
||||
})
|
||||
}
|
||||
|
||||
val buildResult = Vod.VodPlayBuilder().append("glod", playUrlList).build()
|
||||
|
||||
val time = parse.select("div.item:contains(上映时间)").select(".item-top").text()
|
||||
vod.setVodYear(DateFormatUtils.format(DateUtils.parseDate(time, "yyyy-MM-dd"), "yyyy"))
|
||||
vod.setVodPlayFrom(buildResult.vodPlayFrom)
|
||||
vod.vodPlayUrl = buildResult.vodPlayUrl
|
||||
return Result.string(vod)
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求头
|
||||
* t 时间戳
|
||||
* sign 签名
|
||||
* deviceId
|
||||
* authorization 空的
|
||||
* 还有cookie
|
||||
*/
|
||||
override fun playerContent(flag: String, id: String, vipFlags: MutableList<String>): String {
|
||||
val list = id.split("/")
|
||||
val i = list[3]
|
||||
val nid = list[5]
|
||||
val webHeaders = Util.webHeaders(host)
|
||||
val time = Date().time.toString()
|
||||
val sign = Util.sha1Hex(
|
||||
Util.MD5("id=${i}&nid=${nid}&key=cb808529bae6b6be45ecfab29a4889bc&t=${time}")
|
||||
)
|
||||
webHeaders["t"] = time
|
||||
webHeaders["deviceId"] = deviceId
|
||||
webHeaders["Sign"] = sign
|
||||
|
||||
val string = OkHttp.string(host + String.format(epUrl, i, nid), webHeaders)
|
||||
val parse = Json.parse(string).asJsonObject
|
||||
if (parse.get("code").asInt != 200) {
|
||||
SpiderDebug.log("glod 获取播放链接失败:$string")
|
||||
return Result.error("获取播放链接失败")
|
||||
}
|
||||
val url = parse.get("data").asJsonObject.get("playUrl").asString
|
||||
return Result.get().url(url).string()
|
||||
}
|
||||
|
||||
override fun categoryContent(tid: String, pg: String, filter: Boolean, extend: HashMap<String, String>): String {
|
||||
val url = "$host/type/$tid"
|
||||
val string = OkHttp.string(url, Util.webHeaders(host))
|
||||
val vodList = parseFromJson(string, "cate")
|
||||
return Result.string(classList, vodList)
|
||||
}
|
||||
|
||||
override fun searchContent(key: String, quick: Boolean): String {
|
||||
val string = OkHttp.string("${host}vod/search/$key", Util.webHeaders(host))
|
||||
val vodList = parseFromJson(string, "search")
|
||||
return Result.string(vodList)
|
||||
}
|
||||
|
||||
private fun parseFromJson(string: String, type: String): List<Vod> {
|
||||
val vodList = mutableListOf<Vod>()
|
||||
val parse = Jsoup.parse(string)
|
||||
val select = parse.select("script")
|
||||
val data = select.find {
|
||||
it.html().contains("操作成功")
|
||||
}
|
||||
if (data == null) {
|
||||
SpiderDebug.log("glod 找不到json")
|
||||
return vodList
|
||||
}
|
||||
val json = data.html().replace("self.__next_f.push(", "").replace(")", "")
|
||||
|
||||
val gson = Json.parse(json).asJsonArray.get(1).asString.replace("6:", "")
|
||||
val resp = Json.parse(gson).asJsonArray.get(3).asJsonObject
|
||||
if (type == "home") {
|
||||
val element = resp.get("children").asJsonArray.get(3).asJsonObject.get("data").asJsonObject.get("data")
|
||||
var vList = element.asJsonObject.get("homeNewMoviePageData").asJsonObject.get("list").asJsonArray
|
||||
getVodList(vList, vodList)
|
||||
vList = element.asJsonObject.get("homeBroadcastPageData").asJsonObject.get("list").asJsonArray
|
||||
getVodList(vList, vodList)
|
||||
vList = element.asJsonObject.get("homeManagerPageData").asJsonObject.get("list").asJsonArray
|
||||
getVodList(vList, vodList)
|
||||
vList = element.asJsonObject.get("newestTvPageData").asJsonObject.get("list").asJsonArray
|
||||
getVodList(vList, vodList)
|
||||
vList = element.asJsonObject.get("newestCartoonPageData").asJsonObject.get("list").asJsonArray
|
||||
getVodList(vList, vodList)
|
||||
} else if (type == "cate") {
|
||||
for (jsonElement in resp.get("children").asJsonArray.get(3).asJsonObject.get("data").asJsonArray) {
|
||||
val objList = jsonElement.asJsonObject.get("vodList").asJsonObject.get("list").asJsonArray
|
||||
getVodList(objList, vodList)
|
||||
}
|
||||
} else if (type == "search") {
|
||||
val asJsonArray =
|
||||
resp.get("data").asJsonObject.get("data").asJsonObject.get("result").asJsonObject.get("list").asJsonArray
|
||||
getVodList(asJsonArray, vodList)
|
||||
}
|
||||
return vodList
|
||||
}
|
||||
|
||||
private fun getVodList(
|
||||
objList: JsonArray, vodList: MutableList<Vod>
|
||||
) {
|
||||
for (oj in objList) {
|
||||
val obj = oj.asJsonObject
|
||||
val v = Vod()
|
||||
v.setVodId("/detail/" + obj.get("vodId").asString)
|
||||
v.setVodName(obj.get("vodName").asString)
|
||||
// v.setVodActor(obj.get("vodActor").asString)
|
||||
v.setVodRemarks(obj.get("vodScore").asString)
|
||||
v.setVodPic(obj.get("vodPic").asString)
|
||||
vodList.add(v)
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseVodList(string: String): MutableList<Vod> {
|
||||
val parse = Jsoup.parse(string)
|
||||
val list = parse.select("div.content-card")
|
||||
val vodList = mutableListOf<Vod>()
|
||||
for (element in list) {
|
||||
val id = element.select("a").attr("href")
|
||||
val title = element.select("div.info-title-box > div.title").text()
|
||||
val score = element.select("div.bottom div[class^=score]").text()
|
||||
val img = element.select("img").attr("srcset")
|
||||
vodList.add(Vod(id, title, host + img, score))
|
||||
}
|
||||
return vodList
|
||||
}
|
||||
}
|
||||
|
|
@ -1,221 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.Base64;
|
||||
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.Util;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class HkTv extends Spider {
|
||||
|
||||
private static String siteUrl = "http://www.tvyb03.com";
|
||||
private static String cateUrl = siteUrl + "/vod/type/id/";
|
||||
private static String detailUrl = siteUrl + "/vod/detail/id/";
|
||||
private static String playUrl = siteUrl + "/vod/play/id/";
|
||||
private static String searchUrl = siteUrl + "/vod/search.html?wd=";
|
||||
|
||||
private HashMap<String, String> getHeaders() {
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", Util.CHROME);
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
super.init(context, extend);
|
||||
Document doc = Jsoup.parse(OkHttp.string(extend));
|
||||
|
||||
|
||||
if (StringUtils.isNoneBlank(doc.html())) {
|
||||
String data = doc.select("ul > li > a").first().attr("href");
|
||||
siteUrl = data;
|
||||
}
|
||||
cateUrl = siteUrl + "/vod/type/id/";
|
||||
detailUrl = siteUrl + "/vod/detail/id/";
|
||||
playUrl = siteUrl + "/vod/play/id/";
|
||||
searchUrl = siteUrl + "/vod/search.html?wd=";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
List<Class> classes = new ArrayList<>();
|
||||
String[] typeIdList = {"1", "2", "3", "4", "19"};
|
||||
String[] typeNameList = {"电影", "电视剧", "综艺", "动漫", "短片"};
|
||||
for (int i = 0; i < typeNameList.length; i++) {
|
||||
classes.add(new Class(typeIdList[i], typeNameList[i]));
|
||||
}
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeaders()));
|
||||
for (Element element : doc.select("a.myui-vodlist__thumb")) {
|
||||
try {
|
||||
String pic = element.attr("data-original");
|
||||
String url = element.attr("href");
|
||||
String name = element.attr("title");
|
||||
if (!pic.startsWith("http")) {
|
||||
pic = siteUrl + pic;
|
||||
}
|
||||
String id = url.split("/")[4];
|
||||
list.add(new Vod(id, name, pic));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
return Result.string(classes, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
String target = cateUrl + tid + ".html";
|
||||
if (!"1".equals(pg)) {
|
||||
target = cateUrl + pg + "/page/" + tid + ".html";
|
||||
}
|
||||
Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
|
||||
for (Element element : doc.select("ul.myui-vodlist li a.myui-vodlist__thumb")) {
|
||||
try {
|
||||
String pic = element.attr("data-original");
|
||||
String url = element.attr("href");
|
||||
String name = element.attr("title");
|
||||
if (!pic.startsWith("http")) {
|
||||
pic = siteUrl + pic;
|
||||
}
|
||||
String id = url.split("/")[4];
|
||||
list.add(new Vod(id, name, pic));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
Integer total = (Integer.parseInt(pg) + 1) * 20;
|
||||
return Result.string(Integer.parseInt(pg), Integer.parseInt(pg) + 1, 20, total, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
Document doc = Jsoup.parse(OkHttp.string(detailUrl.concat(ids.get(0)), getHeaders()));
|
||||
String name = doc.select("h1.title").text();
|
||||
String pic = doc.select("a.myui-vodlist__thumb.picture img").attr("data-original");
|
||||
// 播放源
|
||||
Elements tabs = doc.select("div.myui-panel__head.bottom-line.active.clearfix h3");
|
||||
Elements list = doc.select("ul.myui-content__list");
|
||||
String PlayFrom = "";
|
||||
String PlayUrl = "";
|
||||
for (int i = 1; i < tabs.size() - 1; i++) {
|
||||
String tabName = tabs.get(i).text();
|
||||
if (!"".equals(PlayFrom)) {
|
||||
PlayFrom = PlayFrom + "$$$" + tabName;
|
||||
} else {
|
||||
PlayFrom = PlayFrom + tabName;
|
||||
}
|
||||
Elements li = list.get(i - 1).select("a");
|
||||
String liUrl = "";
|
||||
for (int i1 = 0; i1 < li.size(); i1++) {
|
||||
if (!"".equals(liUrl)) {
|
||||
liUrl = liUrl + "#" + li.get(i1).text() + "$" + li.get(i1).attr("href").replace("/vod/play/id/", "");
|
||||
} else {
|
||||
liUrl = liUrl + li.get(i1).text() + "$" + li.get(i1).attr("href").replace("/vod/play/id/", "");
|
||||
}
|
||||
}
|
||||
if (!"".equals(PlayUrl)) {
|
||||
PlayUrl = PlayUrl + "$$$" + liUrl;
|
||||
} else {
|
||||
PlayUrl = PlayUrl + liUrl;
|
||||
}
|
||||
}
|
||||
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(ids.get(0));
|
||||
vod.setVodPic(siteUrl + pic);
|
||||
vod.setVodName(name);
|
||||
vod.setVodPlayFrom(PlayFrom);
|
||||
vod.setVodPlayUrl(PlayUrl);
|
||||
return Result.string(vod);
|
||||
}
|
||||
|
||||
@Override
|
||||
// 需要验证码
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(searchUrl.concat(URLEncoder.encode(key)), getHeaders()));
|
||||
for (Element element : doc.select("div.searchlist_img")) {
|
||||
try {
|
||||
String pic = element.select("a").attr("data-original");
|
||||
String url = element.select("a").attr("href");
|
||||
String name = element.select("a").attr("title");
|
||||
if (!pic.startsWith("http")) {
|
||||
pic = siteUrl + pic;
|
||||
}
|
||||
String id = url.replace("/video/", "").replace(".html", "-1-1.html");
|
||||
list.add(new Vod(id, name, pic));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
String target = playUrl.concat(id);
|
||||
Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
|
||||
String regex = "\"url\\\":\\\"(.*?)\\\",\\\"url_next\\\":";
|
||||
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(doc.html());
|
||||
String url = doc.html();
|
||||
if (matcher.find()) {
|
||||
String encryptedData = matcher.group(1);
|
||||
String decodedString = new String(Base64.decode(encryptedData, Base64.DEFAULT));
|
||||
url = decodeURL(decodedString);
|
||||
}
|
||||
return Result.get().url(url).header(getHeaders()).string();
|
||||
}
|
||||
|
||||
public static String decodeURL(String encodedURL) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int index = 0;
|
||||
while (index < encodedURL.length()) {
|
||||
if (encodedURL.charAt(index) == '%') {
|
||||
if (index + 2 < encodedURL.length()) {
|
||||
if (encodedURL.charAt(index + 1) == 'u') {
|
||||
String unicodeStr = encodedURL.substring(index + 2, index + 6);
|
||||
char unicodeChar = (char) Integer.parseInt(unicodeStr, 16);
|
||||
sb.append(unicodeChar);
|
||||
index += 6;
|
||||
} else {
|
||||
String hexStr = encodedURL.substring(index + 1, index + 3);
|
||||
char hexChar = (char) Integer.parseInt(hexStr, 16);
|
||||
sb.append(hexChar);
|
||||
index += 3;
|
||||
}
|
||||
} else {
|
||||
sb.append(encodedURL.charAt(index));
|
||||
index++;
|
||||
}
|
||||
} else {
|
||||
sb.append(encodedURL.charAt(index));
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,210 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.ProxyVideo;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Ikanbot extends Spider {
|
||||
|
||||
private static final String siteUrl = "https://v.ikanbot.com";
|
||||
private static final String cateUrl = siteUrl + "/hot";
|
||||
private static final String detailUrl = siteUrl + "/play/";
|
||||
private static final String searchUrl = siteUrl + "/search?q=";
|
||||
|
||||
private HashMap<String, String> getHeaders() {
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", Util.CHROME);
|
||||
return headers;
|
||||
}
|
||||
|
||||
private List<Vod> parseVods(Document doc) {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
for (Element element : doc.select("a.item")) {
|
||||
String pic = element.select("img").attr("data-src");
|
||||
String url = element.attr("href");
|
||||
String name = element.select("img").attr("alt");
|
||||
String id = url.split("/")[2];
|
||||
list.add(new Vod(id, name, ProxyVideo.buildCommonProxyUrl(pic, Util.webHeaders(pic))));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) throws Exception {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
String[] typeIdList = {"/index-movie-热门", "/index-tv-热门", "/index-tv-国产剧", "/index-tv-韩剧"};
|
||||
String[] typeNameList = {"热门电影", "热门剧集", "国产剧", "韩剧"};
|
||||
for (int i = 0; i < typeNameList.length; i++) {
|
||||
classes.add(new Class(typeIdList[i], typeNameList[i]));
|
||||
}
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl + "/billboard.html", getHeaders()));
|
||||
List<Vod> list = new ArrayList<>();
|
||||
for (Element element : doc.select("div.item-root")) {
|
||||
String pic = element.select("img").attr("data-src");
|
||||
String url = element.select("a").attr("href");
|
||||
String name = element.select("img").attr("alt");
|
||||
try {
|
||||
String id = url.split("/")[2];
|
||||
list.add(new Vod(id, name, ProxyVideo.buildCommonProxyUrl(pic, Util.webHeaders(pic))));
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
return Result.string(classes, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||
String target = cateUrl + tid;
|
||||
if (!"1".equals(pg)) {
|
||||
target = target + "-p-" + pg;
|
||||
}
|
||||
Document doc = Jsoup.parse(OkHttp.string(target.concat(".html"), getHeaders()));
|
||||
List<Vod> list = parseVods(doc);
|
||||
Integer total = (Integer.parseInt(pg) + 1) * 24;
|
||||
return Result.get().vod(list).page(Integer.parseInt(pg), Integer.parseInt(pg) + 1, 24, total).string();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
Document doc = Jsoup.parse(OkHttp.string(detailUrl.concat(ids.get(0)), getHeaders()));
|
||||
String name = doc.select("h1").text();
|
||||
String pic = doc.select("meta[property=og:image]").attr("content");
|
||||
Elements desc = doc.select("div.detail > h3");
|
||||
String year = desc.get(1).text();
|
||||
String area = desc.get(2).text();
|
||||
String actor = desc.get(3).text();
|
||||
|
||||
String current_id = doc.select("input#current_id").attr("value");
|
||||
String e_token = doc.select("input#e_token").attr("value");
|
||||
String mtype = doc.select("input#mtype").attr("value");
|
||||
String tks = get_tks(current_id, e_token);
|
||||
String url = siteUrl + "/api/getResN?videoId=" + ids.get(0) + "&mtype=" + mtype + " &token=" + tks;
|
||||
String data = OkHttp.string(url, getHeaders());
|
||||
Gson gson = new Gson();
|
||||
JsonObject jsonObject = gson.fromJson(data, JsonObject.class);
|
||||
JsonArray array = jsonObject.getAsJsonObject("data").getAsJsonArray("list");
|
||||
String PlayFrom = "";
|
||||
String PlayUrl = "";
|
||||
for (JsonElement element : array) {
|
||||
|
||||
// 使用正则表达式匹配 "flag" 和 "url"
|
||||
Pattern pattern = Pattern.compile("\\\"flag\\\":\\\"(.*?)\\\",\\\"url\\\":\\\"(.*?)\\\"");
|
||||
Matcher matcher = pattern.matcher(String.valueOf(element.getAsJsonObject().get("resData")).replace("\\", ""));
|
||||
String flag = "";
|
||||
String liUrl = "";
|
||||
// 提取匹配到的内容
|
||||
if (matcher.find()) {
|
||||
flag = matcher.group(1);
|
||||
liUrl = matcher.group(2);
|
||||
}
|
||||
if (!"".equals(PlayFrom)) {
|
||||
PlayFrom = PlayFrom + "$$$" + flag;
|
||||
} else {
|
||||
PlayFrom = PlayFrom + flag;
|
||||
}
|
||||
if (!"".equals(PlayUrl)) {
|
||||
PlayUrl = PlayUrl + "$$$" + liUrl.replace("$" + flag, "");
|
||||
} else {
|
||||
PlayUrl = PlayUrl + liUrl.replace("$" + flag, "");
|
||||
}
|
||||
|
||||
// PlayUrl += String.valueOf(element.getAsJsonObject().get("resData")).replace("\\","").replace("\\\"","\"");
|
||||
}
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(ids.get(0));
|
||||
vod.setVodPic(ProxyVideo.buildCommonProxyUrl(pic, Util.webHeaders(pic)));
|
||||
vod.setVodYear(year);
|
||||
vod.setVodActor(actor);
|
||||
vod.setVodArea(area);
|
||||
vod.setVodName(name);
|
||||
vod.setVodPlayFrom(PlayFrom);
|
||||
vod.setVodPlayUrl(PlayUrl.replace("##", "#").replace("#$$$", "$$$"));
|
||||
return Result.string(vod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
Document doc = Jsoup.parse(OkHttp.string(searchUrl.concat(URLEncoder.encode(key)), getHeaders()));
|
||||
List<Vod> list = new ArrayList<>();
|
||||
for (Element element : doc.select("a.cover-link")) {
|
||||
String pic = element.select("img").attr("data-src");
|
||||
String url = element.attr("href");
|
||||
String name = element.select("img").attr("alt");
|
||||
String id = url.split("/")[2];
|
||||
|
||||
list.add(new Vod(id, name, ProxyVideo.buildCommonProxyUrl(pic, Util.webHeaders(pic))));
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
return Result.get().url(id).header(getHeaders()).string();
|
||||
}
|
||||
|
||||
|
||||
// function get_tks() {
|
||||
// const _0xf07220 = _0xf746;
|
||||
// let _0x35162d = document['getElementById'] ('current_id').value 'current_id'
|
||||
// , _0xf25678 = document['getElementById'] ('e_token').value;
|
||||
// 'e_token'
|
||||
// if (!_0x35162d || !_0xf25678)
|
||||
// return;
|
||||
// let _0x3882a3 = _0x35162d['length'], _0x52a097 = _0x35162d['substring']
|
||||
// (_0x3882a3 - 4, _0x3882a3)
|
||||
// ,_0x2d9d1b = [];
|
||||
// for (let _0x570711 = 0x0; _0x570711 < _0x52a097['length']; _0x570711++) {
|
||||
// let _0x23e537 = parseInt(_0x52a097[_0x570711]), _0x48b93d = _0x23e537 % 0x3 + 0x1;
|
||||
// _0x2d9d1b[_0x570711] = _0xf25678['substring'] (_0x48b93d, _0x48b93d + 0x8),
|
||||
// _0xf25678 = _0xf25678['substring'] (_0x48b93d + 0x8, _0xf25678['length']);
|
||||
// }
|
||||
// v_tks = _0x2d9d1b['join'] ('');
|
||||
// }
|
||||
|
||||
public String get_tks(String current_id, String e_token) {
|
||||
// String current_id = "798347";
|
||||
// String e_token = "mre0530ce88964487488y67d38c0a1uj7fd15cb8";
|
||||
System.out.printf("current_id " + current_id);
|
||||
System.out.printf("e_token " + e_token);
|
||||
if ("".equals(current_id) || "".equals(e_token)) {
|
||||
return "";
|
||||
}
|
||||
String[] list = new String[4];
|
||||
int idLength = current_id.length();
|
||||
String subString = current_id.substring(idLength - 4, idLength);
|
||||
for (int i = 0; i < subString.length(); i++) {
|
||||
int num = Character.getNumericValue(subString.charAt(i));
|
||||
int begin = num % 3 + 1;
|
||||
list[i] = e_token.substring(begin, begin + 8);
|
||||
e_token = e_token.substring(begin + 8);
|
||||
}
|
||||
|
||||
StringBuilder v_tks = new StringBuilder();
|
||||
for (String string : list) {
|
||||
v_tks.append(string);
|
||||
}
|
||||
return v_tks.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@ import android.os.Handler;
|
|||
import android.os.Looper;
|
||||
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.utils.ProxyServer;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
|
|
@ -42,11 +41,7 @@ public class Init {
|
|||
|
||||
public static void init(Context context) {
|
||||
get().app = ((Application) context);
|
||||
SpiderDebug.log("自定義爬蟲代碼載入成功!" + "1");
|
||||
execute(() -> {
|
||||
ProxyServer.INSTANCE.stop();
|
||||
ProxyServer.INSTANCE.start();
|
||||
});
|
||||
SpiderDebug.log("自定義爬蟲代碼載入成功!");
|
||||
}
|
||||
|
||||
public static void execute(Runnable runnable) {
|
||||
|
|
@ -65,8 +60,7 @@ public class Init {
|
|||
try {
|
||||
Activity activity = Init.getActivity();
|
||||
if (activity == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return;
|
||||
if (activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
|
||||
return;
|
||||
if (activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) return;
|
||||
activity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 9999);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
|
|
|||
|
|
@ -1,98 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.github.catvod.api.TianYiHandler;
|
||||
import com.github.catvod.api.UCTokenHandler;
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class Introduce extends Spider {
|
||||
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
super.init(context, extend);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) throws Exception {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
classes.add(new Class("1", "UC"));
|
||||
classes.add(new Class("2", "天意"));
|
||||
List<Vod> list = new ArrayList<>();
|
||||
String pic = "https://androidcatvodspider.netlify.app/wechat.png";
|
||||
String name = "关注公众号";
|
||||
list.add(new Vod("https://androidcatvodspider.netlify.app/wechat.png", name, pic));
|
||||
String pic2 = "https://androidcatvodspider.netlify.app/wechat.png";
|
||||
String name2 = "本接口不收费,请不要付费,谢谢!";
|
||||
list.add(new Vod("https://androidcatvodspider.netlify.app/wechat.png", name2, pic2));
|
||||
String pic3 = "https://androidcatvodspider.netlify.app/wechat.png";
|
||||
String name3 = "2025-04-14 11:00";
|
||||
list.add(new Vod("https://androidcatvodspider.netlify.app/wechat.png", name3, pic3));
|
||||
return Result.string(classes, list);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
List<Vod> vodList = new ArrayList<>();
|
||||
//UC
|
||||
if (tid.equals("1")) {
|
||||
String pic = "https://androidcatvodspider.netlify.app/wechat.png";
|
||||
String name = "点击设置Token";
|
||||
vodList.add(new Vod("UCToken", name, pic));
|
||||
}
|
||||
//天翼
|
||||
if (tid.equals("2")) {
|
||||
String pic = "https://androidcatvodspider.netlify.app/wechat.png";
|
||||
String name = "点击设置cookie";
|
||||
vodList.add(new Vod("天翼cookie", name, pic));
|
||||
String pic1 = "https://androidcatvodspider.netlify.app/wechat.png";
|
||||
String name1 = "清除cookie";
|
||||
vodList.add(new Vod("clean天翼cookie", name1, pic1));
|
||||
}
|
||||
return Result.get().vod(vodList).page().string();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
String vodId = ids.get(0);
|
||||
|
||||
//UC Token 扫码
|
||||
if (vodId.equals("UCToken")) {
|
||||
UCTokenHandler qrCodeHandler = new UCTokenHandler();
|
||||
qrCodeHandler.startUC_TOKENScan();
|
||||
}
|
||||
if (vodId.equals("天翼cookie")) {
|
||||
TianYiHandler qrCodeHandler = TianYiHandler.get();
|
||||
qrCodeHandler.startFlow();
|
||||
}
|
||||
|
||||
if (vodId.equals("clean天翼cookie")) {
|
||||
TianYiHandler qrCodeHandler = TianYiHandler.get();
|
||||
qrCodeHandler.cleanCookie();
|
||||
}
|
||||
Vod item = new Vod();
|
||||
item.setVodId(vodId);
|
||||
item.setVodName("公众号");
|
||||
item.setVodPic("https://androidcatvodspider.netlify.app/wechat.png");
|
||||
item.setVodRemarks("");
|
||||
item.setVodPlayFrom("公众号");
|
||||
item.setVodPlayUrl("https://test-streams.mux.dev/x36xhzz/url_6/193039199_mp4_h264_aac_hq_7.m3u8");
|
||||
item.setVodDirector("公众号");
|
||||
return Result.string(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
return Result.get().url("https://test-streams.mux.dev/x36xhzz/url_6/193039199_mp4_h264_aac_hq_7.m3u8").string();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Util;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class Jable extends Spider {
|
||||
|
||||
private static final String siteUrl = "https://jable.tv";
|
||||
private static final String cateUrl = siteUrl + "/categories/";
|
||||
private static final String detailUrl = siteUrl + "/videos/";
|
||||
private static final String searchUrl = siteUrl + "/search/";
|
||||
|
||||
private HashMap<String, String> getHeaders() {
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", Util.CHROME);
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
List<Class> classes = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(cateUrl, getHeaders()));
|
||||
for (Element element : doc.select("div.img-box > a")) {
|
||||
String typeId = element.attr("href").split("/")[4];
|
||||
String typeName = element.select("div.absolute-center > h4").text();
|
||||
classes.add(new Class(typeId, typeName));
|
||||
}
|
||||
doc = Jsoup.parse(OkHttp.string(siteUrl, getHeaders()));
|
||||
for (Element element : doc.select("div.video-img-box")) {
|
||||
String pic = element.select("img").attr("data-src");
|
||||
String url = element.select("a").attr("href");
|
||||
String name = element.select("div.detail > h6").text();
|
||||
if (pic.endsWith(".gif") || name.isEmpty()) continue;
|
||||
String id = url.split("/")[4];
|
||||
list.add(new Vod(id, name, pic));
|
||||
}
|
||||
return Result.string(classes, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
String target = cateUrl + tid + "/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from=" + String.format(Locale.getDefault(), "%02d", Integer.parseInt(pg)) + "&_=" + System.currentTimeMillis();
|
||||
Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
|
||||
for (Element element : doc.select("div.video-img-box")) {
|
||||
String pic = element.select("img").attr("data-src");
|
||||
String url = element.select("a").attr("href");
|
||||
String name = element.select("div.detail > h6").text();
|
||||
String id = url.split("/")[4];
|
||||
list.add(new Vod(id, name, pic));
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
Document doc = Jsoup.parse(OkHttp.string(detailUrl.concat(ids.get(0)).concat("/"), getHeaders()));
|
||||
String name = doc.select("meta[property=og:title]").attr("content");
|
||||
String pic = doc.select("meta[property=og:image]").attr("content");
|
||||
String year = doc.select("span.inactive-color").get(0).text();
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(ids.get(0));
|
||||
vod.setVodPic(pic);
|
||||
vod.setVodYear(year.replace("上市於 ", ""));
|
||||
vod.setVodName(name);
|
||||
vod.setVodPlayFrom("Jable");
|
||||
vod.setVodPlayUrl("播放$" + Util.getVar(doc.html(), "hlsUrl"));
|
||||
return Result.string(vod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(searchUrl.concat(URLEncoder.encode(key)).concat("/"), getHeaders()));
|
||||
for (Element element : doc.select("div.video-img-box")) {
|
||||
String pic = element.select("img").attr("data-src");
|
||||
String url = element.select("a").attr("href");
|
||||
String name = element.select("div.detail > h6").text();
|
||||
String id = url.split("/")[4];
|
||||
list.add(new Vod(id, name, pic));
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
return Result.get().url(id).header(getHeaders()).string();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Util;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Qile
|
||||
*/
|
||||
public class JavDb extends Spider {
|
||||
|
||||
private static String siteUrl = "https://javdb523.com";
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
if (!extend.isEmpty()) siteUrl = extend;
|
||||
}
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
header.put("Referer", siteUrl + "/");
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) throws Exception {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
List<String> typeIds = Arrays.asList("", "censored", "uncensored", "western");
|
||||
List<String> typeNames = Arrays.asList("全部", "有码", "无码", "欧美");
|
||||
for (int i = 0; i < typeIds.size(); i++) classes.add(new Class(typeIds.get(i), typeNames.get(i)));
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeader()));
|
||||
List<Vod> list = new ArrayList<>();
|
||||
for (Element li : doc.select(".item")) {
|
||||
String vid = siteUrl + li.select("a").attr("href");
|
||||
String name = li.select("a").attr("title");
|
||||
String pic = li.select("img").attr("src");
|
||||
list.add(new Vod(vid, name, pic));
|
||||
}
|
||||
return Result.string(classes, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||
String cateUrl = siteUrl + String.format("/%s?page=%s", tid, pg);
|
||||
Document doc = Jsoup.parse(OkHttp.string(cateUrl, getHeader()));
|
||||
List<Vod> list = new ArrayList<>();
|
||||
for (Element li : doc.select(".item")) {
|
||||
String vid = siteUrl + li.select("a").attr("href");
|
||||
String name = li.select("a").attr("title");
|
||||
String pic = li.select("img").attr("src");
|
||||
list.add(new Vod(vid, name, pic));
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
Document doc = Jsoup.parse(OkHttp.string(ids.get(0), getHeader()));
|
||||
if (doc.text().contains("歡迎登入")) return Result.error("该资源需要登入");
|
||||
List<String> vodItems = new ArrayList<>();
|
||||
Elements sourceList = doc.select(".item.columns");
|
||||
for (Element a : sourceList) {
|
||||
String episodeUrl = a.select("div a").attr("href");
|
||||
String episodeName = a.select("div a").text();
|
||||
vodItems.add(episodeName + "$" + episodeUrl);
|
||||
}
|
||||
Elements elements = doc.select(".panel-block");
|
||||
String classifyName = "";
|
||||
String year = "";
|
||||
String area = "";
|
||||
String remark = "";
|
||||
for (Element element : elements) {
|
||||
String text = element.text();
|
||||
if (text.startsWith("類別:")) {
|
||||
classifyName = element.select("span a").text();
|
||||
} else if (text.startsWith("片商:")) {
|
||||
area = element.select("span a").text();
|
||||
} else if (text.startsWith("日期:")) {
|
||||
year = element.select("span").text();
|
||||
} else if (text.startsWith("時長:")) {
|
||||
remark = element.select("span").text();
|
||||
}
|
||||
}
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(ids.get(0));
|
||||
vod.setVodYear(year);
|
||||
vod.setVodArea(area);
|
||||
vod.setVodRemarks(remark);
|
||||
vod.setTypeName(classifyName);
|
||||
vod.setVodContent(ids.get(0));
|
||||
vod.setVodPlayFrom("Qile");
|
||||
vod.setVodPlayUrl(TextUtils.join("#", vodItems));
|
||||
return Result.string(vod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
String searchUrl = siteUrl + "/search?q=" + Uri.encode(key) + "&f=all";
|
||||
Document doc = Jsoup.parse(OkHttp.string(searchUrl, getHeader()));
|
||||
List<Vod> list = new ArrayList<>();
|
||||
for (Element li : doc.select(".item")) {
|
||||
String vid = siteUrl + li.select("a").attr("href");
|
||||
String name = li.select("a").attr("title");
|
||||
String pic = li.select("img").attr("src");
|
||||
list.add(new Vod(vid, name, pic));
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
return Result.get().url(id).header(getHeader()).string();
|
||||
}
|
||||
}
|
||||
|
|
@ -8,13 +8,9 @@ import com.github.catvod.bean.Vod;
|
|||
import com.github.catvod.bean.jianpian.Data;
|
||||
import com.github.catvod.bean.jianpian.Detail;
|
||||
import com.github.catvod.bean.jianpian.Resp;
|
||||
import com.github.catvod.bean.jianpian.Search;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.github.catvod.utils.Json;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -28,87 +24,66 @@ import java.util.Map;
|
|||
*/
|
||||
public class Jianpian extends Spider {
|
||||
|
||||
private String siteUrl = "https://ev5356.970xw.com";
|
||||
private String imgDomain;
|
||||
private final String siteUrl = "http://api2.rinhome.com";
|
||||
private String extend;
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Linux; Android 9; V2196A Build/PQ3A.190705.08211809; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/91.0.4472.114 Mobile Safari/537.36;webank/h5face;webank/1.0;netType:NETWORK_WIFI;appVersion:416;packageName:com.jp3.xg3");
|
||||
headers.put("Referer", siteUrl);
|
||||
headers.put("User-Agent", "jianpian-android/360");
|
||||
headers.put("JPAUTH", "y261ow7kF2dtzlxh1GS9EB8nbTxNmaK/QQIAjctlKiEv");
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
this.extend = extend;
|
||||
JsonObject domains = new Gson().fromJson(OkHttp.string("https://dns.alidns.com/resolve?name=swrdsfeiujo25sw.cc&type=TXT"), JsonObject.class);
|
||||
String parts = domains.getAsJsonArray("Answer").get(0).getAsJsonObject().get("data").getAsString();
|
||||
parts = parts.replace("\"", "");
|
||||
String[] domain = parts.split(",");
|
||||
for (String d : domain) {
|
||||
siteUrl = "https://wangerniu." + d;
|
||||
String json = OkHttp.string(siteUrl + "/api/appAuthConfig");
|
||||
if (!json.isEmpty()) {
|
||||
JsonObject root = new Gson().fromJson(json, JsonObject.class);
|
||||
imgDomain = root.getAsJsonObject("data").get("imgDomain").getAsString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) throws Exception {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
List<String> typeIds = Arrays.asList("1", "2", "3", "4", "50", "99");
|
||||
List<String> typeNames = Arrays.asList("電影", "電視劇", "動漫", "綜藝", "紀錄片", "Netflix");
|
||||
List<String> typeIds = Arrays.asList("0", "1", "2", "3", "4");
|
||||
List<String> typeNames = Arrays.asList("全部", "电影", "电视剧", "动漫", "综艺");
|
||||
for (int i = 0; i < typeIds.size(); i++) classes.add(new Class(typeIds.get(i), typeNames.get(i)));
|
||||
return Result.string(classes, JsonParser.parseString(OkHttp.string(extend)));
|
||||
return Result.string(classes, Json.parse(OkHttp.string(extend)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeVideoContent() {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
String url = siteUrl + "/api/slide/list?pos_id=88";
|
||||
String url = siteUrl + "/api/slide/list?code=unknown9039b6856c3a3306&pos_id=888&channel=wandoujia";
|
||||
Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader()));
|
||||
for (Data data : resp.getData()) list.add(data.homeVod(imgDomain));
|
||||
for (Data data : resp.getData()) list.add(data.vod());
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||
if (tid.endsWith("/{pg}")) return searchContent(tid.split("/")[0], pg);
|
||||
if (tid.equals("50") || tid.equals("99") || tid.equals("111")) {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
String url = siteUrl + String.format("/api/dyTag/list?category_id=%s&page=%s", tid, pg);
|
||||
Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader()));
|
||||
for (Data data : resp.getData()) for (Data dataList : data.getDataList()) list.add(dataList.vod(imgDomain));
|
||||
return Result.get().page().vod(list).string();
|
||||
} else {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
HashMap<String, String> ext = new HashMap<>();
|
||||
if (extend != null && !extend.isEmpty()) ext.putAll(extend);
|
||||
String area = ext.get("area") == null ? "0" : ext.get("area");
|
||||
String year = ext.get("year") == null ? "0" : ext.get("year");
|
||||
String by = ext.get("by") == null ? "updata" : ext.get("by");
|
||||
String url = siteUrl + String.format("/api/crumb/list?fcate_pid=%s&area=%s&year=%s&type=0&sort=%s&page=%s&category_id=", tid, area, year, by, pg);
|
||||
Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader()));
|
||||
for (Data data : resp.getData()) list.add(data.vod(imgDomain));
|
||||
return Result.string(list);
|
||||
}
|
||||
List<Vod> list = new ArrayList<>();
|
||||
HashMap<String, String> ext = new HashMap<>();
|
||||
if (extend != null && extend.size() > 0) ext.putAll(extend);
|
||||
String cateId = ext.get("cateId") == null ? tid : ext.get("cateId");
|
||||
String area = ext.get("area") == null ? "0" : ext.get("area");
|
||||
String year = ext.get("year") == null ? "0" : ext.get("year");
|
||||
String by = ext.get("by") == null ? "hot" : ext.get("by");
|
||||
String url = siteUrl + String.format("/api/crumb/list?area=%s&category_id=%s&page=%s&type=0&limit=24&sort=%s&year=%s", area, cateId, pg, by, year);
|
||||
Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader()));
|
||||
for (Data data : resp.getData()) list.add(data.vod());
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
String url = siteUrl + "/api/video/detailv2?id=" + ids.get(0);
|
||||
String url = siteUrl + "/api/node/detail?channel=wandoujia&token=&id=" + ids.get(0);
|
||||
Data data = Detail.objectFrom(OkHttp.string(url, getHeader())).getData();
|
||||
Vod vod = data.vod(imgDomain);
|
||||
vod.setVodPlayFrom(data.getVodFrom());
|
||||
Vod vod = data.vod();
|
||||
vod.setVodPlayFrom("Jianpian");
|
||||
vod.setVodYear(data.getYear());
|
||||
vod.setVodArea(data.getArea());
|
||||
vod.setTypeName(data.getTypes());
|
||||
vod.setVodActor(data.getActors());
|
||||
vod.setVodPlayUrl(data.getVodUrl());
|
||||
vod.setVodPlayUrl(data.getPlayUrl());
|
||||
vod.setVodDirector(data.getDirectors());
|
||||
vod.setVodContent(data.getDescription());
|
||||
return Result.string(vod);
|
||||
|
|
@ -131,9 +106,9 @@ public class Jianpian extends Spider {
|
|||
|
||||
public String searchContent(String key, String pg) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
String url = siteUrl + String.format("/api/v2/search/videoV2?key=%s&category_id=88&page=%s&pageSize=20", URLEncoder.encode(key), pg);
|
||||
Search search = Search.objectFrom(OkHttp.string(url, getHeader()));
|
||||
for (Search data : search.getData()) list.add(data.vod(imgDomain));
|
||||
String url = siteUrl + "/api/video/search?page=" + pg + "&key=" + URLEncoder.encode(key);
|
||||
Resp resp = Resp.objectFrom(OkHttp.string(url, getHeader()));
|
||||
for (Data data : resp.getData()) list.add(data.vod());
|
||||
return Result.string(list);
|
||||
}
|
||||
}
|
||||
|
|
@ -145,7 +145,7 @@ public class JustLive extends Spider {
|
|||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
String searchUrl = siteUrl + "/api/live/search?platform=all&keyWords=" + URLEncoder.encode(key) + "&uid=f12b7678af364cb4b3c318559ade200e";
|
||||
String searchUrl = siteUrl + "/api/live/search?platform=all&keyWords=" + URLEncoder.encode(key) + "&uid=35717d71548f4ec9ab6f327cc16ad2bf";
|
||||
String content = OkHttp.string(searchUrl, getHeader());
|
||||
List<Vod> list = new ArrayList<>();
|
||||
JSONArray dataArray = new JSONObject(content).getJSONArray("data");
|
||||
|
|
|
|||
|
|
@ -1,152 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Util;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 夸克吧
|
||||
*
|
||||
* @author lushunming
|
||||
*/
|
||||
public class KuaKeBa extends Cloud {
|
||||
|
||||
private final String siteUrl = "https://www.kuakeba.top/yunpan";
|
||||
private final String hostUrl = "https://www.kuakeba.top";
|
||||
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
return header;
|
||||
}
|
||||
|
||||
private Map<String, String> getHeaderWithCookie() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
header.put("cookie", "esc_search_captcha=1; result=43");
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
|
||||
super.init(context, extend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeader()));
|
||||
Elements elements = doc.select(" div.catleader > ul > li > a");
|
||||
for (Element e : elements) {
|
||||
String url = e.attr("href");
|
||||
String name = e.text();
|
||||
classes.add(new Class(url, name));
|
||||
}
|
||||
|
||||
return Result.string(classes, parseVodListFromDoc(doc));
|
||||
}
|
||||
|
||||
private List<Vod> parseVodListFromDoc(Document doc) {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Elements elements = doc.select(" article.excerpt");
|
||||
for (Element e : elements) {
|
||||
String vodId = e.selectFirst(" a").attr("href");
|
||||
String vodPic = e.selectFirst(" img").attr("data-src");
|
||||
if (!vodPic.startsWith("http")) {
|
||||
vodPic = hostUrl + vodPic;
|
||||
}
|
||||
String vodName = e.selectFirst(" header > h2 > a").text();
|
||||
String vodRemarks = "";
|
||||
list.add(new Vod(vodId, vodName, vodPic, vodRemarks));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
|
||||
Document doc = Jsoup.parse(OkHttp.string(String.format("%s/page/%s", tid, pg), getHeader()));
|
||||
List<Vod> list = parseVodListFromDoc(doc);
|
||||
int total = (Integer.parseInt(pg) + 1) * 20;
|
||||
return Result.get().vod(list).page(Integer.parseInt(pg), Integer.parseInt(pg) + 1, 20, total).string();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
String vodId = ids.get(0);
|
||||
Document doc = Jsoup.parse(OkHttp.string(vodId, getHeader()));
|
||||
|
||||
Vod item = new Vod();
|
||||
item.setVodId(vodId);
|
||||
item.setVodName(doc.selectFirst(" h1.article-title > a").text());
|
||||
item.setVodPic(doc.selectFirst(" img").attr("src"));
|
||||
item.setVodArea(getStrByRegex(Pattern.compile("导演:(.*?)<br"), doc.html()));
|
||||
item.setVodDirector(getStrByRegex(Pattern.compile("地区:(.*?)<br"), doc.html()));
|
||||
item.setVodActor(getStrByRegex(Pattern.compile("主演:(.*?)<br"), doc.html()));
|
||||
item.setVodYear(getStrByRegex(Pattern.compile("上映日期:(.*?)<br"), doc.html()));
|
||||
item.setVodRemarks("");
|
||||
item.setVodContent(getStrByRegex(Pattern.compile("<h2>剧情简介</h2>\n(.*?)</p>"), doc.html()).replace("<p>", ""));
|
||||
|
||||
List<String> shareLinks = new ArrayList<>();
|
||||
List<String> tags = new ArrayList<>();
|
||||
for (Element element : doc.select("article.article-content p a")) {
|
||||
if (element.attr("href").matches(Util.patternQuark)) {
|
||||
shareLinks.add(element.attr("href").trim());
|
||||
} else if (element.attr("href").contains("tag")) {
|
||||
tags.add(element.attr("href"));
|
||||
}
|
||||
}
|
||||
|
||||
item.setTypeName(String.join(",", tags));
|
||||
|
||||
item.setVodPlayUrl(super.detailContentVodPlayUrl(shareLinks));
|
||||
item.setVodPlayFrom(super.detailContentVodPlayFrom(shareLinks));
|
||||
|
||||
return Result.string(item);
|
||||
}
|
||||
|
||||
private String getStrByRegex(Pattern pattern, String str) {
|
||||
Matcher matcher = pattern.matcher(str);
|
||||
if (matcher.find()) return matcher.group(1).trim();
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
return searchContent(key, "1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick, String pg) throws Exception {
|
||||
return searchContent(key, pg);
|
||||
}
|
||||
|
||||
private String searchContent(String key, String pg) {
|
||||
String searchURL = siteUrl + String.format("/?s=%s", URLEncoder.encode(key));
|
||||
String html = OkHttp.string(searchURL, getHeaderWithCookie());
|
||||
Document doc = Jsoup.parse(html);
|
||||
|
||||
return Result.string(parseVodListFromDoc(doc));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 夸克社
|
||||
*
|
||||
* @author lushunming
|
||||
* @createdate 2024-12-03
|
||||
*/
|
||||
public class KuaKeS extends Cloud {
|
||||
|
||||
private final String siteUrl = "https://kuakes.com";
|
||||
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
return header;
|
||||
}
|
||||
|
||||
private Map<String, String> getHeaderWithCookie() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
header.put("cookie", "esc_search_captcha=1; result=43");
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
|
||||
super.init(context, extend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeader()));
|
||||
Elements elements = doc.select(" #J_topNavMb a");
|
||||
for (Element e : elements) {
|
||||
String url = e.attr("href");
|
||||
String name = e.text();
|
||||
if (url.contains(siteUrl)) {
|
||||
classes.add(new Class(url, name));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Result.string(classes, parseVodListFromDoc(doc));
|
||||
}
|
||||
|
||||
private List<Vod> parseVodListFromDoc(Document doc) {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Elements elements = doc.select(" div.articles-list > article.post");
|
||||
for (Element e : elements) {
|
||||
String vodId = e.selectFirst(" a.post-title").attr("href");
|
||||
String vodPic = e.selectFirst(" img").attr("data-lazy-src");
|
||||
if (!vodPic.startsWith("http")) {
|
||||
vodPic = siteUrl + vodPic;
|
||||
}
|
||||
String vodName = e.selectFirst("a.post-title").text();
|
||||
String vodRemarks = Objects.nonNull(e.selectFirst("span.db_score")) ? e.selectFirst("span.db_score").text() : "";
|
||||
;
|
||||
list.add(new Vod(vodId, vodName, vodPic, vodRemarks));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
|
||||
Document doc = Jsoup.parse(OkHttp.string(String.format("%s/page/%s", tid, pg), getHeader()));
|
||||
List<Vod> list = parseVodListFromDoc(doc);
|
||||
int total = (Integer.parseInt(pg) + 1) * 19;
|
||||
return Result.get().vod(list).page(Integer.parseInt(pg), Integer.parseInt(pg) + 1, 19, total).string();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
String vodId = ids.get(0);
|
||||
Document doc = Jsoup.parse(OkHttp.string(vodId, getHeader()));
|
||||
|
||||
Vod item = new Vod();
|
||||
item.setVodId(vodId);
|
||||
item.setVodName(doc.selectFirst(" h1.title-detail").text());
|
||||
item.setVodPic(doc.selectFirst("div.media-pic img").attr("data-lazy-src"));
|
||||
String html = doc.select("div.wp-block-media-text__content > p").text();
|
||||
item.setVodDirector(getStrByRegex(Pattern.compile("导演:(.*?)编剧:"), html));
|
||||
item.setVodArea(getStrByRegex(Pattern.compile("地区:(.*?)语言:"), html));
|
||||
item.setVodActor(getStrByRegex(Pattern.compile("主演:(.*?)类型:"), html));
|
||||
item.setVodYear(getStrByRegex(Pattern.compile("上映日期:(.*?)\\()"), html));
|
||||
item.setTypeName(getStrByRegex(Pattern.compile("类型:(.*?)制片"), html));
|
||||
item.setVodRemarks("");
|
||||
item.setVodContent(doc.select("div.article-detail > p").text());
|
||||
|
||||
List<String> shareLinks = new ArrayList<>();
|
||||
Elements elements = doc.select("div.magicpost-cont-bd > a");
|
||||
String rid = elements.attr("data-rid");
|
||||
String pid = elements.attr("data-pid");
|
||||
String action = "wb_mpdl_front";
|
||||
|
||||
String result = OkHttp.post("https://kuakes.com/wp-admin/admin-ajax.php", Map.of("action", action, "rid", rid, "pid", pid));
|
||||
JsonObject object = Json.safeObject(result);
|
||||
JsonObject data = object.get("data").getAsJsonObject();
|
||||
String url = data.get("url").getAsString();
|
||||
shareLinks.add(url);
|
||||
item.setVodPlayUrl(super.detailContentVodPlayUrl(shareLinks));
|
||||
item.setVodPlayFrom(super.detailContentVodPlayFrom(shareLinks));
|
||||
|
||||
return Result.string(item);
|
||||
}
|
||||
|
||||
private String getStrByRegex(Pattern pattern, String str) {
|
||||
Matcher matcher = pattern.matcher(str);
|
||||
if (matcher.find()) return matcher.group(1).trim();
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
return searchContent(key, "1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick, String pg) throws Exception {
|
||||
return searchContent(key, pg);
|
||||
}
|
||||
|
||||
private String searchContent(String key, String pg) {
|
||||
String searchURL = siteUrl + String.format("/?s=%s", URLEncoder.encode(key));
|
||||
String html = OkHttp.string(searchURL, getHeaderWithCookie());
|
||||
Document doc = Jsoup.parse(html);
|
||||
|
||||
return Result.string(parseVodListFromDoc(doc));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class LeiJing extends Cloud {
|
||||
private static final String siteUrl = "https://leijing1.com/";
|
||||
|
||||
private final String hostUrl = siteUrl;
|
||||
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
return header;
|
||||
}
|
||||
|
||||
private Map<String, String> getHeaderWithCookie() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
header.put("cookie", "esc_search_captcha=1; result=43");
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
|
||||
super.init(context, extend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeader()));
|
||||
Elements elements = doc.select(" #tabNavigation > a.tab");
|
||||
for (Element e : elements) {
|
||||
String url = e.attr("href");
|
||||
String name = e.text();
|
||||
if (StringUtils.isNoneBlank(url)) {
|
||||
classes.add(new Class(url, name));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Result.string(classes, parseVodListFromDoc(doc));
|
||||
}
|
||||
|
||||
private List<Vod> parseVodListFromDoc(Document doc) {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
|
||||
Elements topicItems = doc.select(".topicItem");
|
||||
|
||||
for (Element each : topicItems) {
|
||||
// 检查是否有锁定标记
|
||||
if (each.select(".cms-lock-solid").size() > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 提取href
|
||||
String href = each.select("h2 a").attr("href");
|
||||
// 提取标题并处理空格
|
||||
String title = each.select("h2 a").text().trim().replaceAll("\\s+", " ");
|
||||
// 提取摘要
|
||||
String r = each.select(".summary").text();
|
||||
// 提取标签
|
||||
String tag = each.select(".tag").text();
|
||||
|
||||
// 过滤条件
|
||||
if (r.contains("content") && !r.contains("cloud")) {
|
||||
continue;
|
||||
}
|
||||
if (tag.contains("软件") || tag.contains("游戏") || tag.contains("书籍") || tag.contains("图片") || tag.contains("公告") || tag.contains("音乐") || tag.contains("课程")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 创建Video对象
|
||||
Vod video = new Vod(href, title, "", "");
|
||||
list.add(video);
|
||||
}
|
||||
return list;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
|
||||
Document doc = Jsoup.parse(OkHttp.string(String.format("%s%s&page=%s", siteUrl, tid, pg), getHeader()));
|
||||
List<Vod> list = parseVodListFromDoc(doc);
|
||||
int total = (Integer.parseInt(pg) + 1) * 30;
|
||||
return Result.get().vod(list).page(Integer.parseInt(pg), Integer.parseInt(pg) + 1, 30, total).string();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
String vodId = ids.get(0);
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl + vodId, getHeader()));
|
||||
|
||||
|
||||
Vod item = new Vod();
|
||||
item.setVodId(vodId);
|
||||
item.setVodName(doc.selectFirst("div.title").text());
|
||||
|
||||
Elements elements = doc.select("a");
|
||||
List<String> shareLinks = new ArrayList<>();
|
||||
|
||||
for (Element element : elements) {
|
||||
if (element.attr("href").contains("https://cloud.189.cn")) {
|
||||
shareLinks.add(element.attr("href"));
|
||||
}
|
||||
}
|
||||
item.setVodPlayUrl(super.detailContentVodPlayUrl(shareLinks));
|
||||
item.setVodPlayFrom(super.detailContentVodPlayFrom(shareLinks));
|
||||
|
||||
return Result.string(item);
|
||||
}
|
||||
|
||||
private String getStrByRegex(Pattern pattern, String str) {
|
||||
Matcher matcher = pattern.matcher(str);
|
||||
if (matcher.find()) return matcher.group(1).trim();
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
return searchContent(key, "1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick, String pg) throws Exception {
|
||||
return searchContent(key, pg);
|
||||
}
|
||||
|
||||
private String searchContent(String key, String pg) {
|
||||
String searchURL = siteUrl + String.format("search?keyword=%s", URLEncoder.encode(key));
|
||||
String html = OkHttp.string(searchURL, getHeaderWithCookie());
|
||||
Document doc = Jsoup.parse(html);
|
||||
|
||||
return Result.string(parseVodListFromDoc(doc));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,247 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.JsonElement;
|
||||
import org.json.JSONObject;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Libvio extends Cloud {
|
||||
|
||||
private static String siteUrl = "https://www.libvio.link/";
|
||||
|
||||
|
||||
private static final String 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";
|
||||
|
||||
private HashMap<String, String> getHeaders() {
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", MOBILE_UA);
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
private HashMap<String, String> getHeaders(String refer) {
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", MOBILE_UA);
|
||||
headers.put("Referer", refer);
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
JsonElement json = Json.parse(extend);
|
||||
super.init(context, extend);
|
||||
String html = OkHttp.string(json.getAsJsonObject().get("site").getAsString());
|
||||
Document doc = Jsoup.parse(html);
|
||||
for (Element element : doc.select(" a")) {
|
||||
if (element.text().contains("可用")) {
|
||||
siteUrl = element.attr("href");
|
||||
break;
|
||||
}
|
||||
}
|
||||
SpiderDebug.log("libvio跳转地址 =====>" + siteUrl); // js_debug.log
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
List<Class> classes = new ArrayList<>();
|
||||
|
||||
|
||||
String link = siteUrl;
|
||||
Document doc = Jsoup.parse(OkHttp.string(link, getHeaders()));
|
||||
for (Element element : doc.select("ul.stui-header__menu > li > a")) {
|
||||
classes.add(new Class(element.attr("href").replace(".html", ""), element.text()));
|
||||
}
|
||||
|
||||
for (Element element : doc.select("ul.stui-vodlist > li > div > a")) {
|
||||
|
||||
String pic = element.attr("data-original");
|
||||
String url = element.attr("href");
|
||||
String name = element.attr("title");
|
||||
if (!pic.startsWith("http")) {
|
||||
pic = siteUrl + pic;
|
||||
}
|
||||
String id = url.split("/")[2];
|
||||
list.add(new Vod(id, name, pic));
|
||||
|
||||
}
|
||||
return Result.string(classes, list);
|
||||
}
|
||||
|
||||
public String MD5(String string) {
|
||||
// 创建 MD5 实例
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
// 计算 MD5 哈希值
|
||||
byte[] hashBytes = md.digest(string.getBytes());
|
||||
|
||||
// 将字节数组转换为十六进制字符串表示
|
||||
StringBuilder hexString = new StringBuilder();
|
||||
for (byte hashByte : hashBytes) {
|
||||
String hex = Integer.toHexString(0xff & hashByte);
|
||||
if (hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
|
||||
// 输出加密后的 MD5 字符串
|
||||
System.out.println("MD5 加密: " + hexString.toString());
|
||||
return hexString.toString();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
|
||||
String target = siteUrl + tid + "-" + pg + ".html";
|
||||
Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
|
||||
for (Element element : doc.select("ul.stui-vodlist > li > div > a")) {
|
||||
|
||||
String pic = element.attr("data-original");
|
||||
String url = element.attr("href");
|
||||
String name = element.attr("title");
|
||||
if (!pic.startsWith("http")) {
|
||||
pic = siteUrl + pic;
|
||||
}
|
||||
String id = url.split("/")[2];
|
||||
list.add(new Vod(id, name, pic));
|
||||
|
||||
}
|
||||
|
||||
Integer total = (Integer.parseInt(pg) + 1) * 20;
|
||||
return Result.string(Integer.parseInt(pg), Integer.parseInt(pg) + 1, 20, total, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl.concat("/detail/").concat(ids.get(0)), getHeaders()));
|
||||
String name = doc.select("body > div:nth-child(3) > div.row > div > div > div > div.stui-content > div.stui-content__detail > h1").text();
|
||||
String pic = doc.select("div.stui-content__thumb > a >img").attr("data-original");
|
||||
// 播放源
|
||||
Elements tabs = doc.select("div.stui-vodlist__head > div > h3");
|
||||
Elements list = doc.select("div.stui-vodlist__head > ul.stui-content__playlist ");
|
||||
|
||||
Vod.VodPlayBuilder builder = new Vod.VodPlayBuilder();
|
||||
List<String> quarkList = new ArrayList<>();
|
||||
for (int i = 0; i < tabs.size(); i++) {
|
||||
List<Vod.VodPlayBuilder.PlayUrl> playUrls = new ArrayList<>();
|
||||
|
||||
String tabName = tabs.get(i).text();
|
||||
|
||||
Elements li = list.get(i).select("a");
|
||||
for (Element element : li) {
|
||||
if (tabName.contains("夸克") || tabName.contains("UC")) {
|
||||
quarkList.add(element.attr("href"));
|
||||
} else {
|
||||
Vod.VodPlayBuilder.PlayUrl playUrl = new Vod.VodPlayBuilder.PlayUrl();
|
||||
playUrl.name = element.text();
|
||||
playUrl.url = element.attr("href").replace("/play/", "");
|
||||
playUrls.add(playUrl);
|
||||
}
|
||||
|
||||
}
|
||||
if (!tabName.contains("夸克") && !tabName.contains("UC")) {
|
||||
builder.append(tabName, playUrls);
|
||||
}
|
||||
}
|
||||
List<String> shareLinks = new ArrayList<>();
|
||||
String quarkNames = "";
|
||||
String quarkUrls = "";
|
||||
|
||||
if (!quarkList.isEmpty()) {
|
||||
for (String s : quarkList) {
|
||||
Document detailPageDoc = Jsoup.parse(OkHttp.string(siteUrl.concat(s), getHeaders()));
|
||||
Matcher matcher = Pattern.compile("player_aaaa=(.*?)</script>").matcher(detailPageDoc.html());
|
||||
String json = matcher.find() ? matcher.group(1) : "";
|
||||
org.json.JSONObject player = new JSONObject(json);
|
||||
String url = player.getString("url");
|
||||
shareLinks.add(url);
|
||||
}
|
||||
quarkUrls = super.detailContentVodPlayUrl(shareLinks);
|
||||
quarkNames = super.detailContentVodPlayFrom(shareLinks);
|
||||
}
|
||||
|
||||
Vod.VodPlayBuilder.BuildResult result = builder.build();
|
||||
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(ids.get(0));
|
||||
vod.setVodPic(siteUrl + pic);
|
||||
vod.setVodName(name);
|
||||
vod.setVodPlayFrom(result.vodPlayFrom + "$$$" + quarkNames);
|
||||
vod.setVodPlayUrl(result.vodPlayUrl + "$$$" + quarkUrls);
|
||||
return Result.string(vod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl.concat("/search/-------------.html?wd=").concat(URLEncoder.encode(key)), getHeaders()));
|
||||
for (Element element : doc.select("ul.stui-vodlist > li > div > a")) {
|
||||
|
||||
String pic = element.attr("data-original");
|
||||
String url = element.attr("href");
|
||||
String name = element.attr("title");
|
||||
if (!pic.startsWith("http")) {
|
||||
pic = siteUrl + pic;
|
||||
}
|
||||
String id = url.split("/")[2];
|
||||
list.add(new Vod(id, name, pic));
|
||||
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
if (flag.contains("quark")) {
|
||||
return super.playerContent(flag, id, vipFlags);
|
||||
}
|
||||
String target = siteUrl.concat("/play/").concat(id);
|
||||
Document doc = Jsoup.parse(OkHttp.string(target));
|
||||
Matcher matcher = Pattern.compile("player_aaaa=(.*?)</script>").matcher(doc.html());
|
||||
String json = matcher.find() ? matcher.group(1) : "";
|
||||
org.json.JSONObject player = new JSONObject(json);
|
||||
String url = player.getString("url");
|
||||
String from = player.getString("from");
|
||||
String next = player.getString("link_next");
|
||||
String vodid = player.getString("id");
|
||||
String nid = player.getString("nid");
|
||||
String paurl = OkHttp.string(siteUrl + "/static/player/" + from + ".js");
|
||||
Matcher matcher1 = Pattern.compile(" src=\"(.*?)'").matcher(paurl);
|
||||
paurl = matcher1.find() ? matcher1.group(1) : "";
|
||||
String purl = paurl + url + "&next=" + next + "&id=" + vodid + "&nid=" + nid;
|
||||
if (!purl.startsWith("http")) {
|
||||
purl = siteUrl.replace("www.", "") + purl;
|
||||
}
|
||||
String playUrl = OkHttp.string(purl, getHeaders(target.replace("www.", "")));
|
||||
|
||||
String realUrl = Util.getVar(playUrl, "vid");
|
||||
|
||||
return Result.get().url(realUrl).header(getHeaders()).string();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Util;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author zhixc
|
||||
*/
|
||||
public class Mogg extends Cloud {
|
||||
|
||||
private final String siteUrl = "https://woog.nxog.eu.org/";
|
||||
private final Pattern regexCategory = Pattern.compile("index.php/vod/type/id/(\\w+).html");
|
||||
private final Pattern regexPageTotal = Pattern.compile("\\$\\(\"\\.mac_total\"\\)\\.text\\('(\\d+)'\\);");
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
// JsonObject ext = Json.safeObject(extend);
|
||||
super.init(context, extend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeader()));
|
||||
Elements elements = doc.select(".nav-link");
|
||||
for (Element e : elements) {
|
||||
Matcher mather = regexCategory.matcher(e.attr("href"));
|
||||
if (mather.find()) {
|
||||
classes.add(new Class(mather.group(1), e.text().trim()));
|
||||
}
|
||||
}
|
||||
return Result.string(classes, parseVodListFromDoc(doc));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
String[] urlParams = new String[]{tid, "", "", "", "", "", "", "", pg, "", "", ""};
|
||||
if (extend != null && extend.size() > 0) {
|
||||
for (String key : extend.keySet()) {
|
||||
urlParams[Integer.parseInt(key)] = extend.get(key);
|
||||
}
|
||||
}
|
||||
Document doc = Jsoup.parse(OkHttp.string(String.format("%s/index.php/vod/show/id/%s/page/%s.html", siteUrl, tid, pg), getHeader()));
|
||||
int page = Integer.parseInt(pg), limit = 72, total = 0;
|
||||
Matcher matcher = regexPageTotal.matcher(doc.html());
|
||||
if (matcher.find()) total = Integer.parseInt(matcher.group(1));
|
||||
int count = total <= limit ? 1 : ((int) Math.ceil(total / (double) limit));
|
||||
return Result.get().vod(parseVodListFromDoc(doc)).page(page, count, limit, total).string();
|
||||
}
|
||||
|
||||
private List<Vod> parseVodListFromDoc(Document doc) {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Elements elements = doc.select(".module-item");
|
||||
for (Element e : elements) {
|
||||
String vodId = e.selectFirst(".video-name a").attr("href");
|
||||
String vodPic = e.selectFirst(".module-item-pic > img").attr("data-src");
|
||||
String vodName = e.selectFirst(".video-name").text();
|
||||
String vodRemarks = e.selectFirst(".module-item-text").text();
|
||||
list.add(new Vod(vodId, vodName, vodPic, vodRemarks));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
String vodId = ids.get(0);
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl + vodId, getHeader()));
|
||||
|
||||
Vod item = new Vod();
|
||||
item.setVodId(vodId);
|
||||
item.setVodName(doc.selectFirst(".video-info-header > .page-title").text());
|
||||
item.setVodPic(doc.selectFirst(".module-item-pic img").attr("data-src"));
|
||||
item.setVodArea(doc.select(".video-info-header a.tag-link").last().text());
|
||||
item.setTypeName(String.join(",", doc.select(".video-info-header div.tag-link a").eachText()));
|
||||
|
||||
List<String> shareLinks = doc.select(".module-row-text").eachAttr("data-clipboard-text");
|
||||
for (int i = 0; i < shareLinks.size(); i++) {
|
||||
shareLinks.set(i, shareLinks.get(i).trim());
|
||||
//String detailContent = super.detailContent(List.of(shareLinks.get(i)));
|
||||
}
|
||||
item.setVodPlayUrl(super.detailContentVodPlayUrl(shareLinks));
|
||||
item.setVodPlayFrom(super.detailContentVodPlayFrom(shareLinks));
|
||||
|
||||
Elements elements = doc.select(".video-info-item");
|
||||
for (Element e : elements) {
|
||||
String title = e.previousElementSibling().text();
|
||||
if (title.contains("导演")) {
|
||||
item.setVodDirector(String.join(",", e.select("a").eachText()));
|
||||
} else if (title.contains("主演")) {
|
||||
item.setVodActor(String.join(",", e.select("a").eachText()));
|
||||
} else if (title.contains("年代")) {
|
||||
item.setVodYear(e.selectFirst("a").text().trim());
|
||||
} else if (title.contains("备注")) {
|
||||
item.setVodRemarks(e.text().trim());
|
||||
} else if (title.contains("剧情")) {
|
||||
item.setVodContent(e.selectFirst(".sqjj_a").text().replace("[收起部分]", "").trim());
|
||||
}
|
||||
}
|
||||
|
||||
return Result.string(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
return searchContent(key, "1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick, String pg) throws Exception {
|
||||
return searchContent(key, pg);
|
||||
}
|
||||
|
||||
|
||||
private String searchContent(String key, String pg) {
|
||||
String searchURL = siteUrl + String.format("/index.php/vod/search/page/%s/wd/%s.html", pg,URLEncoder.encode(key));
|
||||
String html = OkHttp.string(searchURL, getHeader());
|
||||
Elements items = Jsoup.parse(html).select(".module-search-item");
|
||||
List<Vod> list = new ArrayList<>();
|
||||
for (Element item : items) {
|
||||
String vodId = item.select(".video-serial").attr("href");
|
||||
String name = item.select(".video-serial").attr("title");
|
||||
String pic = item.select(".module-item-pic > img").attr("data-src");
|
||||
String remark = item.select(".video-tag-icon").text();
|
||||
list.add(new Vod(vodId, name, pic, remark));
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.AESEncryption;
|
||||
import com.github.catvod.utils.Util;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class NCat extends Spider {
|
||||
|
||||
private static final String siteUrl = "https://www.ncat3.app";
|
||||
private static final String picUrl = "https://vres.wbadl.cn";
|
||||
private static final String cateUrl = siteUrl + "/show/";
|
||||
private static final String detailUrl = siteUrl + "/detail/";
|
||||
private static final String searchUrl = siteUrl + "/search?k=";
|
||||
private static final String playUrl = siteUrl + "/play/";
|
||||
|
||||
private HashMap<String, String> getHeaders() {
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", Util.CHROME);
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
List<Class> classes = new ArrayList<>();
|
||||
String[] typeIdList = {"1", "2", "3", "4", "6"};
|
||||
String[] typeNameList = {"电影", "连续剧", "动漫", "综艺", "短剧"};
|
||||
for (int i = 0; i < typeNameList.length; i++) {
|
||||
classes.add(new Class(typeIdList[i], typeNameList[i]));
|
||||
}
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeaders()));
|
||||
for (Element element : doc.select("div.module-item")) {
|
||||
try {
|
||||
String pic = element.select("img").last().attr("data-original");
|
||||
String url = element.select("a").attr("href");
|
||||
String name = element.select(".v-item-title").text().replace("可可影视-kekys.com", "").trim();
|
||||
if (!pic.startsWith("http")) {
|
||||
pic = picUrl + pic;
|
||||
}
|
||||
String id = url.split("/")[2];
|
||||
list.add(new Vod(id, name, pic));
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
return Result.string(classes, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
String target = cateUrl + tid + "-----3-" + pg + ".html";
|
||||
Document doc = Jsoup.parse(OkHttp.string(target, getHeaders()));
|
||||
for (Element element : doc.select("div.module-item")) {
|
||||
try {
|
||||
String pic = element.select("img").last().attr("data-original");
|
||||
String url = element.select("a").attr("href");
|
||||
String name = element.select(".v-item-title").text().replace("可可影视-kekys.com", "").trim();
|
||||
if (!pic.startsWith("http")) {
|
||||
pic = picUrl + pic;
|
||||
}
|
||||
String id = url.split("/")[2];
|
||||
list.add(new Vod(id, name, pic));
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
Integer total = (Integer.parseInt(pg) + 1) * 20;
|
||||
return Result.string(Integer.parseInt(pg), Integer.parseInt(pg) + 1, 20, total, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
Document doc = Jsoup.parse(OkHttp.string(detailUrl.concat(ids.get(0)), getHeaders()));
|
||||
String name = doc.select("div.detail-title strong").text();
|
||||
String pic = doc.select(".detail-pic img").last().attr("data-original");
|
||||
String year = doc.select("a.detail-tags-item").get(0).text();
|
||||
String desc = doc.select("div.detail-desc p").text();
|
||||
|
||||
// 播放源
|
||||
Elements tabs = doc.select("a.source-item");
|
||||
Elements list = doc.select("div.episode-list");
|
||||
String PlayFrom = "";
|
||||
String PlayUrl = "";
|
||||
for (int i = 0; i < tabs.size(); i++) {
|
||||
String tabName = tabs.get(i).select("span").last().text();
|
||||
if (Arrays.asList("超清", "4K(高峰不卡)").contains(tabName)) continue;
|
||||
if (!"".equals(PlayFrom)) {
|
||||
PlayFrom = PlayFrom + "$$$" + tabName;
|
||||
} else {
|
||||
PlayFrom = PlayFrom + tabName;
|
||||
}
|
||||
Elements li = list.get(i).select("a");
|
||||
String liUrl = "";
|
||||
for (int i1 = 0; i1 < li.size(); i1++) {
|
||||
if (!"".equals(liUrl)) {
|
||||
liUrl = liUrl + "#" + li.get(i1).text() + "$" + li.get(i1).attr("href").replace("/play/", "");
|
||||
} else {
|
||||
liUrl = liUrl + li.get(i1).text() + "$" + li.get(i1).attr("href").replace("/play/", "");
|
||||
}
|
||||
}
|
||||
if (!"".equals(PlayUrl)) {
|
||||
PlayUrl = PlayUrl + "$$$" + liUrl;
|
||||
} else {
|
||||
PlayUrl = PlayUrl + liUrl;
|
||||
}
|
||||
}
|
||||
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(ids.get(0));
|
||||
vod.setVodPic(picUrl + pic);
|
||||
vod.setVodYear(year);
|
||||
vod.setVodName(name);
|
||||
vod.setVodContent(desc);
|
||||
vod.setVodPlayFrom(PlayFrom);
|
||||
vod.setVodPlayUrl(PlayUrl);
|
||||
return Result.string(vod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(searchUrl.concat(URLEncoder.encode(key)).concat(".html"), getHeaders()));
|
||||
for (Element element : doc.select("a.search-result-item")) {
|
||||
try {
|
||||
String pic = element.select("img").attr("data-original");
|
||||
String url = element.attr("href");
|
||||
String name = element.select(".v-item-title").text().replace("可可影视-kekys.com", "").trim();
|
||||
if (!pic.startsWith("http")) {
|
||||
pic = picUrl + pic;
|
||||
}
|
||||
String id = url.split("/")[2];
|
||||
list.add(new Vod(id, name, pic));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
Document doc = Jsoup.parse(OkHttp.string(playUrl.concat(id), getHeaders()));
|
||||
String regex = "window.whatTMDwhatTMDPPPP = '(.*?)'";
|
||||
String playSource = "playSource=\\{(.*?)\\}";
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(doc.html());
|
||||
String url = "";
|
||||
if (matcher.find()) {
|
||||
url = matcher.group(1);
|
||||
Pattern playSourcePattern = Pattern.compile(playSource);
|
||||
Matcher playSourceMatcher = playSourcePattern.matcher(doc.html());
|
||||
//playSourceMatcher.find();
|
||||
String srcUrl = Util.findByRegex("https?://[^\\s/$.?#].+\\.m3u8", doc.html(), 0);
|
||||
if (StringUtils.isNoneBlank(srcUrl)) {
|
||||
return Result.get().url(srcUrl).header(getHeaders()).string();
|
||||
|
||||
}
|
||||
String js = playSourceMatcher.group(1);
|
||||
|
||||
String regex1 = "KKYS\\['safePlay'\\]\\(\\)\\['url'\\]\\(\"([^\"]+)\"\\)";
|
||||
Pattern pattern1 = Pattern.compile(regex1);
|
||||
String jsSource = Util.unicodeToString(js);
|
||||
Matcher matcher1 = pattern1.matcher(jsSource);
|
||||
String iv = "VNF9aVQF!G*0ux@2hAigUeH3";
|
||||
if (matcher1.find()) {
|
||||
iv = matcher1.group(1);
|
||||
}
|
||||
url = decryptUrl(url, iv);
|
||||
}
|
||||
return Result.get().url(url).header(getHeaders()).string();
|
||||
}
|
||||
|
||||
public String decryptUrl(String encryptedData, String iv) {
|
||||
try {
|
||||
String encryptedKey = "VNF9aVQF!G*0ux@2hAigUeH3";
|
||||
|
||||
return AESEncryption.decrypt(encryptedData, encryptedKey, iv, AESEncryption.ECB_PKCS_7_PADDING);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return "123456";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,455 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Filter;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.ProxyVideo;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class NG extends Spider {
|
||||
private final String FIND_VIDEO_VOD_LIST = "/api.php/provide/vod_list";
|
||||
private final String FIND_CLASSIFICATION = "/api.php/provide/home_nav";
|
||||
private final String VIDEO_DETAIL = "/api.php/provide/vod_detail";
|
||||
private final String SEARCH_SEARCH = "/api.php/provide/search_result";
|
||||
private final List<Class> classList = new ArrayList<>();
|
||||
private final LinkedHashMap<String, List<Filter>> filters = new LinkedHashMap<>();
|
||||
private final String COMMON_URL = Util.base64Decode("aHR0cDovL3lzLmNoYW5nbWVuZ3l1bi5jb20=");
|
||||
|
||||
private Map<String, String> getParams() {
|
||||
Map<String, String> hashMap = new HashMap<>();
|
||||
hashMap.put("devices", "android");
|
||||
hashMap.put("deviceModel", "ASUS_I003DD");
|
||||
hashMap.put("deviceBrand", "ASUS");
|
||||
hashMap.put("deviceVersion", "9");
|
||||
hashMap.put("deviceScreen", "2340*1080");
|
||||
hashMap.put("appVersionCode", "9");
|
||||
hashMap.put("appVersionName", "1.0.9");
|
||||
hashMap.put("time", String.valueOf(System.currentTimeMillis() / 1000));
|
||||
hashMap.put("imei", "");
|
||||
hashMap.put("app", "ylys");
|
||||
return hashMap;
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders() {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
long currentTimeMillis = System.currentTimeMillis();
|
||||
headers.put("timeMillis", String.valueOf(currentTimeMillis));
|
||||
headers.put("sign", Util.MD5(Util.base64Decode("I3VCRnN6ZEVNMG9MMEpSbkA=") + currentTimeMillis));
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
if (classList.isEmpty()) {
|
||||
String string = OkHttp.string(COMMON_URL + FIND_CLASSIFICATION, getParams(), getHeaders());
|
||||
|
||||
JsonArray filterList = JsonParser.parseString(string).getAsJsonArray();
|
||||
for (int index = 0; index < filterList.size(); index++) {
|
||||
if (index == 0) continue;
|
||||
JsonObject obj = filterList.get(index).getAsJsonObject();
|
||||
int id = obj.get("id").getAsInt();
|
||||
String name = obj.get("name").getAsString();
|
||||
Class clazz = new Class(String.valueOf(id), name);
|
||||
classList.add(clazz);
|
||||
}
|
||||
}
|
||||
Map<String, String> params = new HashMap<>(getParams());
|
||||
/* for (String s : extend.keySet()) {
|
||||
params.put(s, URLEncoder.encode(extend.get(s), "UTF-8"));
|
||||
}*/
|
||||
params.put("page", "1");
|
||||
params.put("id", classList.get(0).getTypeId());
|
||||
String string = OkHttp.string(COMMON_URL + FIND_VIDEO_VOD_LIST, params, getHeaders());
|
||||
Type type = new TypeToken<Rst<It>>() {
|
||||
}.getType();
|
||||
Rst<It> resp = Json.parseSafe(string, type);
|
||||
List<Vod> vodList = new ArrayList<>();
|
||||
if (resp != null && resp.isSuccess()) {
|
||||
for (It it : resp.getList()) {
|
||||
vodList.add(it.toVod());
|
||||
}
|
||||
} else {
|
||||
SpiderDebug.log("ng cate error: " + string);
|
||||
}
|
||||
return Result.string(classList, vodList, filters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
try {
|
||||
Map<String, String> params = new HashMap<>(getParams());
|
||||
/* for (String s : extend.keySet()) {
|
||||
params.put(s, URLEncoder.encode(extend.get(s), "UTF-8"));
|
||||
}*/
|
||||
params.put("page", pg);
|
||||
params.put("id", tid);
|
||||
String string = OkHttp.string(COMMON_URL + FIND_VIDEO_VOD_LIST, params, getHeaders());
|
||||
Type type = new TypeToken<Rst<It>>() {
|
||||
}.getType();
|
||||
Rst<It> resp = Json.parseSafe(string, type);
|
||||
List<Vod> vodList = new ArrayList<>();
|
||||
if (resp != null && resp.isSuccess()) {
|
||||
for (It it : resp.getList()) {
|
||||
vodList.add(it.toVod());
|
||||
}
|
||||
} else {
|
||||
SpiderDebug.log("ng cate error: " + string);
|
||||
}
|
||||
|
||||
return Result.string(Integer.parseInt(pg), Integer.parseInt(pg) + 1, vodList.size(), Integer.MAX_VALUE, vodList);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) {
|
||||
Map<String, String> map = new HashMap<>(getParams());
|
||||
map.put("id", ids.get(0));
|
||||
String string = OkHttp.string(COMMON_URL + VIDEO_DETAIL, map, getHeaders());
|
||||
Type type = new TypeToken<Rst<Dt>>() {
|
||||
}.getType();
|
||||
Rst<Dt> dt = Json.parseSafe(string, type);
|
||||
if (!dt.isSuccess()) {
|
||||
SpiderDebug.log("ng detail err: " + dt.getMsg());
|
||||
return Result.error(dt.getMsg());
|
||||
}
|
||||
return Result.string(dt.data.toVod());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) {
|
||||
String string = OkHttp.string(id);
|
||||
Type type = new TypeToken<Rst<PlayRst>>() {
|
||||
}.getType();
|
||||
Rst<PlayRst> rst = Json.parseSafe(string, type);
|
||||
if (!rst.isSuccess()) {
|
||||
SpiderDebug.log("play err: " + rst.getMsg());
|
||||
return Result.error(rst.getMsg());
|
||||
}
|
||||
Map<String, String> filter = new HashMap<>();
|
||||
|
||||
for (String s : rst.getData().getHeader().keySet()) {
|
||||
if (s.equals("User-Agent")) {
|
||||
filter.put(s, rst.getData().getHeader().get(s));
|
||||
}
|
||||
}
|
||||
|
||||
return Result.get().url(ProxyVideo.buildCommonProxyUrl(rst.getData().getUrl(), filter)).string();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws UnsupportedEncodingException {
|
||||
Map<String, String> params = new HashMap<>(getParams());
|
||||
params.put("video_name", URLEncoder.encode(key, "UTF-8"));
|
||||
String string = OkHttp.string(COMMON_URL + SEARCH_SEARCH, params, getHeaders());
|
||||
Type type = new TypeToken<Rst<List<SearchRst>>>() {
|
||||
}.getType();
|
||||
Rst<List<SearchRst>> rst = Json.parseSafe(string, type);
|
||||
if (!rst.isSuccess()) {
|
||||
SpiderDebug.log("ng search error: " + rst.getMsg());
|
||||
return Result.error(rst.getMsg());
|
||||
}
|
||||
return Result.string(rst.getData().get(0).toVodList());
|
||||
|
||||
}
|
||||
|
||||
public static class Rst<T> {
|
||||
private int code;
|
||||
private String msg;
|
||||
private String limit;
|
||||
private int pagecount;
|
||||
private int total;
|
||||
private List<T> list;
|
||||
private T data;
|
||||
|
||||
public boolean isSuccess() {
|
||||
return code == 1;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public String getLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
public void setLimit(String limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public int getPagecount() {
|
||||
return pagecount;
|
||||
}
|
||||
|
||||
public void setPagecount(int pagecount) {
|
||||
this.pagecount = pagecount;
|
||||
}
|
||||
|
||||
public int getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(int total) {
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public List<T> getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
public void setList(List<T> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
public static class It {
|
||||
private int id;
|
||||
private String img;
|
||||
private String name;
|
||||
private String score;
|
||||
private String msg;
|
||||
|
||||
public Vod toVod() {
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(String.valueOf(id));
|
||||
vod.setVodName(name);
|
||||
vod.setVodRemarks(score);
|
||||
vod.setVodPic(img);
|
||||
return vod;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Dt {
|
||||
private String name;
|
||||
private String year;
|
||||
private String score;
|
||||
private int hits;
|
||||
private String type;
|
||||
private String img;
|
||||
private String info;
|
||||
@SerializedName("total_count")
|
||||
private int totalCount;
|
||||
@SerializedName("player_info")
|
||||
private List<DtIt> playerInfo;
|
||||
|
||||
public Vod toVod() {
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(name + score);
|
||||
vod.setVodName(name);
|
||||
vod.setVodPic(img);
|
||||
vod.setVodTag(type);
|
||||
vod.setVodRemarks(year);
|
||||
vod.setVodContent(info);
|
||||
|
||||
StringBuilder playFrom = new StringBuilder();
|
||||
StringBuilder playUrl = new StringBuilder();
|
||||
|
||||
for (DtIt info : playerInfo) {
|
||||
playFrom.append(info.getShow()).append("$$$");
|
||||
for (VtInfo vtInfo : info.getVideoInfo()) {
|
||||
|
||||
playUrl.append(vtInfo.getName()).append("$").append(vtInfo.getUrl().get(0));
|
||||
playUrl.append("#");
|
||||
|
||||
}
|
||||
playUrl.append("$$$");
|
||||
}
|
||||
|
||||
vod.setVodPlayFrom(playFrom.toString());
|
||||
vod.setVodPlayUrl(playUrl.toString());
|
||||
return vod;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DtIt {
|
||||
private int id;
|
||||
private String from;
|
||||
private String show;
|
||||
@SerializedName("url_count")
|
||||
private int urlCount;
|
||||
@SerializedName("video_info")
|
||||
private List<VtInfo> videoInfo;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
public void setFrom(String from) {
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
public String getShow() {
|
||||
return show;
|
||||
}
|
||||
|
||||
public void setShow(String show) {
|
||||
this.show = show;
|
||||
}
|
||||
|
||||
public int getUrlCount() {
|
||||
return urlCount;
|
||||
}
|
||||
|
||||
public void setUrlCount(int urlCount) {
|
||||
this.urlCount = urlCount;
|
||||
}
|
||||
|
||||
public List<VtInfo> getVideoInfo() {
|
||||
return videoInfo;
|
||||
}
|
||||
|
||||
public void setVideoInfo(List<VtInfo> videoInfo) {
|
||||
this.videoInfo = videoInfo;
|
||||
}
|
||||
}
|
||||
|
||||
public static class VtInfo {
|
||||
private int id;
|
||||
private String name;
|
||||
private String pic;
|
||||
private List<String> url;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPic() {
|
||||
return pic;
|
||||
}
|
||||
|
||||
public void setPic(String pic) {
|
||||
this.pic = pic;
|
||||
}
|
||||
|
||||
public List<String> getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(List<String> url) {
|
||||
this.url = url;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlayRst {
|
||||
private String url;
|
||||
private Map<String, String> header;
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public Map<String, String> getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
public void setHeader(Map<String, String> header) {
|
||||
this.header = header;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SearchRst {
|
||||
private int id;
|
||||
private String name;
|
||||
private List<SearchRstItem> data;
|
||||
|
||||
public List<Vod> toVodList() {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
for (SearchRstItem datum : data) {
|
||||
list.add(datum.toVOd());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SearchRstItem {
|
||||
private int id;
|
||||
private int type;
|
||||
@SerializedName("video_name")
|
||||
private String videoName;
|
||||
private String qingxidu;
|
||||
private String img;
|
||||
private String director;
|
||||
@SerializedName("main_actor")
|
||||
private String mainActor;
|
||||
private String category;
|
||||
|
||||
public Vod toVOd() {
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(String.valueOf(id));
|
||||
vod.setVodTag(qingxidu);
|
||||
vod.setVodPic(img);
|
||||
vod.setVodRemarks(category);
|
||||
vod.setVodName(videoName);
|
||||
vod.setVodActor(mainActor);
|
||||
return vod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,277 +0,0 @@
|
|||
package com.github.catvod.spider
|
||||
|
||||
|
||||
import com.github.catvod.bean.Class
|
||||
import com.github.catvod.bean.Filter
|
||||
import com.github.catvod.bean.Result
|
||||
import com.github.catvod.bean.Vod
|
||||
import com.github.catvod.crawler.Spider
|
||||
import com.github.catvod.crawler.SpiderDebug
|
||||
import com.github.catvod.net.OkHttp
|
||||
import com.github.catvod.utils.Json
|
||||
import com.github.catvod.utils.ProxyVideo
|
||||
import com.github.catvod.utils.Util
|
||||
import com.google.gson.JsonParser
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import java.net.URLEncoder
|
||||
|
||||
|
||||
class NGkt : Spider() {
|
||||
private var COMMON_URL: String = Util.base64Decode("aHR0cDovL3lzLmNoYW5nbWVuZ3l1bi5jb20=")
|
||||
private val FIND_VIDEO_VOD_LIST: String = "/api.php/provide/vod_list"
|
||||
private val FIND_CLASSIFICATION: String = "/api.php/provide/home_nav"
|
||||
private val VIDEO_DETAIL: String = "/api.php/provide/vod_detail"
|
||||
private val SEARCH_SEARCH: String = "/api.php/provide/search_result"
|
||||
|
||||
|
||||
private val classList = mutableListOf<Class>()
|
||||
private val filters = LinkedHashMap<String, MutableList<Filter>>()
|
||||
|
||||
|
||||
private fun getParams(): Map<String, String> {
|
||||
val hashMap: HashMap<String, String> = java.util.HashMap()
|
||||
hashMap["devices"] = "android"
|
||||
hashMap["deviceModel"] = "ASUS_I003DD"
|
||||
hashMap["deviceBrand"] = "ASUS"
|
||||
hashMap["deviceVersion"] = "9"
|
||||
hashMap["deviceScreen"] = "2340*1080"
|
||||
hashMap["appVersionCode"] = "9"
|
||||
hashMap["appVersionName"] = "1.0.9"
|
||||
hashMap["time"] = (System.currentTimeMillis() / 1000).toString()
|
||||
hashMap["imei"] = ""
|
||||
hashMap["app"] = "ylys"
|
||||
return hashMap
|
||||
}
|
||||
|
||||
fun getHeaders(): Map<String, String> {
|
||||
val headers = HashMap<String, String>()
|
||||
val currentTimeMillis = System.currentTimeMillis()
|
||||
headers.put("timeMillis", currentTimeMillis.toString())
|
||||
headers.put(
|
||||
"sign", Util.MD5(Util.base64Decode("I3VCRnN6ZEVNMG9MMEpSbkA=") + "$currentTimeMillis")
|
||||
)
|
||||
return headers
|
||||
}
|
||||
|
||||
override fun homeContent(filter: Boolean): String {
|
||||
if (classList.isEmpty()) {
|
||||
val string = OkHttp.string("$COMMON_URL$FIND_CLASSIFICATION", getParams(), getHeaders())
|
||||
val filterList = JsonParser.parseString(string).asJsonArray
|
||||
for ((index, jsonElement) in filterList.withIndex()) {
|
||||
if (index == 0) continue
|
||||
val obj = jsonElement.asJsonObject
|
||||
val id = obj.get("id").asInt
|
||||
val name = obj.get("name").asString
|
||||
val clazz = Class(id.toString(), name)
|
||||
classList.add(clazz)
|
||||
// val msgs = obj.get("msg").asJsonArray
|
||||
// if(msgs.isEmpty){
|
||||
// continue
|
||||
// }
|
||||
// for (msg in msgs) {
|
||||
// val msgObj = msg.asJsonObject
|
||||
// val dataArray = msgObj.get("data").asJsonArray
|
||||
// val list = mutableListOf<Filter.Value>()
|
||||
// for ((index, jsonElement1) in dataArray.withIndex()) {
|
||||
// if(index == 0) continue
|
||||
// list.add(Filter.Value(jsonElement1.asString, jsonElement1.asString))
|
||||
// }
|
||||
//
|
||||
// if(filters[id.toString()].isNullOrEmpty()){
|
||||
// filters[id.toString()] = mutableListOf(Filter(msgObj.get("name").asString, dataArray.get(0).asString, list))
|
||||
// }else{
|
||||
// filters[id.toString()]!!.add(Filter(msgObj.get("name").asString, dataArray.get(0).asString, list))
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
return Result.string(classList, filters)
|
||||
}
|
||||
|
||||
override fun categoryContent(
|
||||
tid: String, pg: String, filter: Boolean, extend: java.util.HashMap<String, String>
|
||||
): String {
|
||||
val params = getParams().toMutableMap()
|
||||
extend.forEach { (t, u) ->
|
||||
params[t] = URLEncoder.encode(u, "UTF-8")
|
||||
}
|
||||
params["page"] = pg
|
||||
params["id"] = tid
|
||||
val string = OkHttp.string("$COMMON_URL$FIND_VIDEO_VOD_LIST", params, getHeaders())
|
||||
val type = object : TypeToken<Rst<It>>() {}.type
|
||||
val resp = Json.parseSafe<Rst<It>>(string, type)
|
||||
var vodList = listOf<Vod>()
|
||||
if (resp.isSuccess()) {
|
||||
vodList = resp.list.toVodList()
|
||||
} else {
|
||||
SpiderDebug.log("ng cate error: $string")
|
||||
}
|
||||
return Result.string(classList, vodList, filters)
|
||||
}
|
||||
|
||||
override fun detailContent(ids: MutableList<String>): String {
|
||||
val map = getParams().toMutableMap()
|
||||
map["id"] = ids[0]
|
||||
val string = OkHttp.string("$COMMON_URL$VIDEO_DETAIL", map, getHeaders())
|
||||
val type = object : TypeToken<Rst<Dt>>() {}.type
|
||||
val dt = Json.parseSafe<Rst<Dt>>(string, type)
|
||||
if (!dt.isSuccess()) {
|
||||
SpiderDebug.log("ng detail err: ${dt.msg}")
|
||||
return Result.error(dt.msg)
|
||||
}
|
||||
return Result.string(dt.data.toVod().apply { setVodId(ids[0]) })
|
||||
}
|
||||
|
||||
override fun playerContent(flag: String, id: String, vipFlags: MutableList<String>): String {
|
||||
val string = OkHttp.string(id)
|
||||
val type = object : TypeToken<Rst<PlayRst>>() {}.type
|
||||
val rst = Json.parseSafe<Rst<PlayRst>>(string, type)
|
||||
if (!rst.isSuccess()) {
|
||||
SpiderDebug.log("play err: ${rst.msg}")
|
||||
return Result.error(rst.msg)
|
||||
}
|
||||
val filter = rst.data.header.filter { it.key.equals("User-Agent", true) }
|
||||
return Result.get().url(ProxyVideo.buildCommonProxyUrl(rst.data.url, filter)).string()
|
||||
}
|
||||
|
||||
override fun searchContent(key: String, quick: Boolean): String {
|
||||
val params = getParams().toMutableMap()
|
||||
params["video_name"] = URLEncoder.encode(key, "UTF-8")
|
||||
val string = OkHttp.string("$COMMON_URL$SEARCH_SEARCH", params, getHeaders())
|
||||
val type = object : TypeToken<Rst<List<SearchRst>>>() {}.type
|
||||
val rst = Json.parseSafe<Rst<List<SearchRst>>>(string, type)
|
||||
if (!rst.isSuccess()) {
|
||||
SpiderDebug.log("ng search error:${rst.msg}")
|
||||
return Result.error(rst.msg)
|
||||
}
|
||||
return Result.string(rst.data[0].toVodList())
|
||||
}
|
||||
|
||||
|
||||
data class Rst<T>(
|
||||
val code: Int,
|
||||
val msg: String,
|
||||
val limit: String,
|
||||
val pagecount: Int,
|
||||
val total: Int,
|
||||
val list: List<T>,
|
||||
val data: T
|
||||
) {
|
||||
fun isSuccess(): Boolean {
|
||||
return code == 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class It(
|
||||
val id: Int,
|
||||
val img: String,
|
||||
val name: String,
|
||||
val score: String,
|
||||
val msg: String,
|
||||
) {
|
||||
fun toVod(): Vod {
|
||||
val vod = Vod()
|
||||
vod.setVodId(id.toString())
|
||||
vod.setVodName(name)
|
||||
vod.setVodRemarks(score)
|
||||
vod.setVodPic(img)
|
||||
return vod
|
||||
}
|
||||
}
|
||||
|
||||
data class Dt(
|
||||
val name: String,
|
||||
val year: String,
|
||||
val score: String,
|
||||
val hits: Int,
|
||||
val type: String,
|
||||
val img: String,
|
||||
val info: String,
|
||||
@SerializedName("total_count") val totalCount: Int,
|
||||
@SerializedName("player_info") val playerInfo: List<DtIt>
|
||||
) {
|
||||
fun toVod(): Vod {
|
||||
val vod = Vod()
|
||||
vod.setVodId(name + score)
|
||||
vod.setVodName(name)
|
||||
vod.setVodPic(img)
|
||||
vod.setVodTag(type)
|
||||
vod.setVodRemarks(year)
|
||||
vod.vodContent = info
|
||||
val playFrom = StringBuilder()
|
||||
val playUrl = StringBuilder()
|
||||
for ((_, _, show, _, videoInfo) in playerInfo) {
|
||||
playFrom.append(show).append("$$$")
|
||||
for ((_, name1, _, url) in videoInfo) {
|
||||
playUrl.append(name1).append("$").append(url[0])
|
||||
playUrl.append("#")
|
||||
}
|
||||
playUrl.append("$$$")
|
||||
}
|
||||
vod.setVodPlayFrom(playFrom.toString())
|
||||
vod.vodPlayUrl = playUrl.toString()
|
||||
return vod
|
||||
}
|
||||
}
|
||||
|
||||
data class DtIt(
|
||||
val id: Int,
|
||||
val from: String,
|
||||
val show: String,
|
||||
@SerializedName("url_count") val urlCount: Int,
|
||||
@SerializedName("video_info") val videoInfo: List<VtInfo>
|
||||
)
|
||||
|
||||
data class VtInfo(
|
||||
val id: Int, val name: String, val pic: String, val url: List<String>
|
||||
)
|
||||
|
||||
private fun List<It>.toVodList(): MutableList<Vod> {
|
||||
val list = mutableListOf<Vod>()
|
||||
for (it in this) {
|
||||
list.add(it.toVod())
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
data class PlayRst(
|
||||
val url: String, val header: Map<String, String>
|
||||
)
|
||||
|
||||
data class SearchRst(
|
||||
val id: Int, val name: String, val data: List<SearchRstItem>
|
||||
) {
|
||||
fun toVodList(): MutableList<Vod> {
|
||||
val list = mutableListOf<Vod>()
|
||||
for (datum in data) {
|
||||
list.add(datum.toVOd())
|
||||
}
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
data class SearchRstItem(
|
||||
val id: Int,
|
||||
val type: Int,
|
||||
@SerializedName("video_name") val videoName: String,
|
||||
val qingxidu: String,
|
||||
val img: String,
|
||||
val director: String,
|
||||
@SerializedName("main_actor") val mainActor: String,
|
||||
val category: String
|
||||
) {
|
||||
fun toVOd(): Vod {
|
||||
val vod = Vod()
|
||||
vod.setVodId(id.toString())
|
||||
vod.setVodTag(qingxidu)
|
||||
vod.setVodPic(img)
|
||||
vod.setVodRemarks(category)
|
||||
vod.setVodName(videoName)
|
||||
vod.setVodActor(mainActor)
|
||||
return vod
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author zhixc
|
||||
*/
|
||||
public class NaBi extends Cloud {
|
||||
|
||||
private String siteUrl = "https://duopan.fun/";
|
||||
private final Pattern regexCategory = Pattern.compile("index.php/vod/type/id/(\\w+).html");
|
||||
private final Pattern regexPageTotal = Pattern.compile("\\$\\(\"\\.mac_total\"\\)\\.text\\('(\\d+)'\\);");
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
// JsonObject ext = Json.safeObject(extend);
|
||||
super.init(context, extend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeader()));
|
||||
Elements elements = doc.select(".nav-link");
|
||||
for (Element e : elements) {
|
||||
Matcher mather = regexCategory.matcher(e.attr("href"));
|
||||
if (mather.find()) {
|
||||
classes.add(new Class(mather.group(1), e.text().trim()));
|
||||
}
|
||||
}
|
||||
return Result.string(classes, parseVodListFromDoc(doc));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
String[] urlParams = new String[]{tid, "", "", "", "", "", "", "", pg, "", "", ""};
|
||||
if (extend != null && extend.size() > 0) {
|
||||
for (String key : extend.keySet()) {
|
||||
urlParams[Integer.parseInt(key)] = extend.get(key);
|
||||
}
|
||||
}
|
||||
Document doc = Jsoup.parse(OkHttp.string(String.format("%s/index.php/vod/show/id/%s/page/%s.html", siteUrl, tid, pg), getHeader()));
|
||||
int page = Integer.parseInt(pg), limit = 72, total = 0;
|
||||
Matcher matcher = regexPageTotal.matcher(doc.html());
|
||||
if (matcher.find()) total = Integer.parseInt(matcher.group(1));
|
||||
int count = total <= limit ? 1 : ((int) Math.ceil(total / (double) limit));
|
||||
return Result.get().vod(parseVodListFromDoc(doc)).page(page, count, limit, total).string();
|
||||
}
|
||||
|
||||
private List<Vod> parseVodListFromDoc(Document doc) {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Elements elements = doc.select(".module-item");
|
||||
for (Element e : elements) {
|
||||
String vodId = e.selectFirst(".video-name a").attr("href");
|
||||
String vodPic = e.selectFirst(".module-item-pic > img").attr("data-src");
|
||||
String vodName = e.selectFirst(".video-name").text();
|
||||
String vodRemarks = e.selectFirst(".module-item-text").text();
|
||||
list.add(new Vod(vodId, vodName, vodPic, vodRemarks));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
String vodId = ids.get(0);
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl + vodId, getHeader()));
|
||||
|
||||
Vod item = new Vod();
|
||||
item.setVodId(vodId);
|
||||
item.setVodName(doc.selectFirst(".video-info-header > .page-title").text());
|
||||
item.setVodPic(doc.selectFirst(".module-item-pic img").attr("data-src"));
|
||||
item.setVodArea(doc.select(".video-info-header a.tag-link").last().text());
|
||||
item.setTypeName(String.join(",", doc.select(".video-info-header div.tag-link a").eachText()));
|
||||
|
||||
List<String> shareLinks = doc.select(".module-row-text").eachAttr("data-clipboard-text");
|
||||
for (int i = 0; i < shareLinks.size(); i++) {
|
||||
shareLinks.set(i, shareLinks.get(i).trim());
|
||||
//String detailContent = super.detailContent(List.of(shareLinks.get(i)));
|
||||
}
|
||||
item.setVodPlayUrl(super.detailContentVodPlayUrl(shareLinks));
|
||||
item.setVodPlayFrom(super.detailContentVodPlayFrom(shareLinks));
|
||||
|
||||
Elements elements = doc.select(".video-info-item");
|
||||
for (Element e : elements) {
|
||||
String title = e.previousElementSibling().text();
|
||||
if (title.contains("导演")) {
|
||||
item.setVodDirector(String.join(",", e.select("a").eachText()));
|
||||
} else if (title.contains("主演")) {
|
||||
item.setVodActor(String.join(",", e.select("a").eachText()));
|
||||
} else if (title.contains("年代")) {
|
||||
item.setVodYear(e.selectFirst("a").text().trim());
|
||||
} else if (title.contains("备注")) {
|
||||
item.setVodRemarks(e.text().trim());
|
||||
} else if (title.contains("剧情")) {
|
||||
item.setVodContent(e.selectFirst(".sqjj_a").text().replace("[收起部分]", "").trim());
|
||||
}
|
||||
}
|
||||
|
||||
return Result.string(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
return searchContent(key, "1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick, String pg) throws Exception {
|
||||
return searchContent(key, pg);
|
||||
}
|
||||
|
||||
|
||||
private String searchContent(String key, String pg) {
|
||||
String searchURL = siteUrl + String.format("/index.php/vod/search/page/%s/wd/%s.html", pg,URLEncoder.encode(key));
|
||||
String html = OkHttp.string(searchURL, getHeader());
|
||||
Elements items = Jsoup.parse(html).select(".module-search-item");
|
||||
List<Vod> list = new ArrayList<>();
|
||||
for (Element item : items) {
|
||||
String vodId = item.select(".video-serial").attr("href");
|
||||
String name = item.select(".video-serial").attr("title");
|
||||
String pic = item.select(".module-item-pic > img").attr("data-src");
|
||||
String remark = item.select(".video-tag-icon").text();
|
||||
list.add(new Vod(vodId, name, pic, remark));
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import com.github.catvod.api.Pan123Api;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author lushunming
|
||||
*/
|
||||
public class Pan123 extends Spider {
|
||||
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
|
||||
if (StringUtils.isNoneBlank(extend)) {
|
||||
// Pan123Api.INSTANCE.setAuth(extend);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
|
||||
@NotNull Map<@NotNull String, @NotNull String> shareData = Pan123Api.INSTANCE.getShareData(ids.get(0));
|
||||
return Result.string(Pan123Api.INSTANCE.getVod(shareData.get("key"), shareData.get("sharePwd")));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
return Pan123Api.INSTANCE.playerContent(id, flag);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 獲取詳情內容視頻播放來源(多 shared_link)
|
||||
*
|
||||
* @param ids share_link 集合
|
||||
* @param
|
||||
* @return 詳情內容視頻播放來源
|
||||
*/
|
||||
public String detailContentVodPlayFrom(List<String> ids, int index) {
|
||||
List<String> playFrom = new ArrayList<>();
|
||||
/* if (ids.size() < 2){
|
||||
return TextUtils.join("$$$", Pan123Api.INSTANCE.getPlayFormatList());
|
||||
}*/
|
||||
|
||||
for (int i = 1; i <= ids.size(); i++) {
|
||||
|
||||
for (String s : Pan123Api.INSTANCE.getPlayFormatList()) {
|
||||
playFrom.add(String.format(Locale.getDefault(), "pan123" + s + "#%02d_%02d", i, index));
|
||||
|
||||
}
|
||||
// playFrom.add("天意" + i + index);
|
||||
}
|
||||
return TextUtils.join("$$$", playFrom);
|
||||
}
|
||||
|
||||
/**
|
||||
* 獲取詳情內容視頻播放地址(多 share_link)
|
||||
*
|
||||
* @param ids share_link 集合
|
||||
* @return 詳情內容視頻播放地址
|
||||
*/
|
||||
public String detailContentVodPlayUrl(List<String> ids){
|
||||
List<String> playUrl = new ArrayList<>();
|
||||
for (String id : ids) {
|
||||
@NotNull Map<@NotNull String, @NotNull String> shareData = Pan123Api.INSTANCE.getShareData(id);
|
||||
try {
|
||||
playUrl.add(Pan123Api.INSTANCE.getVod(shareData.get("key"), shareData.get("sharePwd")).getVodPlayUrl());
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log("获取播放地址出错:" + e.getMessage());
|
||||
playUrl.add("");
|
||||
}
|
||||
}
|
||||
return TextUtils.join("$$$", playUrl);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@ import org.json.JSONObject;
|
|||
import org.jsoup.Jsoup;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
|
@ -19,7 +18,7 @@ import java.util.Map;
|
|||
/**
|
||||
* @author zhixc
|
||||
*/
|
||||
public class PanSearch extends Cloud {
|
||||
public class PanSearch extends Ali {
|
||||
|
||||
private final String URL = "https://www.pansearch.me/";
|
||||
|
||||
|
|
@ -41,26 +40,21 @@ public class PanSearch extends Cloud {
|
|||
String html = OkHttp.string(URL, getHeader());
|
||||
String data = Jsoup.parse(html).select("script[id=__NEXT_DATA__]").get(0).data();
|
||||
String buildId = new JSONObject(data).getString("buildId");
|
||||
List<String> types = List.of("quark", "aliyundrive");
|
||||
String url = URL + "_next/data/" + buildId + "/search.json?keyword=" + URLEncoder.encode(key) + "&pan=aliyundrive";
|
||||
String result = OkHttp.string(url, getSearchHeader());
|
||||
JSONArray array = new JSONObject(result).getJSONObject("pageProps").getJSONObject("data").getJSONArray("data");
|
||||
List<Vod> list = new ArrayList<>();
|
||||
|
||||
for (String type : types) {
|
||||
String url = URL + "_next/data/" + buildId + "/search.json?keyword=" + URLEncoder.encode(key, Charset.defaultCharset().name()) + "&pan=" + type;
|
||||
String result = OkHttp.string(url, getSearchHeader());
|
||||
JSONArray array = new JSONObject(result).getJSONObject("pageProps").getJSONObject("data").getJSONArray("data");
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
JSONObject item = array.getJSONObject(i);
|
||||
String content = item.optString("content");
|
||||
String[] split = content.split("\\n");
|
||||
if (split.length == 0) continue;
|
||||
String vodId = Jsoup.parse(content).select("a").attr("href");
|
||||
String name = split[0].replaceAll("</?[^>]+>", "");
|
||||
String remark = item.optString("time");
|
||||
String pic = item.optString("image");
|
||||
list.add(new Vod(vodId, name, pic, remark));
|
||||
}
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
JSONObject item = array.getJSONObject(i);
|
||||
String content = item.optString("content");
|
||||
String[] split = content.split("\\n");
|
||||
if (split.length == 0) continue;
|
||||
String vodId = Jsoup.parse(content).select("a").attr("href");
|
||||
String name = split[0].replaceAll("</?[^>]+>", "");
|
||||
String remark = item.optString("time");
|
||||
String pic = item.optString("image");
|
||||
list.add(new Vod(vodId, name, pic, remark));
|
||||
}
|
||||
|
||||
return Result.string(list);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,156 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Util;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class PanTa extends Cloud {
|
||||
private static final String HOST = "https://www.91panta.cn/";
|
||||
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
// JsonObject ext = Json.safeObject(extend);
|
||||
super.init(context, extend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
|
||||
|
||||
List<Class> classes = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(HOST));
|
||||
Elements elements = doc.select("#tabNavigation > a.tab");
|
||||
for (Element element : elements) {
|
||||
|
||||
classes.add(new Class(element.attr("href"), element.text().trim()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
return Result.string(classes, parseVodListFromDoc(doc));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
String url = HOST + tid + "&page=" + pg;
|
||||
Document doc = Jsoup.parse(OkHttp.string(url));
|
||||
int page = Integer.parseInt(pg), limit = 30, total = Integer.MAX_VALUE;
|
||||
return Result.get().vod(parseVodListFromDoc(doc)).page(page, 99999, limit, total).string();
|
||||
}
|
||||
|
||||
private List<Vod> parseVodListFromDoc(Document doc) {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Elements elements = doc.select(".topicList > .topicItem");
|
||||
for (Element e : elements) {
|
||||
String pic = Objects.isNull(e.selectFirst(".tm-m-photos-thumb li")) ? "" : e.selectFirst(".tm-m-photos-thumb li").attr("data-src");
|
||||
pic = StringUtils.isAllBlank(pic) ? e.selectFirst("a.avatarLink img").attr("src") : pic;
|
||||
Element content = e.selectFirst(".content > h2 > a");
|
||||
String vodId = content.attr("href");
|
||||
String vodPic = HOST + pic;
|
||||
String vodName = content.text();
|
||||
|
||||
list.add(new Vod(vodId, vodName, vodPic));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
// 获取视频信息
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
String vodId = ids.get(0);
|
||||
Document doc = Jsoup.parse(OkHttp.string(HOST + vodId));
|
||||
|
||||
Vod item = new Vod();
|
||||
|
||||
Element titleElement = doc.selectFirst(".title");
|
||||
if (titleElement != null) {
|
||||
item.setVodName(titleElement.text().trim());
|
||||
}
|
||||
item.setVodId("/" + vodId);
|
||||
|
||||
|
||||
// 解析链接
|
||||
String contentHtml = doc.selectFirst(".topicContent").html();
|
||||
String link = null;
|
||||
|
||||
// 第一种匹配模式:<a href>
|
||||
Pattern aPattern = Pattern.compile("<a\\s+(?:[^>]*?\\s+)?href=[\"'](https://caiyun\\.139\\.com/[^\"']*)[\"'][^>]*>", Pattern.CASE_INSENSITIVE);
|
||||
Matcher aMatcher = aPattern.matcher(contentHtml);
|
||||
if (aMatcher.find()) {
|
||||
link = aMatcher.group(1);
|
||||
}
|
||||
|
||||
// 第二种匹配模式:<span>中的文本
|
||||
if (StringUtils.isAllBlank(link)) {
|
||||
Pattern spanPattern = Pattern.compile("<span\\s+style=\"color:\\s*#0070C0;\\s*\">(https://caiyun\\.139\\.com/[^<]*)</span>", Pattern.CASE_INSENSITIVE);
|
||||
Matcher spanMatcher = spanPattern.matcher(contentHtml);
|
||||
if (spanMatcher.find()) {
|
||||
link = spanMatcher.group(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 第三种匹配模式:纯文本
|
||||
if (StringUtils.isAllBlank(link)) {
|
||||
Pattern textPattern = Pattern.compile("https://caiyun\\.139\\.com/[^<]*");
|
||||
Matcher textMatcher = textPattern.matcher(contentHtml);
|
||||
if (textMatcher.find()) {
|
||||
link = textMatcher.group();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
item.setVodPlayUrl(super.detailContentVodPlayUrl(List.of(link)));
|
||||
item.setVodPlayFrom(super.detailContentVodPlayFrom(List.of(link)));
|
||||
|
||||
String text = doc.select("div.topicContent > p").text().trim();
|
||||
|
||||
String director = Util.findByRegex("导演:(.*)主演", text, 1);
|
||||
String actor = Util.findByRegex("主演:(.*)类型", text, 1);
|
||||
String cat = Util.findByRegex("类型:(.*)制片", text, 1);
|
||||
String area = Util.findByRegex("地区:(.*)语言", text, 1);
|
||||
String year = Util.findByRegex("上映日期:(.*)片长", text, 1);
|
||||
String remark = Util.findByRegex("简介:(.*)", text, 1);
|
||||
item.setVodDirector(director);
|
||||
item.setVodActor(actor);
|
||||
item.setTypeName(cat);
|
||||
item.setVodArea(area);
|
||||
item.setVodYear(year);
|
||||
item.setVodContent(remark);
|
||||
return Result.string(item);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick, String pg) throws Exception {
|
||||
return searchContent(key, pg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
return searchContent(key, "1");
|
||||
}
|
||||
|
||||
|
||||
private String searchContent(String key, String pg) {
|
||||
String searchURL = HOST + String.format("search?keyword=%s&page=%s", URLEncoder.encode(key), pg);
|
||||
String html = OkHttp.string(searchURL);
|
||||
return Result.string(parseVodListFromDoc(Jsoup.parse(html)));
|
||||
}
|
||||
}
|
||||
|
|
@ -3,14 +3,8 @@ package com.github.catvod.spider;
|
|||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.ProxyVideo;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Proxy extends Spider {
|
||||
|
|
@ -23,42 +17,17 @@ public class Proxy extends Spider {
|
|||
return new Object[]{200, "text/plain; charset=utf-8", new ByteArrayInputStream("ok".getBytes("UTF-8"))};
|
||||
case "ali":
|
||||
return Ali.proxy(params);
|
||||
case "quark":
|
||||
return Quark.proxy(params);
|
||||
case "uc":
|
||||
return UC.proxy(params);
|
||||
case "bili":
|
||||
return Bili.proxy(params);
|
||||
case "webdav":
|
||||
return WebDAV.vod(params);
|
||||
case "local":
|
||||
return Local.proxy(params);
|
||||
case "proxy":
|
||||
return commonProxy(params);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final List<String> keys = Arrays.asList("url", "header", "do", "Content-Type", "User-Agent", "Host");
|
||||
|
||||
private static Object[] commonProxy(Map<String, String> params) throws Exception {
|
||||
String url = Util.base64Decode(params.get("url"));
|
||||
Map<String, String> header = new Gson().fromJson(Util.base64Decode(params.get("header")), Map.class);
|
||||
if (header == null) header = new HashMap<>();
|
||||
List<String> keys = Arrays.asList("range", "connection", "accept-encoding");
|
||||
for (String key : params.keySet()) {
|
||||
if (keys.contains(key.toLowerCase())) {
|
||||
header.put(key, params.get(key));
|
||||
}
|
||||
}
|
||||
/*for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||
if (!keys.contains(entry.getKey())) header.put(entry.getKey(), entry.getValue());
|
||||
}*/
|
||||
return ProxyVideo.proxyMultiThread(url, header);
|
||||
}
|
||||
|
||||
|
||||
static void adjustPort() {
|
||||
if (Proxy.port > 0) return;
|
||||
int port = 9978;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import com.github.catvod.bean.Result;
|
|||
import com.github.catvod.bean.Sub;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Image;
|
||||
import com.github.catvod.utils.Util;
|
||||
|
|
@ -20,54 +19,31 @@ import java.util.List;
|
|||
|
||||
public class Push extends Spider {
|
||||
|
||||
private Cloud cloud;
|
||||
private final Ali ali;
|
||||
|
||||
public Push() {
|
||||
cloud = new Cloud();
|
||||
ali = new Ali();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) {
|
||||
try {
|
||||
cloud.init(context, extend);
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log("Cloud init error: " + e.getMessage());
|
||||
}
|
||||
ali.init(context, extend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
String url = ids.get(0);
|
||||
|
||||
// 使用Cloud类处理各种云盘链接
|
||||
String cloudResult = cloud.detailContent(ids);
|
||||
if (cloudResult != null) {
|
||||
return cloudResult;
|
||||
}
|
||||
|
||||
// 如果不是云盘链接,返回普通链接处理结果
|
||||
return Result.string(vod(url));
|
||||
if (Ali.pattern.matcher(ids.get(0)).find()) return ali.detailContent(ids);
|
||||
return Result.string(vod(ids.get(0)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) {
|
||||
try {
|
||||
// 使用Cloud类处理云盘链接的播放
|
||||
String cloudResult = cloud.playerContent(flag, id, vipFlags);
|
||||
if (cloudResult != null) {
|
||||
return cloudResult;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log("Cloud playerContent error: " + e.getMessage());
|
||||
}
|
||||
|
||||
// 原有逻辑处理其他类型链接
|
||||
if (id.startsWith("http") && id.contains("***")) id = id.replace("***", "#");
|
||||
if (flag.equals("直連")) return Result.get().url(id).subs(getSubs(id)).string();
|
||||
if (flag.equals("解析")) return Result.get().parse().jx().url(id).string();
|
||||
if (flag.equals("嗅探")) return Result.get().parse().url(id).string();
|
||||
if (flag.equals("迅雷")) return Result.get().url(id).string();
|
||||
return Result.get().url(id).string();
|
||||
return ali.playerContent(flag, id, vipFlags);
|
||||
}
|
||||
|
||||
private Vod vod(String url) {
|
||||
|
|
|
|||
|
|
@ -1,71 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.Util;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author zhixc
|
||||
*/
|
||||
public class QiLeSo extends Cloud {
|
||||
|
||||
private final String URL = "https://www.qileso.com/";
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> shareUrl) throws Exception {
|
||||
SpiderDebug.log("qileso detail args:" + Json.toJson(shareUrl));
|
||||
|
||||
String html = OkHttp.string(shareUrl.get(0), getHeader());
|
||||
Document doc = Jsoup.parse(html);
|
||||
Element elements = doc.selectFirst("#body > div > div.thread-body > div.thread-content.message.break-all > p > a");
|
||||
SpiderDebug.log("qileso detail shareurl:" + elements.attr("href"));
|
||||
|
||||
|
||||
String result = super.detailContent(List.of(elements.attr("href")));
|
||||
SpiderDebug.log("qileso detail:" + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
String url = URL + "?s=" + URLEncoder.encode(key, Charset.defaultCharset().name());
|
||||
|
||||
String html = OkHttp.string(url, getHeader());
|
||||
Document doc = Jsoup.parse(html);
|
||||
List<Vod> list = new ArrayList<>();
|
||||
|
||||
Elements elements = doc.select(" ul.list-group > li.list-group-item > div.subject > h2 > a");
|
||||
for (Element element : elements) {
|
||||
String id = element.attr("href");
|
||||
String name = element.text();
|
||||
list.add(new Vod(id, name, ""));
|
||||
}
|
||||
|
||||
SpiderDebug.log("qileso searchContent:" + Result.string(list));
|
||||
|
||||
return Result.string(list);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.github.catvod.api.QuarkApi;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.quark.ShareData;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.crawler.SpiderDebug;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ColaMint & Adam & FongMi
|
||||
*/
|
||||
public class Quark extends Spider {
|
||||
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
|
||||
QuarkApi.get().setCookie(extend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
|
||||
ShareData shareData = QuarkApi.get().getShareData(ids.get(0));
|
||||
return Result.string(QuarkApi.get().getVod(shareData));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
return QuarkApi.get().playerContent(id.split("\\+\\+"), flag);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 獲取詳情內容視頻播放來源(多 shared_link)
|
||||
*
|
||||
* @param ids share_link 集合
|
||||
* @param i
|
||||
* @return 詳情內容視頻播放來源
|
||||
*/
|
||||
public String detailContentVodPlayFrom(List<String> ids, int index) {
|
||||
List<String> playFrom = new ArrayList<>();
|
||||
/* if (ids.size() < 2){
|
||||
return TextUtils.join("$$$", QuarkApi.get().getPlayFormatList());
|
||||
}*/
|
||||
|
||||
for (int i = 1; i <= ids.size(); i++) {
|
||||
playFrom.add(String.format("quark原画#%02d_%02d" ,i , index));
|
||||
for (String s : QuarkApi.get().getPlayFormatList()) {
|
||||
playFrom.add(String.format(Locale.getDefault(), "quark" + s + "#%02d_%02d", i, index));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return TextUtils.join("$$$", playFrom);
|
||||
}
|
||||
|
||||
/**
|
||||
* 獲取詳情內容視頻播放地址(多 share_link)
|
||||
*
|
||||
* @param ids share_link 集合
|
||||
* @return 詳情內容視頻播放地址
|
||||
*/
|
||||
public String detailContentVodPlayUrl(List<String> ids) {
|
||||
List<String> playUrl = new ArrayList<>();
|
||||
for (String id : ids) {
|
||||
ShareData shareData = QuarkApi.get().getShareData(id);
|
||||
try {
|
||||
playUrl.add(QuarkApi.get().getVod(shareData)==null?"":QuarkApi.get().getVod(shareData).getVodPlayUrl());
|
||||
} catch (Exception e) {
|
||||
SpiderDebug.log("获取播放地址出错:" + e.getMessage());
|
||||
playUrl.add("");
|
||||
}
|
||||
}
|
||||
return TextUtils.join("$$$", playUrl);
|
||||
}
|
||||
|
||||
public static Object[] proxy(Map<String, String> params) throws Exception {
|
||||
String type = params.get("type");
|
||||
if ("video".equals(type)) return QuarkApi.get().proxyVideo(params);
|
||||
//if ("sub".equals(type)) return AliYun.get().proxySub(params);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,192 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Qupans extends Cloud {
|
||||
|
||||
private static final String BASE_URL = "https://www.qupanshe.com";
|
||||
private static final String DEFAULT_COVER_URL = "https://fs-im-kefu.7moor-fs1.com/ly/4d2c3f00-7d4c-11e5-af15-41bf63ae4ea0/1743950734122/baidu.jpg";
|
||||
|
||||
private String get(String url) {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||
headers.put("Referer", BASE_URL);
|
||||
return OkHttp.string(url, headers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
try {
|
||||
JSONObject result = new JSONObject();
|
||||
JSONArray classes = new JSONArray();
|
||||
String[][] types = {{"电影","3"}, {"电视剧","2"}, {"综艺","4"}, {"动漫","5"}, {"纪录片","6"}};
|
||||
for (String[] type : types) {
|
||||
JSONObject cls = new JSONObject();
|
||||
cls.put("type_id", type[1]);
|
||||
cls.put("type_name", type[0]);
|
||||
classes.put(cls);
|
||||
}
|
||||
result.put("class", classes);
|
||||
return result.toString();
|
||||
} catch (Exception e) {
|
||||
return "{\"class\":[]}";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
try {
|
||||
String html = get(BASE_URL + "/forum.php?mod=forumdisplay&fid=" + tid + "&page=" + pg);
|
||||
Document doc = Jsoup.parse(html);
|
||||
JSONArray list = new JSONArray();
|
||||
|
||||
for (Element item : doc.select("div.tit_box > a.s")) {
|
||||
String title = item.text();
|
||||
if (title.contains("公告") || title.contains("求")) continue;
|
||||
JSONObject vod = new JSONObject();
|
||||
vod.put("vod_id", item.attr("href"));
|
||||
vod.put("vod_name", title);
|
||||
vod.put("vod_pic", DEFAULT_COVER_URL);
|
||||
vod.put("vod_remarks", "");
|
||||
list.put(vod);
|
||||
}
|
||||
|
||||
return new JSONObject()
|
||||
.put("list", list)
|
||||
.put("page", pg)
|
||||
.put("pagecount", "0")
|
||||
.put("total", "0")
|
||||
.toString();
|
||||
} catch (Exception e) {
|
||||
return "{\"list\":[]}";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) {
|
||||
try {
|
||||
String vodId = ids.get(0);
|
||||
String html = get(vodId.startsWith("http") ? vodId : BASE_URL + "/" + vodId);
|
||||
Document doc = Jsoup.parse(html);
|
||||
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(vodId);
|
||||
vod.setVodName(doc.select("h1").first().text());
|
||||
vod.setVodPic(DEFAULT_COVER_URL);
|
||||
|
||||
List<String> links = getLinks(doc);
|
||||
if (!links.isEmpty()) {
|
||||
String pwd = getPwd(doc);
|
||||
for (int i = 0; i < links.size(); i++) {
|
||||
String link = links.get(i);
|
||||
if (!link.contains("pwd=") && !TextUtils.isEmpty(pwd)) {
|
||||
links.set(i, link + "?pwd=" + pwd);
|
||||
}
|
||||
}
|
||||
vod.setVodPlayFrom(super.detailContentVodPlayFrom(links));
|
||||
vod.setVodPlayUrl(super.detailContentVodPlayUrl(links));
|
||||
}
|
||||
|
||||
return Result.string(vod);
|
||||
} catch (Exception e) {
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(ids.get(0));
|
||||
vod.setVodName("加载失败");
|
||||
vod.setVodPic(DEFAULT_COVER_URL);
|
||||
return Result.string(vod);
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getLinks(Document doc) {
|
||||
List<String> links = new ArrayList<>();
|
||||
// 从a标签中提取链接
|
||||
Elements linksElements = doc.select("a");
|
||||
for (Element linkElement : linksElements) {
|
||||
String href = linkElement.attr("href");
|
||||
if (href.contains(".baidu")) {
|
||||
links.add(href);
|
||||
break; // 只提取第一个百度网盘链接
|
||||
}
|
||||
}
|
||||
return links;
|
||||
}
|
||||
|
||||
private String getPwd(Document doc) {
|
||||
try {
|
||||
// 使用正则表达式模式提取密码
|
||||
String patternStr = "提取码:\\s*([A-Za-z0-9]{4})";
|
||||
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(patternStr);
|
||||
Element contentElement = doc.select("td.t_f").first();
|
||||
if (contentElement != null) {
|
||||
String text = contentElement.text();
|
||||
java.util.regex.Matcher matcher = pattern.matcher(text);
|
||||
if (matcher.find()) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 忽略异常
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) {
|
||||
return searchContent(key, quick, "1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick, String pg) {
|
||||
try {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("searchsubmit", "yes");
|
||||
params.put("srchtxt", key);
|
||||
String[] fids = {"2", "3", "4", "5", "6"};
|
||||
for (int i = 0; i < fids.length; i++) params.put("srchfid[" + i + "]", fids[i]);
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||
headers.put("content-type", "application/x-www-form-urlencoded");
|
||||
|
||||
String html = OkHttp.post(BASE_URL + "/search.php?mod=forum", params, headers).getBody();
|
||||
Document doc = Jsoup.parse(html);
|
||||
|
||||
JSONArray list = new JSONArray();
|
||||
for (Element item : doc.select("#threadlist ul li h3 > a")) {
|
||||
JSONObject vod = new JSONObject();
|
||||
vod.put("vod_id", item.attr("href"));
|
||||
vod.put("vod_name", item.text());
|
||||
vod.put("vod_pic", DEFAULT_COVER_URL);
|
||||
vod.put("vod_remarks", "");
|
||||
list.put(vod);
|
||||
}
|
||||
|
||||
return new JSONObject()
|
||||
.put("list", list)
|
||||
.put("page", pg)
|
||||
.put("pagecount", "1")
|
||||
.put("total", list.length())
|
||||
.toString();
|
||||
} catch (Exception e) {
|
||||
return "{\"list\":[]}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.crawler.Spider;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Util;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class QxiTv extends Spider {
|
||||
|
||||
private static final String siteUrl = "https://www.7xi.tv";
|
||||
private static final String cateUrl = siteUrl + "/vodtype/";
|
||||
private static final String searchUrl = siteUrl + "/vodsearch/page/1/wd/";
|
||||
private static final String playUrl = siteUrl + "/FosiPlayer/API.php";
|
||||
|
||||
private HashMap<String, String> getHeaders() {
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
headers.put("User-Agent", Util.CHROME);
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
List<Class> classes = new ArrayList<>();
|
||||
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeaders()));
|
||||
for (Element element : doc.select("ul.swiper-wrapper > li.swiper-slide > a")) {
|
||||
if(element.text().contains("留言")){
|
||||
break;
|
||||
}
|
||||
classes.add(new Class(element.attr("href"),element.text()));
|
||||
}
|
||||
|
||||
for (Element element : doc.select("a.public-list-exp")) {
|
||||
try {
|
||||
String pic = element.select("img").attr("data-src");
|
||||
String url = element.attr("href");
|
||||
String name = element.attr("title");
|
||||
if (!pic.startsWith("http")) {
|
||||
pic = siteUrl + pic;
|
||||
}
|
||||
list.add(new Vod(url, name, pic));
|
||||
} catch (Exception ignored) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return Result.string(classes, list);
|
||||
}
|
||||
|
||||
public String MD5(String string) {
|
||||
// 创建 MD5 实例
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
// 计算 MD5 哈希值
|
||||
byte[] hashBytes = md.digest(string.getBytes());
|
||||
|
||||
// 将字节数组转换为十六进制字符串表示
|
||||
StringBuilder hexString = new StringBuilder();
|
||||
for (byte hashByte : hashBytes) {
|
||||
String hex = Integer.toHexString(0xff & hashByte);
|
||||
if (hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
|
||||
// 输出加密后的 MD5 字符串
|
||||
System.out.println("MD5 加密: " + hexString.toString());
|
||||
return hexString.toString();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
|
||||
String url = siteUrl + tid;
|
||||
if(!Objects.equals(pg, "1")){
|
||||
url += "-" + pg;
|
||||
}
|
||||
String res = OkHttp.string(url, getHeaders());
|
||||
Document document = Jsoup.parse(res);
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Elements vodList = document.select("a.public-list-exp");
|
||||
for (Element element : vodList) {
|
||||
String vodId = element.attr("href");
|
||||
String title = element.attr("title");
|
||||
String img = element.select("img").attr("data-src");
|
||||
String remark = element.select(".public-list-prb").val();
|
||||
list.add(new Vod(vodId, title, img, remark));
|
||||
}
|
||||
|
||||
Integer total = Integer.MAX_VALUE;
|
||||
return Result.string(Integer.parseInt(pg), Integer.parseInt(pg) + 1, list.size(), total, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl + ids.get(0), getHeaders()));
|
||||
String name = doc.select("div.this-desc-title").text();
|
||||
String pic = doc.select("div.this-pic-bj").attr("style").replace("background-image: url('", "").replace("')", "");
|
||||
String year = doc.select("div.this-desc-info > span").get(1).text();
|
||||
|
||||
// 播放源
|
||||
Elements tabs = doc.select("a.swiper-slide");
|
||||
Elements list = doc.select("div.anthology-list-box.none");
|
||||
String PlayFrom = "";
|
||||
String PlayUrl = "";
|
||||
for (int i = 0; i < tabs.size(); i++) {
|
||||
String tabName = tabs.get(i).text();
|
||||
if (!"".equals(PlayFrom)) {
|
||||
PlayFrom = PlayFrom + "$$$" + tabName;
|
||||
} else {
|
||||
PlayFrom = PlayFrom + tabName;
|
||||
}
|
||||
Elements li = list.get(i).select("a");
|
||||
String liUrl = "";
|
||||
for (int i1 = 0; i1 < li.size(); i1++) {
|
||||
if (!"".equals(liUrl)){
|
||||
liUrl = liUrl + "#" + li.get(i1).text() + "$" + li.get(i1).attr("href");
|
||||
}else {
|
||||
liUrl = liUrl + li.get(i1).text() + "$" + li.get(i1).attr("href");
|
||||
}
|
||||
}
|
||||
if (!"".equals(PlayUrl)) {
|
||||
PlayUrl = PlayUrl + "$$$" + liUrl;
|
||||
}else {
|
||||
PlayUrl = PlayUrl + liUrl;
|
||||
}
|
||||
}
|
||||
|
||||
Vod vod = new Vod();
|
||||
vod.setVodId(ids.get(0));
|
||||
vod.setVodPic(pic);
|
||||
vod.setVodYear(year);
|
||||
vod.setVodName(name);
|
||||
vod.setVodPlayFrom(PlayFrom);
|
||||
vod.setVodPlayUrl(PlayUrl);
|
||||
return Result.string(vod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(searchUrl.concat(URLEncoder.encode(key)).concat(".html"), getHeaders()));
|
||||
for (Element element : doc.select("a.public-list-exp")) {
|
||||
try {
|
||||
String pic = element.select("img").attr("data-src");
|
||||
String url = element.attr("href");
|
||||
String name = element.attr("title");
|
||||
if (!pic.startsWith("http")) {
|
||||
pic = siteUrl + pic;
|
||||
}
|
||||
list.add(new Vod(url, name, pic));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl.concat(id),getHeaders()));
|
||||
String regex = "\"url\":\"(.*?)m3u8\",";
|
||||
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(doc.html());
|
||||
String url = "";
|
||||
if (matcher.find()) {
|
||||
url = matcher.group(1);
|
||||
url = url.replace("\\/","/") + "m3u8";
|
||||
}
|
||||
|
||||
return Result.get().url(url).header(getHeaders()).string();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
package com.github.catvod.spider
|
||||
|
||||
import android.content.Context
|
||||
import com.github.catvod.bean.Class
|
||||
import com.github.catvod.bean.Result
|
||||
import com.github.catvod.bean.Vod
|
||||
import com.github.catvod.net.OkHttp
|
||||
import com.github.catvod.utils.Json
|
||||
import com.github.catvod.utils.Util
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Document
|
||||
import java.net.URLEncoder
|
||||
import java.nio.charset.Charset
|
||||
|
||||
/**
|
||||
* 电影云集
|
||||
*
|
||||
* @author lushunming
|
||||
* @createdate 2024-12-03
|
||||
*/
|
||||
class ReBoYingShi : Cloud() {
|
||||
private val siteUrl = "https://reboys.cn"
|
||||
|
||||
|
||||
|
||||
|
||||
private val headerWithCookie: MutableMap<String?, String?>
|
||||
get() {
|
||||
val header: MutableMap<String?, String?> = HashMap<String?, String?>()
|
||||
header.put("User-Agent", Util.CHROME)
|
||||
|
||||
return header
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun init(context: Context?, extend: String?) {
|
||||
super.init(context, extend)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun searchContent(key: String?, quick: Boolean): String? {
|
||||
return searchContent(key, "1")
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun searchContent(key: String?, quick: Boolean, pg: String?): String? {
|
||||
return searchContent(key, pg)
|
||||
}
|
||||
|
||||
private fun searchContent(key: String?, pg: String?): String? {
|
||||
val searchPageURL = siteUrl + "/s/${URLEncoder.encode(key, Charset.defaultCharset().name())}.html"
|
||||
val html = OkHttp.string(searchPageURL, this.headerWithCookie)
|
||||
val apiToken = Util.findByRegex("const apiToken = \"(.*?)\";", html, 1)
|
||||
|
||||
val searchURL = siteUrl + "/search?keyword=${URLEncoder.encode(key, Charset.defaultCharset().name())}"
|
||||
val header = headerWithCookie.toMutableMap()
|
||||
header.put("API-TOKEN", apiToken)
|
||||
val json = OkHttp.string(searchURL, header)
|
||||
val jsonObj = Json.safeObject(json)
|
||||
var vodList = emptyList<Vod>()
|
||||
if (jsonObj.get("code").asInt == 0) {
|
||||
val results = jsonObj.get("data").asJsonObject.get("data").asJsonObject.get("results").asJsonArray
|
||||
vodList = results.map {
|
||||
val title = it.asJsonObject.get("title").asString
|
||||
val vodId = it.asJsonObject.get("links").asJsonArray[0].asJsonObject.get("url").asString
|
||||
Vod(vodId, title, "", "")
|
||||
}
|
||||
}
|
||||
return Result.string(vodList)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,248 +0,0 @@
|
|||
package com.github.catvod.spider
|
||||
|
||||
|
||||
import android.content.Context
|
||||
import com.github.catvod.bean.Class
|
||||
import com.github.catvod.bean.Filter
|
||||
import com.github.catvod.bean.Result
|
||||
import com.github.catvod.bean.Vod
|
||||
import com.github.catvod.net.OkHttp
|
||||
import com.github.catvod.utils.Util
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import kotlinx.coroutines.*
|
||||
import okhttp3.HttpUrl
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Document
|
||||
import java.net.URLEncoder
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
* @author lushunming
|
||||
*/
|
||||
class SeedHub : Cloud() {
|
||||
private val siteUrl = "https://www.seedhub.cc"
|
||||
private val regexCategory: Pattern = Pattern.compile("/vodtype/(\\w+).html")
|
||||
private val regexPageTotal: Pattern = Pattern.compile("\\$\\(\"\\.mac_total\"\\)\\.text\\('(\\d+)'\\);")
|
||||
|
||||
private var extend: JsonObject? = null
|
||||
|
||||
|
||||
private val header: MutableMap<String?, String?>
|
||||
get() {
|
||||
val header: MutableMap<String?, String?> = HashMap<String?, String?>()
|
||||
header.put("User-Agent", Util.MOBILE)
|
||||
return header
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun init(context: Context, extend: String) {
|
||||
this.extend = JsonParser.parseString(extend).getAsJsonObject()
|
||||
super.init(context, "")
|
||||
}
|
||||
|
||||
override fun homeContent(filter: Boolean): String? {
|
||||
val classes: MutableList<Class?> = ArrayList<Class?>()
|
||||
val filters = LinkedHashMap<String?, MutableList<Filter?>?>()
|
||||
|
||||
|
||||
val html = OkHttp.string(siteUrl, this.header)
|
||||
val doc = Jsoup.parse(html)
|
||||
|
||||
parseClassFromDoc(doc, classes)
|
||||
if (filter) {
|
||||
parseFilterFromDoc(doc, filters)
|
||||
}
|
||||
|
||||
return Result.string(classes, parseVodListFromDoc(doc), filters)
|
||||
}
|
||||
|
||||
private fun parseFilterFromDoc(
|
||||
doc: Document, filters: LinkedHashMap<String?, MutableList<Filter?>?>
|
||||
) {
|
||||
|
||||
val groups = doc.select("div.sidebar-group")
|
||||
for (group in groups) {
|
||||
val clazz = group.select("p.sidebar-heading a")
|
||||
if (clazz.attr("href").startsWith("/")) {
|
||||
val name = clazz.text()
|
||||
val url = clazz.attr("href")
|
||||
val filter = group.select("ul.sidebar-sub-headers>li.sidebar-sub-header>a")
|
||||
val filterList: MutableList<Filter?> = ArrayList<Filter?>()
|
||||
val values: MutableList<Filter.Value> = ArrayList<Filter.Value>()
|
||||
for (f in filter) {
|
||||
val filterName = f.text()
|
||||
val filterUrl = f.attr("href")
|
||||
values.add(Filter.Value(filterName, filterUrl))
|
||||
}
|
||||
filterList.add(Filter("0", "分类", values))
|
||||
filters[url] = filterList
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*获取分类
|
||||
*/
|
||||
private fun parseClassFromDoc(
|
||||
doc: Document, classes: MutableList<Class?>
|
||||
) {
|
||||
val navs = doc.select("div.nav-item")
|
||||
for (nav in navs) {
|
||||
val link = nav.select("a")
|
||||
if (link.attr("href").startsWith("/")) {
|
||||
val name = nav.select("a").text()
|
||||
val url = nav.select("a").attr("href")
|
||||
classes.add(Class(url, name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun categoryContent(
|
||||
tid: String?, pg: String, filter: Boolean, extend: HashMap<String, String?>?
|
||||
): String? {
|
||||
var urlParams = tid
|
||||
if (extend != null && extend.size > 0) {
|
||||
extend.keys.forEach {
|
||||
urlParams = extend[it]
|
||||
}
|
||||
}
|
||||
val doc = Jsoup.parse(
|
||||
OkHttp.string(
|
||||
String.format("%s%s?page=%s", siteUrl, urlParams, pg), this.header
|
||||
)
|
||||
)
|
||||
val page = pg.toInt()
|
||||
val limit = 20
|
||||
val total = Int.MAX_VALUE
|
||||
|
||||
|
||||
return Result.get().vod(parseVodListFromDoc(doc)).page(page, 0, limit, total).string()
|
||||
}
|
||||
|
||||
private fun parseVodListFromDoc(doc: Document): MutableList<Vod?> {
|
||||
val list: MutableList<Vod?> = ArrayList<Vod?>()
|
||||
val elements = doc.select("div.cover")
|
||||
for (e in elements) {
|
||||
val vodId = e.selectFirst(" a")!!.attr("href")
|
||||
var vodPic = e.selectFirst("img")!!.attr("src")
|
||||
if (!vodPic.startsWith("http")) {
|
||||
vodPic = siteUrl + vodPic
|
||||
}
|
||||
val vodName = e.selectFirst("h2")!!.text()
|
||||
val vodRemarks = e.select("ul >li")!!.text()
|
||||
list.add(Vod(vodId, vodName, vodPic, vodRemarks))
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun detailContent(ids: MutableList<String?>): String? {
|
||||
|
||||
val vodId = ids.get(0)
|
||||
val doc = Jsoup.parse(
|
||||
OkHttp.string(
|
||||
siteUrl + vodId, this.header
|
||||
)
|
||||
)
|
||||
val infos = doc.select("div.cover-container >ul > li").text().replace(" ", "")
|
||||
val item = Vod()
|
||||
item.setVodId(vodId)
|
||||
item.setVodName(doc.selectFirst("h1")!!.text())
|
||||
item.setVodPic(doc.selectFirst("div.cover-container img")!!.attr("src"))
|
||||
item.setVodArea(Util.getStrByRegex(Pattern.compile("制片国家/地区:(.*?)语言:"), infos))
|
||||
item.setTypeName(Util.getStrByRegex(Pattern.compile("类型:(.*?)制片"), infos))
|
||||
item.setVodDirector(Util.getStrByRegex(Pattern.compile("导演:(.*?)制片"), infos))
|
||||
item.setVodActor(Util.getStrByRegex(Pattern.compile("主演:(.*?)类型"), infos))
|
||||
item.setVodYear(Util.getStrByRegex(Pattern.compile("首播:(.*?)集数"), infos))
|
||||
item.setVodRemarks(Util.getStrByRegex(Pattern.compile("豆瓣评分:(.*?)常用标签"), infos))
|
||||
item.vodContent = doc.select("div.content > p").text()
|
||||
|
||||
val shareLinks: CopyOnWriteArrayList<String?> = CopyOnWriteArrayList<String?>()
|
||||
val jobs = ArrayList<Job>()
|
||||
|
||||
runBlocking {
|
||||
val docEle = doc.select("ul.pan-links > li > a")
|
||||
docEle.filter { it.attr("data-link").contains("uc") }.take(2).forEach { element ->
|
||||
|
||||
jobs += CoroutineScope(Dispatchers.IO).launch {
|
||||
var link = siteUrl + element.attr("href")
|
||||
val movieTitle = HttpUrl.parse(link)?.queryParameter("movie_title")
|
||||
link = HttpUrl.parse(link)?.newBuilder()?.removeAllQueryParameters("movie_title")
|
||||
?.addEncodedQueryParameter(
|
||||
"movie_title", URLEncoder.encode(movieTitle)
|
||||
)?.build().toString()
|
||||
val string = OkHttp.string(link, header)
|
||||
val docEle = Jsoup.parse(string)
|
||||
docEle.select("a.direct-pan").attr("href").let {
|
||||
if (it.isNotEmpty()) {
|
||||
shareLinks.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
docEle.filter { it.attr("data-link").contains("baidu") }.take(2).forEach { element ->
|
||||
|
||||
jobs += CoroutineScope(Dispatchers.IO).launch {
|
||||
var link = siteUrl + element.attr("href")
|
||||
val movieTitle = HttpUrl.parse(link)?.queryParameter("movie_title")
|
||||
link = HttpUrl.parse(link)?.newBuilder()?.removeAllQueryParameters("movie_title")
|
||||
?.addEncodedQueryParameter(
|
||||
"movie_title", URLEncoder.encode(movieTitle)
|
||||
)?.build().toString()
|
||||
val string = OkHttp.string(link, header)
|
||||
val docEle = Jsoup.parse(string)
|
||||
docEle.select("a.direct-pan").attr("href").let {
|
||||
if (it.isNotEmpty()) {
|
||||
shareLinks.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
docEle.filter { it.attr("data-link").contains("quark") }.take(2).forEach { element ->
|
||||
|
||||
jobs += CoroutineScope(Dispatchers.IO).launch {
|
||||
var link = siteUrl + element.attr("href")
|
||||
val movieTitle = HttpUrl.parse(link)?.queryParameter("movie_title")
|
||||
link = HttpUrl.parse(link)?.newBuilder()?.removeAllQueryParameters("movie_title")
|
||||
?.addEncodedQueryParameter(
|
||||
"movie_title", URLEncoder.encode(movieTitle)
|
||||
)?.build().toString()
|
||||
val string = OkHttp.string(link, header)
|
||||
val docEle = Jsoup.parse(string)
|
||||
docEle.select("a.direct-pan").attr("href").let {
|
||||
if (it.isNotEmpty()) {
|
||||
shareLinks.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
jobs.joinAll()
|
||||
item.vodPlayUrl = super.detailContentVodPlayUrl(java.util.ArrayList(shareLinks))
|
||||
item.setVodPlayFrom(super.detailContentVodPlayFrom(java.util.ArrayList(shareLinks)))
|
||||
|
||||
|
||||
}
|
||||
return Result.string(item)
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun searchContent(key: String?, quick: Boolean): String? {
|
||||
return searchContent(key, "1")
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun searchContent(key: String?, quick: Boolean, pg: String?): String? {
|
||||
return searchContent(key, pg)
|
||||
}
|
||||
|
||||
private fun searchContent(key: String?, pg: String?): String? {
|
||||
val searchURL = siteUrl + String.format("/s/%s/?page=%s", URLEncoder.encode(key), pg)
|
||||
val html = OkHttp.string(searchURL, this.header)
|
||||
val doc = Jsoup.parse(html)
|
||||
|
||||
return Result.string(parseVodListFromDoc(doc))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author zhixc
|
||||
*/
|
||||
public class ShanDian extends Cloud {
|
||||
|
||||
private String siteUrl = "http://1.95.79.193/";
|
||||
private final Pattern regexCategory = Pattern.compile("index.php/vod/type/id/(\\w+).html");
|
||||
private final Pattern regexPageTotal = Pattern.compile("\\$\\(\"\\.mac_total\"\\)\\.text\\('(\\d+)'\\);");
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
// JsonObject ext = Json.safeObject(extend);
|
||||
super.init(context, extend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeader()));
|
||||
Elements elements = doc.select(".nav-link");
|
||||
for (Element e : elements) {
|
||||
Matcher mather = regexCategory.matcher(e.attr("href"));
|
||||
if (mather.find()) {
|
||||
classes.add(new Class(mather.group(1), e.text().trim()));
|
||||
}
|
||||
}
|
||||
return Result.string(classes, parseVodListFromDoc(doc));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
String[] urlParams = new String[]{tid, "", "", "", "", "", "", "", pg, "", "", ""};
|
||||
if (extend != null && extend.size() > 0) {
|
||||
for (String key : extend.keySet()) {
|
||||
urlParams[Integer.parseInt(key)] = extend.get(key);
|
||||
}
|
||||
}
|
||||
Document doc = Jsoup.parse(OkHttp.string(String.format("%s/index.php/vod/show/id/%s/page/%s.html", siteUrl, tid, pg), getHeader()));
|
||||
int page = Integer.parseInt(pg), limit = 72, total = 0;
|
||||
Matcher matcher = regexPageTotal.matcher(doc.html());
|
||||
if (matcher.find()) total = Integer.parseInt(matcher.group(1));
|
||||
int count = total <= limit ? 1 : ((int) Math.ceil(total / (double) limit));
|
||||
return Result.get().vod(parseVodListFromDoc(doc)).page(page, count, limit, total).string();
|
||||
}
|
||||
|
||||
private List<Vod> parseVodListFromDoc(Document doc) {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Elements elements = doc.select(".module-item");
|
||||
for (Element e : elements) {
|
||||
String vodId = e.selectFirst(".video-name a").attr("href");
|
||||
String vodPic = e.selectFirst(".module-item-pic > img").attr("data-src");
|
||||
String vodName = e.selectFirst(".video-name").text();
|
||||
String vodRemarks = e.selectFirst(".module-item-text").text();
|
||||
list.add(new Vod(vodId, vodName, vodPic, vodRemarks));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
String vodId = ids.get(0);
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl + vodId, getHeader()));
|
||||
|
||||
Vod item = new Vod();
|
||||
item.setVodId(vodId);
|
||||
item.setVodName(doc.selectFirst(".video-info-header > .page-title").text());
|
||||
item.setVodPic(doc.selectFirst(".module-item-pic img").attr("data-src"));
|
||||
item.setVodArea(doc.select(".video-info-header a.tag-link").last().text());
|
||||
item.setTypeName(String.join(",", doc.select(".video-info-header div.tag-link a").eachText()));
|
||||
|
||||
List<String> shareLinks = doc.select(".module-row-text").eachAttr("data-clipboard-text");
|
||||
for (int i = 0; i < shareLinks.size(); i++) {
|
||||
shareLinks.set(i, shareLinks.get(i).trim());
|
||||
//String detailContent = super.detailContent(List.of(shareLinks.get(i)));
|
||||
}
|
||||
item.setVodPlayUrl(super.detailContentVodPlayUrl(shareLinks));
|
||||
item.setVodPlayFrom(super.detailContentVodPlayFrom(shareLinks));
|
||||
|
||||
Elements elements = doc.select(".video-info-item");
|
||||
for (Element e : elements) {
|
||||
String title = e.previousElementSibling().text();
|
||||
if (title.contains("导演")) {
|
||||
item.setVodDirector(String.join(",", e.select("a").eachText()));
|
||||
} else if (title.contains("主演")) {
|
||||
item.setVodActor(String.join(",", e.select("a").eachText()));
|
||||
} else if (title.contains("年代")) {
|
||||
item.setVodYear(e.selectFirst("a").text().trim());
|
||||
} else if (title.contains("备注")) {
|
||||
item.setVodRemarks(e.text().trim());
|
||||
} else if (title.contains("剧情")) {
|
||||
item.setVodContent(e.selectFirst(".sqjj_a").text().replace("[收起部分]", "").trim());
|
||||
}
|
||||
}
|
||||
|
||||
return Result.string(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
return searchContent(key, "1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick, String pg) throws Exception {
|
||||
return searchContent(key, pg);
|
||||
}
|
||||
|
||||
|
||||
private String searchContent(String key, String pg) {
|
||||
String searchURL = siteUrl + String.format("/index.php/vod/search/page/%s/wd/%s.html", pg,URLEncoder.encode(key));
|
||||
String html = OkHttp.string(searchURL, getHeader());
|
||||
Elements items = Jsoup.parse(html).select(".module-search-item");
|
||||
List<Vod> list = new ArrayList<>();
|
||||
for (Element item : items) {
|
||||
String vodId = item.select(".video-serial").attr("href");
|
||||
String name = item.select(".video-serial").attr("title");
|
||||
String pic = item.select(".module-item-pic > img").attr("data-src");
|
||||
String remark = item.select(".video-tag-icon").text();
|
||||
list.add(new Vod(vodId, name, pic, remark));
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import com.github.catvod.bean.Class;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author zhixc
|
||||
*/
|
||||
public class TeXiaFan extends Cloud {
|
||||
|
||||
private String siteUrl = "http://www.xn--ghqy10g1w0a.xyz/";
|
||||
private final Pattern regexCategory = Pattern.compile("index.php/vod/type/id/(\\w+).html");
|
||||
private final Pattern regexPageTotal = Pattern.compile("\\$\\(\"\\.mac_total\"\\)\\.text\\('(\\d+)'\\);");
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context, String extend) throws Exception {
|
||||
// JsonObject ext = Json.safeObject(extend);
|
||||
super.init(context, extend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String homeContent(boolean filter) {
|
||||
List<Class> classes = new ArrayList<>();
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl, getHeader()));
|
||||
Elements elements = doc.select(".nav-link");
|
||||
for (Element e : elements) {
|
||||
Matcher mather = regexCategory.matcher(e.attr("href"));
|
||||
if (mather.find()) {
|
||||
classes.add(new Class(mather.group(1), e.text().trim()));
|
||||
}
|
||||
}
|
||||
return Result.string(classes, parseVodListFromDoc(doc));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) {
|
||||
String[] urlParams = new String[]{tid, "", "", "", "", "", "", "", pg, "", "", ""};
|
||||
if (extend != null && extend.size() > 0) {
|
||||
for (String key : extend.keySet()) {
|
||||
urlParams[Integer.parseInt(key)] = extend.get(key);
|
||||
}
|
||||
}
|
||||
Document doc = Jsoup.parse(OkHttp.string(String.format("%s/index.php/vod/show/id/%s/page/%s.html", siteUrl, tid, pg), getHeader()));
|
||||
int page = Integer.parseInt(pg), limit = 72, total = 0;
|
||||
Matcher matcher = regexPageTotal.matcher(doc.html());
|
||||
if (matcher.find()) total = Integer.parseInt(matcher.group(1));
|
||||
int count = total <= limit ? 1 : ((int) Math.ceil(total / (double) limit));
|
||||
return Result.get().vod(parseVodListFromDoc(doc)).page(page, count, limit, total).string();
|
||||
}
|
||||
|
||||
private List<Vod> parseVodListFromDoc(Document doc) {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
Elements elements = doc.select(".module-item");
|
||||
for (Element e : elements) {
|
||||
String vodId = e.selectFirst(".video-name a").attr("href");
|
||||
String vodPic = e.selectFirst(".module-item-pic > img").attr("data-src");
|
||||
String vodName = e.selectFirst(".video-name").text();
|
||||
String vodRemarks = e.selectFirst(".module-item-text").text();
|
||||
list.add(new Vod(vodId, vodName, vodPic, vodRemarks));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detailContent(List<String> ids) throws Exception {
|
||||
String vodId = ids.get(0);
|
||||
Document doc = Jsoup.parse(OkHttp.string(siteUrl + vodId, getHeader()));
|
||||
|
||||
Vod item = new Vod();
|
||||
item.setVodId(vodId);
|
||||
item.setVodName(doc.selectFirst(".video-info-header > .page-title").text());
|
||||
item.setVodPic(doc.selectFirst(".module-item-pic img").attr("data-src"));
|
||||
item.setVodArea(doc.select(".video-info-header a.tag-link").last().text());
|
||||
item.setTypeName(String.join(",", doc.select(".video-info-header div.tag-link a").eachText()));
|
||||
|
||||
List<String> shareLinks = doc.select(".module-row-text").eachAttr("data-clipboard-text");
|
||||
for (int i = 0; i < shareLinks.size(); i++) {
|
||||
shareLinks.set(i, shareLinks.get(i).trim());
|
||||
//String detailContent = super.detailContent(List.of(shareLinks.get(i)));
|
||||
}
|
||||
item.setVodPlayUrl(super.detailContentVodPlayUrl(shareLinks));
|
||||
item.setVodPlayFrom(super.detailContentVodPlayFrom(shareLinks));
|
||||
|
||||
Elements elements = doc.select(".video-info-item");
|
||||
for (Element e : elements) {
|
||||
String title = e.previousElementSibling().text();
|
||||
if (title.contains("导演")) {
|
||||
item.setVodDirector(String.join(",", e.select("a").eachText()));
|
||||
} else if (title.contains("主演")) {
|
||||
item.setVodActor(String.join(",", e.select("a").eachText()));
|
||||
} else if (title.contains("年代")) {
|
||||
item.setVodYear(e.selectFirst("a").text().trim());
|
||||
} else if (title.contains("备注")) {
|
||||
item.setVodRemarks(e.text().trim());
|
||||
} else if (title.contains("剧情")) {
|
||||
item.setVodContent(e.selectFirst(".sqjj_a").text().replace("[收起部分]", "").trim());
|
||||
}
|
||||
}
|
||||
|
||||
return Result.string(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
return searchContent(key, "1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick, String pg) throws Exception {
|
||||
return searchContent(key, pg);
|
||||
}
|
||||
|
||||
|
||||
private String searchContent(String key, String pg) {
|
||||
String searchURL = siteUrl + String.format("/index.php/vod/search/page/%s/wd/%s.html", pg,URLEncoder.encode(key));
|
||||
String html = OkHttp.string(searchURL, getHeader());
|
||||
Elements items = Jsoup.parse(html).select(".module-search-item");
|
||||
List<Vod> list = new ArrayList<>();
|
||||
for (Element item : items) {
|
||||
String vodId = item.select(".video-serial").attr("href");
|
||||
String name = item.select(".video-serial").attr("title");
|
||||
String pic = item.select(".module-item-pic > img").attr("data-src");
|
||||
String remark = item.select(".video-tag-icon").text();
|
||||
list.add(new Vod(vodId, name, pic, remark));
|
||||
}
|
||||
return Result.string(list);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
package com.github.catvod.spider
|
||||
|
||||
import com.github.catvod.bean.Result
|
||||
import com.github.catvod.bean.Vod
|
||||
import com.github.catvod.net.OkHttp
|
||||
import com.github.catvod.utils.Json
|
||||
import com.github.catvod.utils.Util
|
||||
import java.net.URLEncoder
|
||||
import java.nio.charset.Charset
|
||||
|
||||
/**
|
||||
* @author zhixc
|
||||
*/
|
||||
class Tg123Search : Cloud() {
|
||||
private val URL = "https://tgsou.252035.xyz/"
|
||||
|
||||
private val header: Map<String, String>
|
||||
get() {
|
||||
val header: MutableMap<String, String> = HashMap()
|
||||
header["User-Agent"] = Util.CHROME
|
||||
return header
|
||||
}
|
||||
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun searchContent(key: String, quick: Boolean): String {
|
||||
val url =
|
||||
URL + "?channelUsername=wp123zy,xx123pan,yp123pan,zyfb123&pic=true&keyword=" + URLEncoder.encode(
|
||||
key, Charset.defaultCharset().name()
|
||||
)
|
||||
val list: MutableList<Vod> = ArrayList()
|
||||
val html = OkHttp.string(url, header)
|
||||
val json = Json.safeObject(html);
|
||||
json["results"].asJsonArray.forEach { element ->
|
||||
val array = element.asString.split("$$$")
|
||||
if (array.size >= 2 && array[1].isNotEmpty()) {
|
||||
array[1].split("##").forEach {
|
||||
|
||||
|
||||
val id = it.split("@")[0]
|
||||
val pic = it.split("@")[1].split("$$")[0]
|
||||
val name = it.split("@")[1].split("$$")[1]
|
||||
|
||||
list.add(Vod(id, name, pic, ""))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return Result.string(list)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
package com.github.catvod.spider
|
||||
|
||||
import com.github.catvod.bean.Result
|
||||
import com.github.catvod.bean.Vod
|
||||
import com.github.catvod.net.OkHttp
|
||||
import com.github.catvod.utils.Json
|
||||
import com.github.catvod.utils.Util
|
||||
import java.net.URLEncoder
|
||||
import java.nio.charset.Charset
|
||||
|
||||
/**
|
||||
* @author zhixc
|
||||
*/
|
||||
class Tg189Search : Cloud() {
|
||||
private val URL = "https://tgsou.252035.xyz/"
|
||||
|
||||
private val header: Map<String, String>
|
||||
get() {
|
||||
val header: MutableMap<String, String> = HashMap()
|
||||
header["User-Agent"] = Util.CHROME
|
||||
return header
|
||||
}
|
||||
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun searchContent(key: String, quick: Boolean): String {
|
||||
val url =
|
||||
URL + "?channelUsername=cloud189_group,yunpan139,cloud189_group,cloudtianyi,kuakeclound,tianyirigeng,txtyzy,tyypzhpd,tyysypzypd,yunpan189&pic=true&keyword=" + URLEncoder.encode(
|
||||
key, Charset.defaultCharset().name()
|
||||
)
|
||||
val list: MutableList<Vod> = ArrayList()
|
||||
val html = OkHttp.string(url, header)
|
||||
val json = Json.safeObject(html);
|
||||
json["results"].asJsonArray.forEach { element ->
|
||||
val array = element.asString.split("$$$")
|
||||
if (array.size >= 2 && array[1].isNotEmpty()) {
|
||||
array[1].split("##").forEach {
|
||||
|
||||
|
||||
val id = it.split("@")[0]
|
||||
val pic = it.split("@")[1].split("$$")[0]
|
||||
val name = it.split("@")[1].split("$$")[1]
|
||||
|
||||
list.add(Vod(id, name, pic, ""))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return Result.string(list)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
package com.github.catvod.spider
|
||||
|
||||
import com.github.catvod.bean.Result
|
||||
import com.github.catvod.bean.Vod
|
||||
import com.github.catvod.net.OkHttp
|
||||
import com.github.catvod.utils.Json
|
||||
import com.github.catvod.utils.Util
|
||||
import java.net.URLEncoder
|
||||
import java.nio.charset.Charset
|
||||
|
||||
/**
|
||||
* @author zhixc
|
||||
*/
|
||||
class TgQuarkSearch : Cloud() {
|
||||
private val URL = "https://tgsou.252035.xyz/"
|
||||
|
||||
private val header: Map<String, String>
|
||||
get() {
|
||||
val header: MutableMap<String, String> = HashMap()
|
||||
header["User-Agent"] = Util.CHROME
|
||||
return header
|
||||
}
|
||||
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun searchContent(key: String, quick: Boolean): String {
|
||||
val url =
|
||||
URL + "?channelUsername=alyp_1,clouddriveresources,dianyingshare,hdhhd21,jdjdn1111,leoziyuan,NewQuark,PanjClub,Quark_Movies,xiangxiunb,yunpanchat,yunpanqk,XiangxiuNB,alyp_4K_Movies,alyp_Animation,alyp_TV,alyp_JLP&pic=true&keyword=" + URLEncoder.encode(
|
||||
key, Charset.defaultCharset().name()
|
||||
)
|
||||
val list: MutableList<Vod> = ArrayList()
|
||||
val html = OkHttp.string(url, header)
|
||||
val json = Json.safeObject(html);
|
||||
json["results"].asJsonArray.forEach { element ->
|
||||
val array = element.asString.split("$$$")
|
||||
if (array.size >= 2 && array[1].isNotEmpty()) {
|
||||
array[1].split("##").forEach {
|
||||
|
||||
|
||||
val id = it.split("@")[0]
|
||||
val pic = it.split("@")[1].split("$$")[0]
|
||||
val name = it.split("@")[1].split("$$")[1]
|
||||
|
||||
list.add(Vod(id, name, pic, ""))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return Result.string(list)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
package com.github.catvod.spider
|
||||
|
||||
import com.github.catvod.bean.Result
|
||||
import com.github.catvod.bean.Vod
|
||||
import com.github.catvod.net.OkHttp
|
||||
import com.github.catvod.utils.Util
|
||||
import org.jsoup.Jsoup
|
||||
import java.net.URLEncoder
|
||||
import java.nio.charset.Charset
|
||||
|
||||
/**
|
||||
* @author zhixc
|
||||
*/
|
||||
class TgSearch : Cloud() {
|
||||
private val URL = "https://tg.252035.xyz/"
|
||||
|
||||
private val header: Map<String, String>
|
||||
get() {
|
||||
val header: MutableMap<String, String> = HashMap()
|
||||
header["User-Agent"] = Util.CHROME
|
||||
return header
|
||||
}
|
||||
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun searchContent(key: String, quick: Boolean): String {
|
||||
val url =
|
||||
URL + "?channelUsername=tianyirigeng,tyypzhpd,XiangxiuNB,yunpanpan,kuakeyun,zaihuayun,Quark_Movies,alyp_4K_Movies,vip115hot,yunpanshare,dianyingshare&pic=true&keyword=" + URLEncoder.encode(
|
||||
key, Charset.defaultCharset().name()
|
||||
)
|
||||
val list: MutableList<Vod> = ArrayList()
|
||||
val html = OkHttp.string(url, header)
|
||||
val arr = html.split(":I".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
if (arr.size > 0) {
|
||||
for (s in arr) {
|
||||
val doc = Jsoup.parse(s)
|
||||
val id = doc.select(" a").eachAttr("href")
|
||||
.first { it.contains("189") || it.contains("139") || it.contains("quark") }
|
||||
val name = doc.select("strong").text()
|
||||
list.add(Vod(id, name, "", ""))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return Result.string(list)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,258 +0,0 @@
|
|||
package com.github.catvod.spider;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import com.github.catvod.bean.Result;
|
||||
import com.github.catvod.bean.Vod;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.net.OkResult;
|
||||
import com.github.catvod.utils.Json;
|
||||
import com.github.catvod.utils.Util;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class TgSearch123 extends Cloud {
|
||||
private static final String KEY_API_URLS = "api_urls";
|
||||
private static final String KEY_DOMAIN_MAP = "siteurl";
|
||||
private static final String KEY_SOURCES = "sources";
|
||||
private static final int DEFAULT_PAGE_SIZE = 10;
|
||||
|
||||
private List<String> apiUrls = new ArrayList<>();
|
||||
private Map<String, String> domainMap = new HashMap<String, String>() {{
|
||||
put("alipan", "阿里");
|
||||
put("aliyundrive", "阿里");
|
||||
put("quark", "夸克");
|
||||
put("115cdn", "115");
|
||||
put("baidu.com", "百度");
|
||||
put("uc", "UC");
|
||||
put("189.cn", "天翼");
|
||||
put("139.com", "移动");
|
||||
put("123", "123盘");
|
||||
}};
|
||||
private Set<String> sources = new HashSet<>();
|
||||
private String[] extInfos = null;
|
||||
|
||||
@Override
|
||||
public synchronized void init(Context context, String extend) throws Exception {
|
||||
super.init(context, extend);
|
||||
|
||||
this.apiUrls.clear();
|
||||
|
||||
if (!TextUtils.isEmpty(extend)) {
|
||||
try {
|
||||
if (extend.contains("###")) {
|
||||
String[] infos = extend.split("###");
|
||||
this.extInfos = infos;
|
||||
|
||||
if (infos.length > 0 && !TextUtils.isEmpty(infos[0])) {
|
||||
processExtendConfig(infos[0]);
|
||||
}
|
||||
} else {
|
||||
this.extInfos = new String[]{extend};
|
||||
processExtendConfig(extend);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
this.extInfos = null; // 重置,避免内存泄漏
|
||||
}
|
||||
|
||||
private void processExtendConfig(String config) {
|
||||
try {
|
||||
// 检查是否为HTTP URL
|
||||
if (isValidUrl(config)) {
|
||||
if (!this.apiUrls.contains(config)) {
|
||||
this.apiUrls.add(config);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 尝试JSON格式解析
|
||||
JsonObject ext = Json.safeObject(config);
|
||||
|
||||
// 处理API URLs配置
|
||||
processApiUrls(ext);
|
||||
|
||||
// 处理域名映射配置
|
||||
processDomainMap(ext);
|
||||
|
||||
// 处理来源过滤配置
|
||||
processSources(ext, true);
|
||||
} catch (Exception e) {
|
||||
// 可以添加日志记录
|
||||
}
|
||||
}
|
||||
|
||||
private void processApiUrls(JsonObject config) {
|
||||
if (config.has(KEY_API_URLS) && config.get(KEY_API_URLS).isJsonArray()) {
|
||||
JsonArray urlsArray = config.getAsJsonArray(KEY_API_URLS);
|
||||
for (JsonElement element : urlsArray) {
|
||||
if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) {
|
||||
String url = element.getAsString();
|
||||
if (isValidUrl(url) && !this.apiUrls.contains(url)) {
|
||||
this.apiUrls.add(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processDomainMap(JsonObject config) {
|
||||
if (config.has(KEY_DOMAIN_MAP) && config.get(KEY_DOMAIN_MAP).isJsonObject()) {
|
||||
JsonObject customDomains = config.getAsJsonObject(KEY_DOMAIN_MAP);
|
||||
for (Map.Entry<String, JsonElement> entry : customDomains.entrySet()) {
|
||||
if (entry == null || entry.getValue() == null) continue;
|
||||
|
||||
String domain = entry.getKey();
|
||||
String sourceName = "";
|
||||
try {
|
||||
sourceName = entry.getValue().getAsString();
|
||||
} catch (Exception e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(domain) && !TextUtils.isEmpty(sourceName) && !domainMap.containsKey(domain)) {
|
||||
domainMap.put(domain, sourceName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processSources(JsonObject config, boolean clearExisting) {
|
||||
if (config.has(KEY_SOURCES) && config.get(KEY_SOURCES).isJsonArray()) {
|
||||
if (clearExisting) {
|
||||
this.sources.clear();
|
||||
}
|
||||
|
||||
JsonArray sourcesArray = config.getAsJsonArray(KEY_SOURCES);
|
||||
for (JsonElement element : sourcesArray) {
|
||||
if (element != null && element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) {
|
||||
String source = element.getAsString();
|
||||
if (!TextUtils.isEmpty(source) && !sources.contains(source)) {
|
||||
sources.add(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidUrl(String url) {
|
||||
return !TextUtils.isEmpty(url) && (url.startsWith("http://") || url.startsWith("https://"));
|
||||
}
|
||||
|
||||
|
||||
private Map<String, String> getHeader() {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
header.put("User-Agent", Util.CHROME);
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchContent(String key, boolean quick) throws Exception {
|
||||
if (key == null || key.trim().isEmpty()) {
|
||||
return Result.error("关键词不能为空");
|
||||
}
|
||||
|
||||
return performSearch(key, 1, DEFAULT_PAGE_SIZE);
|
||||
}
|
||||
|
||||
private String performSearch(String key, int page, int pageSize) throws Exception {
|
||||
List<Vod> list = new ArrayList<>();
|
||||
int total = 0;
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("kw", key);
|
||||
params.put("page", String.valueOf(page));
|
||||
params.put("size", String.valueOf(pageSize));
|
||||
|
||||
for (String apiUrl : apiUrls) {
|
||||
if (!isValidUrl(apiUrl)) continue;
|
||||
|
||||
try {
|
||||
OkResult result = OkHttp.get(apiUrl, params, getHeader());
|
||||
if (result.getCode() == 500 || TextUtils.isEmpty(result.getBody())) continue;
|
||||
|
||||
JsonObject jsonObject = Json.safeObject(result.getBody());
|
||||
if (!jsonObject.has("code") || jsonObject.get("code").getAsInt() != 0 || !jsonObject.has("data"))
|
||||
continue;
|
||||
|
||||
JsonObject data = jsonObject.getAsJsonObject("data");
|
||||
|
||||
total = data.has("total") && !data.get("total").isJsonNull() ? data.get("total").getAsInt() : 0;
|
||||
|
||||
// 直接检查merged_by_type字段,无需三重判断
|
||||
if (!data.has("merged_by_type") || !data.get("merged_by_type").isJsonObject()) continue;
|
||||
|
||||
JsonObject mergedByType = data.getAsJsonObject("merged_by_type");
|
||||
|
||||
for (Map.Entry<String, JsonElement> categoryEntry : mergedByType.entrySet()) {
|
||||
if (!categoryEntry.getValue().isJsonArray()) continue;
|
||||
|
||||
JsonArray items = categoryEntry.getValue().getAsJsonArray();
|
||||
|
||||
for (JsonElement item : items) {
|
||||
if (!item.isJsonObject()) continue;
|
||||
|
||||
JsonObject entry = item.getAsJsonObject();
|
||||
|
||||
String vodUrl = entry.has("url") && !entry.get("url").isJsonNull() ? entry.get("url").getAsString() : "";
|
||||
if (TextUtils.isEmpty(vodUrl)) continue;
|
||||
|
||||
// 获取来源信息并映射
|
||||
String originalSource = entry.has("source") && !entry.get("source").isJsonNull() ? entry.get("source").getAsString() : "未知来源";
|
||||
String sourceName = mapSource(vodUrl, originalSource);
|
||||
|
||||
// 获取标题
|
||||
String title = entry.has("note") && !entry.get("note").isJsonNull() ? entry.get("note").getAsString() : "未命名资源";
|
||||
|
||||
// 获取图片
|
||||
String pic = getFirstImage(entry);
|
||||
|
||||
// 简化VodPlayBuilder的使用
|
||||
Vod vod = new Vod(vodUrl, title, pic, sourceName + " (" + originalSource + ")");
|
||||
// 由于只有一个播放源,直接设置播放信息
|
||||
vod.setVodPlayFrom(sourceName);
|
||||
vod.setVodPlayUrl("播放源$" + vodUrl);
|
||||
|
||||
// 来源过滤
|
||||
if (sources.isEmpty() || sources.contains(sourceName)) {
|
||||
list.add(vod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int pageCount = total > 0 && pageSize > 0 ? (total + pageSize - 1) / pageSize : 1;
|
||||
return Result.string(page, pageCount, pageSize, total, list);
|
||||
} catch (Exception e) {
|
||||
// 出错时继续尝试下一个API
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return Result.error("无法连接到任何搜索API");
|
||||
}
|
||||
|
||||
// 提取来源映射逻辑为单独方法
|
||||
private String mapSource(String vodUrl, String originalSource) {
|
||||
for (Map.Entry<String, String> domainEntry : domainMap.entrySet()) {
|
||||
if (vodUrl.contains(domainEntry.getKey())) {
|
||||
return domainEntry.getValue();
|
||||
}
|
||||
}
|
||||
return originalSource;
|
||||
}
|
||||
|
||||
// 提取图片获取逻辑为单独方法
|
||||
private String getFirstImage(JsonObject entry) {
|
||||
if (entry.has("images") && !entry.get("images").isJsonNull() && entry.get("images").isJsonArray()) {
|
||||
JsonArray images = entry.getAsJsonArray("images");
|
||||
if (images.size() > 0 && !images.get(0).isJsonNull() && images.get(0).isJsonPrimitive()) {
|
||||
return images.get(0).getAsString();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue