Compare commits

..

No commits in common. "multiThread" and "main" have entirely different histories.

238 changed files with 442 additions and 31801 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
CNAME Normal file
View File

@ -0,0 +1 @@
fm.t4tv.hz.cz

View File

@ -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
View File

@ -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.

View File

@ -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 数
[![Star History Chart](https://api.star-history.com/svg?repos=lushunming/AndroidCatVodSpider&type=Date)](https://star-history.com/#lushunming/AndroidCatVodSpider&Date)
---
## 公众号
关注公众号,获取最新更新。
![pAW8wwV.jpg](wechat.png)
## 备注
该项目仅为自己自用开发如果发现bug可以提issues但是基本不接受新需求除非我感兴趣的新需求
## 群组
为了方便讨论可以加群组,但不保证及时回复 https://t.me/+YLvmJsZoFmcyN2M1
https://github.com/CatVodTVOfficial/CatVodTVSpider

20
USE.md
View File

@ -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`文件(可能被隐藏,设置里打开显示隐藏文件,或者将文件夹删除),再重新按照操作走一遍。

View File

@ -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.

View File

@ -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
}

View File

@ -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) {

View File

@ -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)
}
}

View File

@ -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()
}
}

View File

@ -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();
}
}

View File

@ -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: $unamepasswd$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) {
}
}
}

View File

@ -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) {
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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 "";
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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";
}
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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
)

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 = "";
}
}

View File

@ -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();
}
}

View File

@ -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 ;
}
}

View File

@ -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;
}
}

View File

@ -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 = "";
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 = "";
}
}

View File

@ -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);
}
}

View File

@ -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 = "";
}
}

View File

@ -11,7 +11,6 @@ public class SpiderDebug {
}
public static void log(String msg) {
System.out.println(msg);
Log.d(TAG, msg);
}
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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>()
}
}
}

View File

@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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="
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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");

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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";
}
}
}

View File

@ -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;
}
}
}

View File

@ -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
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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)));
}
}

View File

@ -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;

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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\":[]}";
}
}
}

View File

@ -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();
}
}

View File

@ -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)
}
}

View File

@ -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))
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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