Sync all projects

This commit is contained in:
github-actions[bot]
2026-06-29 03:41:14 +00:00
parent 529cd7c625
commit 8b025e0766
11717 changed files with 6370622 additions and 0 deletions
+393
View File
@@ -0,0 +1,393 @@
# coding=utf-8
# !/usr/bin/python
"""
作者 丢丢喵推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from datetime import datetime
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import datetime
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://www.xzyx168.com"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {"class": []}
max_retries = 5
retry_count = 0
while retry_count < max_retries:
try:
detail = requests.get(url=xurl + "/xzyxvt/duanjun.html", headers=headerx, timeout=5)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('h3', class_="2p4d8xbkrf")
for vod in soups:
name_tag = vod.find('a')
if not name_tag:
continue
name = name_tag['title']
if "都市短剧" in name:
continue
id = name_tag['href']
result["class"].append({"type_id": id, "type_name": "集多🌠" + name})
return result
except requests.exceptions.ConnectionError as e:
retry_count += 1
if retry_count < max_retries:
time.sleep(1)
else:
return result
def homeVideoContent(self):
videos = []
detail = requests.get(url=xurl + "/xzyxvt/duanjun.html", headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="fb4c0sv0wd")
for soup in soups:
vods = soup.find_all('a')
for vod in vods:
name = vod['title']
id = vod['href']
pic = vod['data-original']
remark = "欢迎观看"
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
return result
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
fenge = cid.split("zmn")
url = f'{xurl}{fenge[0]}{str(page)}zmn.html'
retries = 5
for attempt in range(retries):
try:
detail = requests.get(url=url, headers=headerx, timeout=5)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('a', class_="hwkltcii1l")
for vod in soups:
name = vod['title']
id = vod['href']
pic = vod['data-original']
remarks = vod.find('span', class_="acd47d1yrm")
remark = remarks.text.strip() if remarks else ''
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多️▶️' + remark
}
videos.append(video)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
except requests.exceptions.SSLError as e:
if attempt < retries - 1:
time.sleep(1)
else:
return {'list': []}
except Exception as e:
return {'list': []}
def detailContent(self, ids):
did = ids[0]
result = {}
videos = []
xianlu = ''
bofang = ''
if 'http' not in did:
did = xurl + did
res = requests.get(url=did, headers=headerx)
res.encoding = "utf-8"
res = res.text
doc = BeautifulSoup(res, "lxml")
url = 'http://rihou.cc:88/je.json'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
content = '集多为您介绍剧情📢' + self.extract_middle_text(res,'简介:</span>','<', 0)
content = content.replace('\n', '').replace(' ', '')
director = self.extract_middle_text(res,'导演:</span>','<', 0)
actor = self.extract_middle_text(res,'主演:</span>','<', 0)
remarks = self.extract_middle_text(res,'类型:</span>','<', 0)
year = self.extract_middle_text(res,'年份:</span>','<', 0)
area = self.extract_middle_text(res, '地区:</span>', '<', 0)
if name not in content:
bofang = Jumps
xianlu = '1'
else:
soups = doc.find('div', class_="9ahntuoroa")
soup = soups.find_all('li')
for sou in soup:
id = sou.find('a')['href']
if 'http' not in id:
id = xurl + id
name = sou.find('a')['title']
bofang = bofang + name + '$' + id + '#'
bofang = bofang[:-1]
xianlu = '集多短剧专线'
videos.append({
"vod_id": did,
"vod_director": director,
"vod_actor": actor,
"vod_remarks": remarks,
"vod_year": year,
"vod_area": area,
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
res = requests.get(url=id, headers=headerx)
res.encoding = "utf-8"
res = res.text
url = self.extract_middle_text(res, '},"url":"', '"', 0).replace('\\', '')
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
return result
def searchContentPage(self, key, quick, pg):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
url = f'{xurl}/xzyxvc/{key}-wdyswzqun{str(page)}num.html'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="vgl7lerf3f")
for item in soups:
vods = item.find_all('li')
for vod in vods:
names = vod.find('a', class_="9jlvu7xrw1")
name = names['title']
id = names['href']
pic = names['data-original']
remarks = vod.find('span', class_="ni1pgkjbk7")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+404
View File
@@ -0,0 +1,404 @@
# -*- coding: utf-8 -*-
# 🌈 Love
import json
import random
import re
import sys
import threading
import time
from base64 import b64decode, b64encode
from urllib.parse import urlparse
import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from pyquery import PyQuery as pq
sys.path.append('..')
from base.spider import Spider
class Spider(Spider):
def init(self, extend=""):
try:self.proxies = json.loads(extend)
except:self.proxies = {}
self.headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Cache-Control': 'no-cache',
}
# Use working dynamic URLs directly
self.host = self.get_working_host()
self.headers.update({'Origin': self.host, 'Referer': f"{self.host}/"})
self.log(f"使用站点: {self.host}")
print(f"使用站点: {self.host}")
pass
def getName(self):
return "🌈 51吸瓜"
def isVideoFormat(self, url):
# Treat direct media formats as playable without parsing
return any(ext in (url or '') for ext in ['.m3u8', '.mp4', '.ts'])
def manualVideoCheck(self):
return False
def destroy(self):
pass
def homeContent(self, filter):
try:
response = requests.get(self.host, headers=self.headers, proxies=self.proxies, timeout=15)
if response.status_code != 200:
return {'class': [], 'list': []}
data = self.getpq(response.text)
result = {}
classes = []
# Try to get categories from different possible locations
category_selectors = [
'.category-list ul li',
'.nav-menu li',
'.menu li',
'nav ul li'
]
for selector in category_selectors:
for k in data(selector).items():
link = k('a')
href = (link.attr('href') or '').strip()
name = (link.text() or '').strip()
# Skip placeholder or invalid entries
if not href or href == '#' or not name:
continue
classes.append({
'type_name': name,
'type_id': href
})
if classes:
break
# If no categories found, create some default ones
if not classes:
classes = [
{'type_name': '首页', 'type_id': '/'},
{'type_name': '最新', 'type_id': '/latest/'},
{'type_name': '热门', 'type_id': '/hot/'}
]
result['class'] = classes
result['list'] = self.getlist(data('#index article a'))
return result
except Exception as e:
print(f"homeContent error: {e}")
return {'class': [], 'list': []}
def homeVideoContent(self):
try:
response = requests.get(self.host, headers=self.headers, proxies=self.proxies, timeout=15)
if response.status_code != 200:
return {'list': []}
data = self.getpq(response.text)
return {'list': self.getlist(data('#index article a, #archive article a'))}
except Exception as e:
print(f"homeVideoContent error: {e}")
return {'list': []}
def categoryContent(self, tid, pg, filter, extend):
try:
if '@folder' in tid:
id = tid.replace('@folder', '')
videos = self.getfod(id)
else:
# Build URL properly
if tid.startswith('/'):
if pg and pg != '1':
url = f"{self.host}{tid}page/{pg}/"
else:
url = f"{self.host}{tid}"
else:
url = f"{self.host}/{tid}"
response = requests.get(url, headers=self.headers, proxies=self.proxies, timeout=15)
if response.status_code != 200:
return {'list': [], 'page': pg, 'pagecount': 1, 'limit': 90, 'total': 0}
data = self.getpq(response.text)
videos = self.getlist(data('#archive article a, #index article a'), tid)
result = {}
result['list'] = videos
result['page'] = pg
result['pagecount'] = 1 if '@folder' in tid else 99999
result['limit'] = 90
result['total'] = 999999
return result
except Exception as e:
print(f"categoryContent error: {e}")
return {'list': [], 'page': pg, 'pagecount': 1, 'limit': 90, 'total': 0}
def detailContent(self, ids):
try:
url = f"{self.host}{ids[0]}" if not ids[0].startswith('http') else ids[0]
response = requests.get(url, headers=self.headers, proxies=self.proxies, timeout=15)
if response.status_code != 200:
return {'list': [{'vod_play_from': '51吸瓜', 'vod_play_url': f'页面加载失败${url}'}]}
data = self.getpq(response.text)
vod = {'vod_play_from': '51吸瓜'}
# Get content/description
try:
clist = []
if data('.tags .keywords a'):
for k in data('.tags .keywords a').items():
title = k.text()
href = k.attr('href')
if title and href:
clist.append('[a=cr:' + json.dumps({'id': href, 'name': title}) + '/]' + title + '[/a]')
vod['vod_content'] = ' '.join(clist) if clist else data('.post-title').text()
except:
vod['vod_content'] = data('.post-title').text() or '51吸瓜视频'
# Get video URLs (build episode list when multiple players exist)
try:
plist = []
used_names = set()
if data('.dplayer'):
for c, k in enumerate(data('.dplayer').items(), start=1):
config_attr = k.attr('data-config')
if config_attr:
try:
config = json.loads(config_attr)
video_url = config.get('video', {}).get('url', '')
# Determine a readable episode name from nearby headings if present
ep_name = ''
try:
parent = k.parents().eq(0)
# search up to a few ancestors for a heading text
for _ in range(3):
if not parent: break
heading = parent.find('h2, h3, h4').eq(0).text() or ''
heading = heading.strip()
if heading:
ep_name = heading
break
parent = parent.parents().eq(0)
except Exception:
ep_name = ''
base_name = ep_name if ep_name else f"视频{c}"
name = base_name
count = 2
# Ensure the name is unique
while name in used_names:
name = f"{base_name} {count}"
count += 1
used_names.add(name)
if video_url:
self.log(f"解析到视频: {name} -> {video_url}")
print(f"解析到视频: {name} -> {video_url}")
plist.append(f"{name}${video_url}")
except:
continue
if plist:
self.log(f"拼装播放列表,共{len(plist)}")
print(f"拼装播放列表,共{len(plist)}")
vod['vod_play_url'] = '#'.join(plist)
else:
vod['vod_play_url'] = f"未找到视频源${url}"
except Exception as e:
vod['vod_play_url'] = f"视频解析失败${url}"
return {'list': [vod]}
except Exception as e:
print(f"detailContent error: {e}")
return {'list': [{'vod_play_from': '51吸瓜', 'vod_play_url': f'详情页加载失败${ids[0] if ids else ""}'}]}
def searchContent(self, key, quick, pg="1"):
try:
url = f"{self.host}/search/{key}/{pg}" if pg != "1" else f"{self.host}/search/{key}/"
response = requests.get(url, headers=self.headers, proxies=self.proxies, timeout=15)
if response.status_code != 200:
return {'list': [], 'page': pg}
data = self.getpq(response.text)
videos = self.getlist(data('#archive article a, #index article a'))
return {'list': videos, 'page': pg}
except Exception as e:
print(f"searchContent error: {e}")
return {'list': [], 'page': pg}
def playerContent(self, flag, id, vipFlags):
url = id
p = 1
if self.isVideoFormat(url):
# m3u8/mp4 direct play; when using proxy setting, wrap to proxy for m3u8
if '.m3u8' in url:
url = self.proxy(url)
p = 0
self.log(f"播放请求: parse={p}, url={url}")
print(f"播放请求: parse={p}, url={url}")
return {'parse': p, 'url': url, 'header': self.headers}
def localProxy(self, param):
if param.get('type') == 'img':
res=requests.get(param['url'], headers=self.headers, proxies=self.proxies, timeout=10)
return [200,res.headers.get('Content-Type'),self.aesimg(res.content)]
elif param.get('type') == 'm3u8':return self.m3Proxy(param['url'])
else:return self.tsProxy(param['url'])
def proxy(self, data, type='m3u8'):
if data and len(self.proxies):return f"{self.getProxyUrl()}&url={self.e64(data)}&type={type}"
else:return data
def m3Proxy(self, url):
url=self.d64(url)
ydata = requests.get(url, headers=self.headers, proxies=self.proxies, allow_redirects=False)
data = ydata.content.decode('utf-8')
if ydata.headers.get('Location'):
url = ydata.headers['Location']
data = requests.get(url, headers=self.headers, proxies=self.proxies).content.decode('utf-8')
lines = data.strip().split('\n')
last_r = url[:url.rfind('/')]
parsed_url = urlparse(url)
durl = parsed_url.scheme + "://" + parsed_url.netloc
iskey=True
for index, string in enumerate(lines):
if iskey and 'URI' in string:
pattern = r'URI="([^"]*)"'
match = re.search(pattern, string)
if match:
lines[index] = re.sub(pattern, f'URI="{self.proxy(match.group(1), "mkey")}"', string)
iskey=False
continue
if '#EXT' not in string:
if 'http' not in string:
domain = last_r if string.count('/') < 2 else durl
string = domain + ('' if string.startswith('/') else '/') + string
lines[index] = self.proxy(string, string.split('.')[-1].split('?')[0])
data = '\n'.join(lines)
return [200, "application/vnd.apple.mpegur", data]
def tsProxy(self, url):
url = self.d64(url)
data = requests.get(url, headers=self.headers, proxies=self.proxies, stream=True)
return [200, data.headers['Content-Type'], data.content]
def e64(self, text):
try:
text_bytes = text.encode('utf-8')
encoded_bytes = b64encode(text_bytes)
return encoded_bytes.decode('utf-8')
except Exception as e:
print(f"Base64编码错误: {str(e)}")
return ""
def d64(self, encoded_text):
try:
encoded_bytes = encoded_text.encode('utf-8')
decoded_bytes = b64decode(encoded_bytes)
return decoded_bytes.decode('utf-8')
except Exception as e:
print(f"Base64解码错误: {str(e)}")
return ""
def get_working_host(self):
"""Get working host from known dynamic URLs"""
# Known working URLs from the dynamic gateway
dynamic_urls = [
'https://artist.vgwtswi.xyz',
'https://ability.vgwtswi.xyz',
'https://am.vgwtswi.xyz'
]
# Test each URL to find a working one
for url in dynamic_urls:
try:
response = requests.get(url, headers=self.headers, proxies=self.proxies, timeout=10)
if response.status_code == 200:
# Verify it has the expected content structure
data = self.getpq(response.text)
articles = data('#index article a')
if len(articles) > 0:
self.log(f"选用可用站点: {url}")
print(f"选用可用站点: {url}")
return url
except Exception as e:
continue
# Fallback to first URL if none work (better than crashing)
self.log(f"未检测到可用站点,回退: {dynamic_urls[0]}")
print(f"未检测到可用站点,回退: {dynamic_urls[0]}")
return dynamic_urls[0]
def getlist(self, data, tid=''):
videos = []
l = '/mrdg' in tid
for k in data.items():
a = k.attr('href')
b = k('h2').text()
# Some pages might not include datePublished; use a fallback
c = k('span[itemprop="datePublished"]').text() or k('.post-meta, .entry-meta, time').text()
if a and b:
videos.append({
'vod_id': f"{a}{'@folder' if l else ''}",
'vod_name': b.replace('\n', ' '),
'vod_pic': self.getimg(k('script').text()),
'vod_remarks': c or '',
'vod_tag': 'folder' if l else '',
'style': {"type": "rect", "ratio": 1.33}
})
return videos
def getfod(self, id):
url = f"{self.host}{id}"
data = self.getpq(requests.get(url, headers=self.headers, proxies=self.proxies).text)
vdata=data('.post-content[itemprop="articleBody"]')
r=['.txt-apps','.line','blockquote','.tags','.content-tabs']
for i in r:vdata.remove(i)
p=vdata('p')
videos=[]
for i,x in enumerate(vdata('h2').items()):
c=i*2
videos.append({
'vod_id': p.eq(c)('a').attr('href'),
'vod_name': p.eq(c).text(),
'vod_pic': f"{self.getProxyUrl()}&url={p.eq(c+1)('img').attr('data-xkrkllgl')}&type=img",
'vod_remarks':x.text()
})
return videos
def getimg(self, text):
match = re.search(r"loadBannerDirect\('([^']+)'", text)
if match:
url = match.group(1)
return f"{self.getProxyUrl()}&url={url}&type=img"
else:
return ''
def aesimg(self, word):
key = b'f5d965df75336270'
iv = b'97b60394abc2fbe1'
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = unpad(cipher.decrypt(word), AES.block_size)
return decrypted
def getpq(self, data):
try:
return pq(data)
except Exception as e:
print(f"{str(e)}")
return pq(data.encode('utf-8'))
+404
View File
@@ -0,0 +1,404 @@
# -*- coding: utf-8 -*-
# 🌈 Love
import json
import random
import re
import sys
import threading
import time
from base64 import b64decode, b64encode
from urllib.parse import urlparse
import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from pyquery import PyQuery as pq
sys.path.append('..')
from base.spider import Spider
class Spider(Spider):
def init(self, extend=""):
try:self.proxies = json.loads(extend)
except:self.proxies = {}
self.headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Cache-Control': 'no-cache',
}
# Use working dynamic URLs directly
self.host = self.get_working_host()
self.headers.update({'Origin': self.host, 'Referer': f"{self.host}/"})
self.log(f"使用站点: {self.host}")
print(f"使用站点: {self.host}")
pass
def getName(self):
return "🌈 51吸瓜"
def isVideoFormat(self, url):
# Treat direct media formats as playable without parsing
return any(ext in (url or '') for ext in ['.m3u8', '.mp4', '.ts'])
def manualVideoCheck(self):
return False
def destroy(self):
pass
def homeContent(self, filter):
try:
response = requests.get(self.host, headers=self.headers, proxies=self.proxies, timeout=15)
if response.status_code != 200:
return {'class': [], 'list': []}
data = self.getpq(response.text)
result = {}
classes = []
# Try to get categories from different possible locations
category_selectors = [
'.category-list ul li',
'.nav-menu li',
'.menu li',
'nav ul li'
]
for selector in category_selectors:
for k in data(selector).items():
link = k('a')
href = (link.attr('href') or '').strip()
name = (link.text() or '').strip()
# Skip placeholder or invalid entries
if not href or href == '#' or not name:
continue
classes.append({
'type_name': name,
'type_id': href
})
if classes:
break
# If no categories found, create some default ones
if not classes:
classes = [
{'type_name': '首页', 'type_id': '/'},
{'type_name': '最新', 'type_id': '/latest/'},
{'type_name': '热门', 'type_id': '/hot/'}
]
result['class'] = classes
result['list'] = self.getlist(data('#index article a'))
return result
except Exception as e:
print(f"homeContent error: {e}")
return {'class': [], 'list': []}
def homeVideoContent(self):
try:
response = requests.get(self.host, headers=self.headers, proxies=self.proxies, timeout=15)
if response.status_code != 200:
return {'list': []}
data = self.getpq(response.text)
return {'list': self.getlist(data('#index article a, #archive article a'))}
except Exception as e:
print(f"homeVideoContent error: {e}")
return {'list': []}
def categoryContent(self, tid, pg, filter, extend):
try:
if '@folder' in tid:
id = tid.replace('@folder', '')
videos = self.getfod(id)
else:
# Build URL properly
if tid.startswith('/'):
if pg and pg != '1':
url = f"{self.host}{tid}page/{pg}/"
else:
url = f"{self.host}{tid}"
else:
url = f"{self.host}/{tid}"
response = requests.get(url, headers=self.headers, proxies=self.proxies, timeout=15)
if response.status_code != 200:
return {'list': [], 'page': pg, 'pagecount': 1, 'limit': 90, 'total': 0}
data = self.getpq(response.text)
videos = self.getlist(data('#archive article a, #index article a'), tid)
result = {}
result['list'] = videos
result['page'] = pg
result['pagecount'] = 1 if '@folder' in tid else 99999
result['limit'] = 90
result['total'] = 999999
return result
except Exception as e:
print(f"categoryContent error: {e}")
return {'list': [], 'page': pg, 'pagecount': 1, 'limit': 90, 'total': 0}
def detailContent(self, ids):
try:
url = f"{self.host}{ids[0]}" if not ids[0].startswith('http') else ids[0]
response = requests.get(url, headers=self.headers, proxies=self.proxies, timeout=15)
if response.status_code != 200:
return {'list': [{'vod_play_from': '51吸瓜', 'vod_play_url': f'页面加载失败${url}'}]}
data = self.getpq(response.text)
vod = {'vod_play_from': '51吸瓜'}
# Get content/description
try:
clist = []
if data('.tags .keywords a'):
for k in data('.tags .keywords a').items():
title = k.text()
href = k.attr('href')
if title and href:
clist.append('[a=cr:' + json.dumps({'id': href, 'name': title}) + '/]' + title + '[/a]')
vod['vod_content'] = ' '.join(clist) if clist else data('.post-title').text()
except:
vod['vod_content'] = data('.post-title').text() or '51吸瓜视频'
# Get video URLs (build episode list when multiple players exist)
try:
plist = []
used_names = set()
if data('.dplayer'):
for c, k in enumerate(data('.dplayer').items(), start=1):
config_attr = k.attr('data-config')
if config_attr:
try:
config = json.loads(config_attr)
video_url = config.get('video', {}).get('url', '')
# Determine a readable episode name from nearby headings if present
ep_name = ''
try:
parent = k.parents().eq(0)
# search up to a few ancestors for a heading text
for _ in range(3):
if not parent: break
heading = parent.find('h2, h3, h4').eq(0).text() or ''
heading = heading.strip()
if heading:
ep_name = heading
break
parent = parent.parents().eq(0)
except Exception:
ep_name = ''
base_name = ep_name if ep_name else f"视频{c}"
name = base_name
count = 2
# Ensure the name is unique
while name in used_names:
name = f"{base_name} {count}"
count += 1
used_names.add(name)
if video_url:
self.log(f"解析到视频: {name} -> {video_url}")
print(f"解析到视频: {name} -> {video_url}")
plist.append(f"{name}${video_url}")
except:
continue
if plist:
self.log(f"拼装播放列表,共{len(plist)}")
print(f"拼装播放列表,共{len(plist)}")
vod['vod_play_url'] = '#'.join(plist)
else:
vod['vod_play_url'] = f"未找到视频源${url}"
except Exception as e:
vod['vod_play_url'] = f"视频解析失败${url}"
return {'list': [vod]}
except Exception as e:
print(f"detailContent error: {e}")
return {'list': [{'vod_play_from': '51吸瓜', 'vod_play_url': f'详情页加载失败${ids[0] if ids else ""}'}]}
def searchContent(self, key, quick, pg="1"):
try:
url = f"{self.host}/search/{key}/{pg}" if pg != "1" else f"{self.host}/search/{key}/"
response = requests.get(url, headers=self.headers, proxies=self.proxies, timeout=15)
if response.status_code != 200:
return {'list': [], 'page': pg}
data = self.getpq(response.text)
videos = self.getlist(data('#archive article a, #index article a'))
return {'list': videos, 'page': pg}
except Exception as e:
print(f"searchContent error: {e}")
return {'list': [], 'page': pg}
def playerContent(self, flag, id, vipFlags):
url = id
p = 1
if self.isVideoFormat(url):
# m3u8/mp4 direct play; when using proxy setting, wrap to proxy for m3u8
if '.m3u8' in url:
url = self.proxy(url)
p = 0
self.log(f"播放请求: parse={p}, url={url}")
print(f"播放请求: parse={p}, url={url}")
return {'parse': p, 'url': url, 'header': self.headers}
def localProxy(self, param):
if param.get('type') == 'img':
res=requests.get(param['url'], headers=self.headers, proxies=self.proxies, timeout=10)
return [200,res.headers.get('Content-Type'),self.aesimg(res.content)]
elif param.get('type') == 'm3u8':return self.m3Proxy(param['url'])
else:return self.tsProxy(param['url'])
def proxy(self, data, type='m3u8'):
if data and len(self.proxies):return f"{self.getProxyUrl()}&url={self.e64(data)}&type={type}"
else:return data
def m3Proxy(self, url):
url=self.d64(url)
ydata = requests.get(url, headers=self.headers, proxies=self.proxies, allow_redirects=False)
data = ydata.content.decode('utf-8')
if ydata.headers.get('Location'):
url = ydata.headers['Location']
data = requests.get(url, headers=self.headers, proxies=self.proxies).content.decode('utf-8')
lines = data.strip().split('\n')
last_r = url[:url.rfind('/')]
parsed_url = urlparse(url)
durl = parsed_url.scheme + "://" + parsed_url.netloc
iskey=True
for index, string in enumerate(lines):
if iskey and 'URI' in string:
pattern = r'URI="([^"]*)"'
match = re.search(pattern, string)
if match:
lines[index] = re.sub(pattern, f'URI="{self.proxy(match.group(1), "mkey")}"', string)
iskey=False
continue
if '#EXT' not in string:
if 'http' not in string:
domain = last_r if string.count('/') < 2 else durl
string = domain + ('' if string.startswith('/') else '/') + string
lines[index] = self.proxy(string, string.split('.')[-1].split('?')[0])
data = '\n'.join(lines)
return [200, "application/vnd.apple.mpegur", data]
def tsProxy(self, url):
url = self.d64(url)
data = requests.get(url, headers=self.headers, proxies=self.proxies, stream=True)
return [200, data.headers['Content-Type'], data.content]
def e64(self, text):
try:
text_bytes = text.encode('utf-8')
encoded_bytes = b64encode(text_bytes)
return encoded_bytes.decode('utf-8')
except Exception as e:
print(f"Base64编码错误: {str(e)}")
return ""
def d64(self, encoded_text):
try:
encoded_bytes = encoded_text.encode('utf-8')
decoded_bytes = b64decode(encoded_bytes)
return decoded_bytes.decode('utf-8')
except Exception as e:
print(f"Base64解码错误: {str(e)}")
return ""
def get_working_host(self):
"""Get working host from known dynamic URLs"""
# Known working URLs from the dynamic gateway
dynamic_urls = [
'https://artist.vgwtswi.xyz',
'https://ability.vgwtswi.xyz',
'https://am.vgwtswi.xyz'
]
# Test each URL to find a working one
for url in dynamic_urls:
try:
response = requests.get(url, headers=self.headers, proxies=self.proxies, timeout=10)
if response.status_code == 200:
# Verify it has the expected content structure
data = self.getpq(response.text)
articles = data('#index article a')
if len(articles) > 0:
self.log(f"选用可用站点: {url}")
print(f"选用可用站点: {url}")
return url
except Exception as e:
continue
# Fallback to first URL if none work (better than crashing)
self.log(f"未检测到可用站点,回退: {dynamic_urls[0]}")
print(f"未检测到可用站点,回退: {dynamic_urls[0]}")
return dynamic_urls[0]
def getlist(self, data, tid=''):
videos = []
l = '/mrdg' in tid
for k in data.items():
a = k.attr('href')
b = k('h2').text()
# Some pages might not include datePublished; use a fallback
c = k('span[itemprop="datePublished"]').text() or k('.post-meta, .entry-meta, time').text()
if a and b:
videos.append({
'vod_id': f"{a}{'@folder' if l else ''}",
'vod_name': b.replace('\n', ' '),
'vod_pic': self.getimg(k('script').text()),
'vod_remarks': c or '',
'vod_tag': 'folder' if l else '',
'style': {"type": "rect", "ratio": 1.33}
})
return videos
def getfod(self, id):
url = f"{self.host}{id}"
data = self.getpq(requests.get(url, headers=self.headers, proxies=self.proxies).text)
vdata=data('.post-content[itemprop="articleBody"]')
r=['.txt-apps','.line','blockquote','.tags','.content-tabs']
for i in r:vdata.remove(i)
p=vdata('p')
videos=[]
for i,x in enumerate(vdata('h2').items()):
c=i*2
videos.append({
'vod_id': p.eq(c)('a').attr('href'),
'vod_name': p.eq(c).text(),
'vod_pic': f"{self.getProxyUrl()}&url={p.eq(c+1)('img').attr('data-xkrkllgl')}&type=img",
'vod_remarks':x.text()
})
return videos
def getimg(self, text):
match = re.search(r"loadBannerDirect\('([^']+)'", text)
if match:
url = match.group(1)
return f"{self.getProxyUrl()}&url={url}&type=img"
else:
return ''
def aesimg(self, word):
key = b'f5d965df75336270'
iv = b'97b60394abc2fbe1'
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = unpad(cipher.decrypt(word), AES.block_size)
return decrypted
def getpq(self, data):
try:
return pq(data)
except Exception as e:
print(f"{str(e)}")
return pq(data.encode('utf-8'))
+780
View File
@@ -0,0 +1,780 @@
# coding=utf-8
# !/usr/bin/python
"""
作者 丢丢喵 内容均从互联网收集而来 仅供交流学习使用 严禁用于商业用途 请于24小时内删除
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from datetime import datetime
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import datetime
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://a131.ybbyelc.com" # https://58ys.app/
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
headers = {
'User-Agent': 'Dart/3.9 (dart:io)',
'version': '1.3.86',
'device': 'android',
'host': 'a131.ybbyelc.com',
'content-type': 'application/json',
'Timestamp': str(int(time.time() * 1000)),
'clienttype': 'phone',
'token': '',
'Accept-Encoding': 'gzip, deflate',
'Content-Length': '37'
}
class Spider(Spider):
def getName(self):
return "丢丢喵"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "电影@影视", "type_name": "丢丢🌠电影"},
{"type_id": "连续剧@影视", "type_name": "丢丢🌠连续剧"},
{"type_id": "动漫@影视", "type_name": "丢丢🌠动漫"},
{"type_id": "综艺@影视", "type_name": "丢丢🌠综艺"},
{"type_id": "短剧@短剧", "type_name": "丢丢🌠短剧"}],
"list": [],
"filters": {"电影@影视": [{"key": "地区",
"name": "地区",
"value": [{"n": "全部", "v": ""},
{"n": "中国大陆", "v": "中国大陆"},
{"n": "中国香港", "v": "中国香港"},
{"n": "中国台湾", "v": "中国台湾"},
{"n": "韩国", "v": "韩国"},
{"n": "泰国", "v": "泰国"},
{"n": "日本", "v": "日本"},
{"n": "美国", "v": "美国"},
{"n": "英国", "v": "英国"},
{"n": "法国", "v": "法国"},
{"n": "德国", "v": "德国"},
{"n": "西班牙", "v": "西班牙"},
{"n": "新加坡", "v": "新加坡"},
{"n": "加拿大", "v": "加拿大"},
{"n": "菲律宾", "v": "菲律宾"},
{"n": "非洲", "v": "非洲"},
{"n": "巴西", "v": "巴西"},
{"n": "捷克", "v": "捷克"},
{"n": "俄罗斯", "v": "俄罗斯"},
{"n": "土耳其", "v": "土耳其"},
{"n": "墨西哥", "v": "墨西哥"},
{"n": "阿根廷", "v": "阿根廷"},
{"n": "马来西亚", "v": "马来西亚"},
{"n": "波兰", "v": "波兰"},
{"n": "乌克兰", "v": "乌克兰"},
{"n": "罗马尼亚", "v": "罗马尼亚"},
{"n": "东南亚", "v": "东南亚"}]},
{"key": "类型",
"name": "类型",
"value": [{"n": "全部", "v": ""},
{"n": "喜剧", "v": "喜剧"},
{"n": "爱情", "v": "爱情"},
{"n": "恐怖", "v": "恐怖"},
{"n": "动作", "v": "动作"},
{"n": "科幻", "v": "科幻"},
{"n": "剧情", "v": "剧情"},
{"n": "战争", "v": "战争"},
{"n": "警匪", "v": "警匪"},
{"n": "纪录片", "v": "纪录片"},
{"n": "犯罪", "v": "犯罪"},
{"n": "动画", "v": "动画"},
{"n": "奇幻", "v": "奇幻"},
{"n": "武侠", "v": "武侠"},
{"n": "冒险", "v": "冒险"},
{"n": "枪战", "v": "枪战"},
{"n": "悬疑", "v": "悬疑"},
{"n": "惊悚", "v": "惊悚"},
{"n": "经典", "v": "经典"},
{"n": "青春", "v": "青春"},
{"n": "文艺", "v": "文艺"},
{"n": "微电影", "v": "微电影"},
{"n": "古装", "v": "古装"},
{"n": "历史", "v": "历史"},
{"n": "运动", "v": "运动"},
{"n": "农村", "v": "农村"},
{"n": "儿童", "v": "儿童"},
{"n": "网络电影", "v": "网络电影"},
{"n": "情色", "v": "情色"},
{"n": "同性", "v": "同性"}]},
{"key": "列表",
"name": "列表",
"value": [{"n": "全部", "v": ""},
{"n": "最新上传", "v": "Time"},
{"n": "人气高", "v": "Hits"},
{"n": "评分高", "v": "Score"}]},
{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2026", "v": "2026"},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"},
{"n": "2017", "v": "2017"},
{"n": "2016", "v": "2016"},
{"n": "2015", "v": "2015"},
{"n": "2014", "v": "2014"},
{"n": "2013", "v": "2013"},
{"n": "2012", "v": "2012"},
{"n": "2011", "v": "2011"},
{"n": "2010", "v": "2010"},
{"n": "2009", "v": "2009"},
{"n": "2008", "v": "2008"},
{"n": "2007", "v": "2007"},
{"n": "2006", "v": "2006"},
{"n": "2005", "v": "2005"},
{"n": "2004", "v": "2004"},
{"n": "2003", "v": "2003"},
{"n": "2002", "v": "2002"},
{"n": "2001", "v": "2001"},
{"n": "2000", "v": "2000"},
{"n": "更早", "v": "更早"}]}],
"连续剧@影视": [{"key": "地区",
"name": "地区",
"value": [{"n": "全部", "v": ""},
{"n": "中国大陆", "v": "中国大陆"},
{"n": "中国香港", "v": "中国香港"},
{"n": "中国台湾", "v": "中国台湾"},
{"n": "韩国", "v": "韩国"},
{"n": "泰国", "v": "泰国"},
{"n": "日本", "v": "日本"},
{"n": "美国", "v": "美国"},
{"n": "英国", "v": "英国"},
{"n": "法国", "v": "法国"},
{"n": "德国", "v": "德国"},
{"n": "西班牙", "v": "西班牙"},
{"n": "新加坡", "v": "新加坡"},
{"n": "加拿大", "v": "加拿大"},
{"n": "菲律宾", "v": "菲律宾"},
{"n": "非洲", "v": "非洲"},
{"n": "巴西", "v": "巴西"},
{"n": "捷克", "v": "捷克"},
{"n": "俄罗斯", "v": "俄罗斯"},
{"n": "土耳其", "v": "土耳其"},
{"n": "墨西哥", "v": "墨西哥"},
{"n": "阿根廷", "v": "阿根廷"},
{"n": "马来西亚", "v": "马来西亚"},
{"n": "波兰", "v": "波兰"},
{"n": "乌克兰", "v": "乌克兰"},
{"n": "罗马尼亚", "v": "罗马尼亚"},
{"n": "东南亚", "v": "东南亚"}]},
{"key": "类型",
"name": "类型",
"value": [{"n": "全部", "v": ""},
{"n": "古装", "v": "古装"},
{"n": "战争", "v": "战争"},
{"n": "青春", "v": "青春"},
{"n": "偶像", "v": "偶像"},
{"n": "喜剧", "v": "喜剧"},
{"n": "家庭", "v": "家庭"},
{"n": "犯罪", "v": "犯罪"},
{"n": "动作", "v": "动作"},
{"n": "科幻", "v": "科幻"},
{"n": "奇幻", "v": "奇幻"},
{"n": "仙侠", "v": "仙侠"},
{"n": "武侠", "v": "武侠"},
{"n": "剧情", "v": "剧情"},
{"n": "历史", "v": "历史"},
{"n": "综艺", "v": "综艺"},
{"n": "真人秀", "v": "真人秀"},
{"n": "音乐", "v": "音乐"},
{"n": "经典", "v": "经典"},
{"n": "乡村", "v": "乡村"},
{"n": "情景", "v": "情景"},
{"n": "商战", "v": "商战"},
{"n": "网剧", "v": "网剧"},
{"n": "其他", "v": "其他"},
{"n": "同性", "v": "同性"}]},
{"key": "列表",
"name": "列表",
"value": [{"n": "全部", "v": ""},
{"n": "最新上传", "v": "Time"},
{"n": "人气高", "v": "Hits"},
{"n": "评分高", "v": "Score"}]},
{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2026", "v": "2026"},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"},
{"n": "2017", "v": "2017"},
{"n": "2016", "v": "2016"},
{"n": "2015", "v": "2015"},
{"n": "2014", "v": "2014"},
{"n": "2013", "v": "2013"},
{"n": "2012", "v": "2012"},
{"n": "2011", "v": "2011"},
{"n": "2010", "v": "2010"},
{"n": "2009", "v": "2009"},
{"n": "2008", "v": "2008"},
{"n": "2007", "v": "2007"},
{"n": "2006", "v": "2006"},
{"n": "2005", "v": "2005"},
{"n": "2004", "v": "2004"},
{"n": "2003", "v": "2003"},
{"n": "2002", "v": "2002"},
{"n": "2001", "v": "2001"},
{"n": "2000", "v": "2000"},
{"n": "更早", "v": "更早"}]}],
"动漫@影视": [{"key": "地区",
"name": "地区",
"value": [{"n": "全部", "v": ""},
{"n": "中国大陆", "v": "中国大陆"},
{"n": "中国香港", "v": "中国香港"},
{"n": "中国台湾", "v": "中国台湾"},
{"n": "韩国", "v": "韩国"},
{"n": "泰国", "v": "泰国"},
{"n": "日本", "v": "日本"},
{"n": "美国", "v": "美国"},
{"n": "英国", "v": "英国"},
{"n": "法国", "v": "法国"},
{"n": "德国", "v": "德国"},
{"n": "西班牙", "v": "西班牙"},
{"n": "新加坡", "v": "新加坡"},
{"n": "加拿大", "v": "加拿大"},
{"n": "菲律宾", "v": "菲律宾"},
{"n": "非洲", "v": "非洲"},
{"n": "巴西", "v": "巴西"},
{"n": "捷克", "v": "捷克"},
{"n": "俄罗斯", "v": "俄罗斯"},
{"n": "土耳其", "v": "土耳其"},
{"n": "墨西哥", "v": "墨西哥"},
{"n": "阿根廷", "v": "阿根廷"},
{"n": "马来西亚", "v": "马来西亚"},
{"n": "波兰", "v": "波兰"},
{"n": "乌克兰", "v": "乌克兰"},
{"n": "罗马尼亚", "v": "罗马尼亚"},
{"n": "东南亚", "v": "东南亚"}]},
{"key": "类型",
"name": "类型",
"value": [{"n": "全部", "v": ""},
{"n": "情感", "v": "情感"},
{"n": "科幻", "v": "科幻"},
{"n": "热血", "v": "热血"},
{"n": "推理", "v": "推理"},
{"n": "搞笑", "v": "搞笑"},
{"n": "冒险", "v": "冒险"},
{"n": "萝莉", "v": "萝莉"},
{"n": "校园", "v": "校园"},
{"n": "动作", "v": "动作"},
{"n": "机战", "v": "机战"},
{"n": "运动", "v": "运动"},
{"n": "战争", "v": "战争"},
{"n": "少年", "v": "少年"},
{"n": "少女", "v": "少女"},
{"n": "社会", "v": "社会"},
{"n": "原创", "v": "原创"},
{"n": "亲子", "v": "亲子"},
{"n": "益智", "v": "益智"},
{"n": "励志", "v": "励志"},
{"n": "其他", "v": "其他"}]},
{"key": "列表",
"name": "列表",
"value": [{"n": "全部", "v": ""},
{"n": "最新上传", "v": "Time"},
{"n": "人气高", "v": "Hits"},
{"n": "评分高", "v": "Score"}]},
{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2026", "v": "2026"},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"},
{"n": "2017", "v": "2017"},
{"n": "2016", "v": "2016"},
{"n": "2015", "v": "2015"},
{"n": "2014", "v": "2014"},
{"n": "2013", "v": "2013"},
{"n": "2012", "v": "2012"},
{"n": "2011", "v": "2011"},
{"n": "2010", "v": "2010"},
{"n": "2009", "v": "2009"},
{"n": "2008", "v": "2008"},
{"n": "2007", "v": "2007"},
{"n": "2006", "v": "2006"},
{"n": "2005", "v": "2005"},
{"n": "2004", "v": "2004"},
{"n": "2003", "v": "2003"},
{"n": "2002", "v": "2002"},
{"n": "2001", "v": "2001"},
{"n": "2000", "v": "2000"},
{"n": "更早", "v": "更早"}]}],
"综艺@影视": [{"key": "地区",
"name": "地区",
"value": [{"n": "全部", "v": ""},
{"n": "中国大陆", "v": "中国大陆"},
{"n": "中国香港", "v": "中国香港"},
{"n": "中国台湾", "v": "中国台湾"},
{"n": "韩国", "v": "韩国"},
{"n": "泰国", "v": "泰国"},
{"n": "日本", "v": "日本"},
{"n": "美国", "v": "美国"},
{"n": "英国", "v": "英国"},
{"n": "法国", "v": "法国"},
{"n": "德国", "v": "德国"},
{"n": "西班牙", "v": "西班牙"},
{"n": "新加坡", "v": "新加坡"},
{"n": "加拿大", "v": "加拿大"},
{"n": "菲律宾", "v": "菲律宾"},
{"n": "非洲", "v": "非洲"},
{"n": "巴西", "v": "巴西"},
{"n": "捷克", "v": "捷克"},
{"n": "俄罗斯", "v": "俄罗斯"},
{"n": "土耳其", "v": "土耳其"},
{"n": "墨西哥", "v": "墨西哥"},
{"n": "阿根廷", "v": "阿根廷"},
{"n": "马来西亚", "v": "马来西亚"},
{"n": "波兰", "v": "波兰"},
{"n": "乌克兰", "v": "乌克兰"},
{"n": "罗马尼亚", "v": "罗马尼亚"},
{"n": "东南亚", "v": "东南亚"}]},
{"key": "类型",
"name": "类型",
"value": [{"n": "全部", "v": ""},
{"n": "真人秀", "v": "真人秀"},
{"n": "脱口秀", "v": "脱口秀"},
{"n": "情感", "v": "情感"},
{"n": "访谈", "v": "访谈"},
{"n": "播报", "v": "播报"},
{"n": "旅游", "v": "旅游"},
{"n": "音乐", "v": "音乐"},
{"n": "美食", "v": "美食"},
{"n": "纪实", "v": "纪实"},
{"n": "曲艺", "v": "曲艺"},
{"n": "生活", "v": "生活"},
{"n": "游戏互动", "v": "游戏互动"},
{"n": "财经", "v": "财经"},
{"n": "求职", "v": "求职"}]},
{"key": "列表",
"name": "列表",
"value": [{"n": "全部", "v": ""},
{"n": "最新上传", "v": "Time"},
{"n": "人气高", "v": "Hits"},
{"n": "评分高", "v": "Score"}]},
{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2026", "v": "2026"},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"},
{"n": "2017", "v": "2017"},
{"n": "2016", "v": "2016"},
{"n": "2015", "v": "2015"},
{"n": "2014", "v": "2014"},
{"n": "2013", "v": "2013"},
{"n": "2012", "v": "2012"},
{"n": "2011", "v": "2011"},
{"n": "2010", "v": "2010"},
{"n": "2009", "v": "2009"},
{"n": "2008", "v": "2008"},
{"n": "2007", "v": "2007"},
{"n": "2006", "v": "2006"},
{"n": "2005", "v": "2005"},
{"n": "2004", "v": "2004"},
{"n": "2003", "v": "2003"},
{"n": "2002", "v": "2002"},
{"n": "2001", "v": "2001"},
{"n": "2000", "v": "2000"},
{"n": "更早", "v": "更早"}]}],
"短剧@短剧": [{"key": "地区",
"name": "地区",
"value": [{"n": "全部", "v": ""},
{"n": "中国大陆", "v": "中国大陆"},
{"n": "中国香港", "v": "中国香港"},
{"n": "中国台湾", "v": "中国台湾"},
{"n": "韩国", "v": "韩国"},
{"n": "泰国", "v": "泰国"},
{"n": "日本", "v": "日本"},
{"n": "美国", "v": "美国"},
{"n": "英国", "v": "英国"},
{"n": "法国", "v": "法国"},
{"n": "德国", "v": "德国"},
{"n": "西班牙", "v": "西班牙"},
{"n": "新加坡", "v": "新加坡"},
{"n": "加拿大", "v": "加拿大"},
{"n": "菲律宾", "v": "菲律宾"},
{"n": "非洲", "v": "非洲"},
{"n": "巴西", "v": "巴西"},
{"n": "捷克", "v": "捷克"},
{"n": "俄罗斯", "v": "俄罗斯"},
{"n": "土耳其", "v": "土耳其"},
{"n": "墨西哥", "v": "墨西哥"},
{"n": "阿根廷", "v": "阿根廷"},
{"n": "马来西亚", "v": "马来西亚"},
{"n": "波兰", "v": "波兰"},
{"n": "乌克兰", "v": "乌克兰"},
{"n": "罗马尼亚", "v": "罗马尼亚"},
{"n": "东南亚", "v": "东南亚"}]},
{"key": "类型",
"name": "类型",
"value": [{"n": "全部", "v": ""},
{"n": "动作运动", "v": "动作运动"},
{"n": "爱情言情", "v": "爱情言情"},
{"n": "科幻灾难", "v": "科幻灾难"},
{"n": "玄幻奇幻", "v": "玄幻奇幻"},
{"n": "惊悚恐怖", "v": "惊悚恐怖"},
{"n": "推理侦探", "v": "推理侦探"},
{"n": "喜剧幽默", "v": "喜剧幽默"},
{"n": "古装宫庭", "v": "古装宫庭"},
{"n": "都市社会", "v": "都市社会"},
{"n": "冒险探险", "v": "冒险探险"},
{"n": "青春校园", "v": "青春校园"},
{"n": "仙侠武侠", "v": "仙侠武侠"},
{"n": "大佬大神", "v": "大佬大神"},
{"n": "娇妻宝爸", "v": "娇妻宝爸"},
{"n": "霸道总裁", "v": "霸道总裁"},
{"n": "屌丝逆袭", "v": "屌丝逆袭"},
{"n": "穿越重生", "v": "穿越重生"},
{"n": "战争历史", "v": "战争历史"},
{"n": "医道医生", "v": "医道医生"},
{"n": "玄门道法", "v": "玄门道法"}]},
{"key": "列表",
"name": "列表",
"value": [{"n": "全部", "v": ""},
{"n": "最新上传", "v": "Time"},
{"n": "人气高", "v": "Hits"},
{"n": "评分高", "v": "Score"}]},
{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2026", "v": "2026"},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"},
{"n": "2017", "v": "2017"},
{"n": "2016", "v": "2016"},
{"n": "2015", "v": "2015"},
{"n": "2014", "v": "2014"},
{"n": "2013", "v": "2013"},
{"n": "2012", "v": "2012"},
{"n": "2011", "v": "2011"},
{"n": "2010", "v": "2010"},
{"n": "2009", "v": "2009"},
{"n": "2008", "v": "2008"},
{"n": "2007", "v": "2007"},
{"n": "2006", "v": "2006"},
{"n": "2005", "v": "2005"},
{"n": "2004", "v": "2004"},
{"n": "2003", "v": "2003"},
{"n": "2002", "v": "2002"},
{"n": "2001", "v": "2001"},
{"n": "2000", "v": "2000"},
{"n": "更早", "v": "更早"}]}]}}
return result
def homeVideoContent(self):
data = self.build_home_request_data()
json_data = self.convert_to_json(data)
urlz = self.get_home_video_url()
response = self.send_home_video_request(urlz, json_data)
data = self.parse_home_video_response(response)
videos = self.process_home_video_list(data)
result = self.build_home_video_result(videos)
return result
def build_home_request_data(self):
return {"Id": 0,"Type": 0,"Page": 1,"Limit": 10}
def convert_to_json(self, data):
return json.dumps(data)
def get_home_video_url(self):
return f'{xurl}/addons/appto/app.php/tindex/home_vod_list2'
def send_home_video_request(self, urlz, json_data):
response = requests.post(url=urlz, headers=headers, data=json_data)
return response
def parse_home_video_response(self, response):
response.encoding = "utf-8"
return response.json()
def process_home_video_list(self, data):
videos = []
for vod in data['data']['vods']:
video = self.parse_home_video_item(vod)
videos.append(video)
return videos
def parse_home_video_item(self, vod):
return {
"vod_id": vod['vod_id'],
"vod_name": vod['vod_name'],
"vod_pic": vod['vod_pic'].replace('mac:', 'https:'),
"vod_year": vod.get('vod_pubdate', '暂无备注'),
"vod_remarks": vod.get('vod_remarks', '暂无备注')
}
def build_home_video_result(self, videos):
return {'list': videos}
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
fenge = self.split_cid(cid)
page = self.get_page_number(pg)
NdType = self.get_ext_value(ext, '年代')
DqType = self.get_ext_value(ext, '地区')
LxType = self.get_ext_value(ext, '类型')
LbType = self.get_ext_value(ext, '列表')
data = self.build_category_request_data(fenge, page, NdType, DqType, LxType, LbType)
json_data = self.convert_to_json(data)
urlz = self.get_category_url()
response = self.send_category_request(urlz, json_data)
data = self.parse_category_response(response)
videos = self.process_category_list(data)
result = self.build_category_result(videos, pg)
return result
def split_cid(self, cid):
return cid.split("@")
def get_page_number(self, pg):
return int(pg) if pg else 1
def get_ext_value(self, ext, key):
return ext[key] if key in ext else ''
def build_category_request_data(self, fenge, page, NdType, DqType, LxType, LbType):
return {"Area": DqType,"Class": LxType,"Limit": 10,"Page": page,"Sort": LbType,"Tab": fenge[1],"Type": fenge[0],"Year": NdType,"topic_id": "Null"}
def convert_to_json(self, data):
return json.dumps(data)
def get_category_url(self):
return f'{xurl}/addons/appto/app.php/tindex/page_vod_lists'
def send_category_request(self, urlz, json_data):
response = requests.post(url=urlz, headers=headers, data=json_data)
return response
def parse_category_response(self, response):
response.encoding = "utf-8"
return response.json()
def process_category_list(self, data):
videos = []
for vod in data['data']['list']:
if not self.should_skip_video(vod):
video = self.parse_category_video_item(vod)
videos.append(video)
return videos
def should_skip_video(self, vod):
name = vod['vod_name']
skip_names = ["PG电子"]
return name in skip_names
def parse_category_video_item(self, vod):
return {
"vod_id": vod['vod_id'],
"vod_name": vod['vod_name'],
"vod_pic": vod['vod_pic'].replace('mac:', 'https:'),
"vod_year": vod.get('vod_pubdate', '暂无备注'),
"vod_remarks": vod.get('vod_remarks', '暂无备注')
}
def build_category_result(self, videos, pg):
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = self.get_first_id(ids)
data = self.build_detail_request_data(did)
json_data = self.convert_to_json(data)
urlz = self.get_detail_url()
response_data = self.send_detail_request(urlz, json_data)
content = self.build_vod_content(response_data)
director = self.get_nested_value(response_data, 'vod_director')
actor = self.get_nested_value(response_data, 'vod_actor')
remarks = self.get_nested_value(response_data, 'vod_remarks')
year = self.get_nested_value(response_data, 'vod_year')
area = self.get_nested_value(response_data, 'vod_area')
bofang = self.get_nested_value(response_data, 'vod_play_url')
videos = self.build_video_info(did, director, actor, remarks, year, area, content, bofang)
result = self.build_detail_result(videos)
return result
def get_first_id(self, ids):
return ids[0]
def build_detail_request_data(self, did):
return {"id": did}
def convert_to_json(self, data):
return json.dumps(data)
def get_detail_url(self):
return f'{xurl}/addons/appto/app.php/tindex/page_player'
def send_detail_request(self, urlz, json_data):
response = requests.post(url=urlz, headers=headers, data=json_data)
response.encoding = "utf-8"
return response.json()
def build_vod_content(self, response_data):
return '😸丢丢为您介绍剧情📢' + response_data.get('data', {}).get('vod_blurb', '')
def get_nested_value(self, response_data, key):
return response_data.get('data', {}).get(key, '')
def build_video_info(self, did, director, actor, remarks, year, area, content, bofang):
return [{"vod_id": did,"vod_director": director,"vod_actor": actor,"vod_remarks": remarks,"vod_year": year,"vod_area": area,"vod_content": content,"vod_play_from": "丢丢58专线","vod_play_url": bofang}]
def build_detail_result(self, videos):
result = {}
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = id
result["header"] = headerx
return result
def searchContentPage(self, key, quick, pg):
page = self.get_page_number(pg)
data = self.build_search_request_data(key, page)
json_data = self.convert_to_json(data)
urlz = self.get_search_url()
response = self.send_search_request(urlz, json_data)
data = self.parse_search_response(response)
videos = self.process_search_list(data)
result = self.build_search_result(videos, pg)
return result
def get_page_number(self, pg):
return int(pg) if pg else 1
def build_search_request_data(self, key, page):
return {"Limit": 10,"Page": page,"Search": key,"type": None}
def convert_to_json(self, data):
return json.dumps(data)
def get_search_url(self):
return f'{xurl}/addons/appto/app.php/tindex/search_film'
def send_search_request(self, urlz, json_data):
response = requests.post(url=urlz, headers=headers, data=json_data)
return response
def parse_search_response(self, response):
response.encoding = "utf-8"
return response.json()
def process_search_list(self, data):
videos = []
for vod in data['data']['vods']['list']:
video = self.parse_search_video_item(vod)
videos.append(video)
return videos
def parse_search_video_item(self, vod):
return {
"vod_id": vod['vod_id'],
"vod_name": vod['vod_name'],
"vod_pic": vod['vod_pic'].replace('mac:', 'https:'),
"vod_remarks": vod.get('vod_remarks', '暂无备注')
}
def build_search_result(self, videos, pg):
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+493
View File
@@ -0,0 +1,493 @@
# coding = utf-8
# !/usr/bin/python
"""
作者 丢丢喵推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://ptt.red"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
pm = ''
class Spider(Spider):
global xurl
global headerx
global headers
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "67", "type_name": "集多🌠爽剧"},
{"type_id": "68", "type_name": "集多🌠言情"},
{"type_id": "70", "type_name": "集多🌠穿越"},
{"type_id": "71", "type_name": "集多🌠悬疑"},
{"type_id": "73", "type_name": "集多🌠古装"},
{"type_id": "80", "type_name": "集多🌠都市"},
{"type_id": "84", "type_name": "集多🌠甜宠"},
{"type_id": "85", "type_name": "集多🌠恋爱"},
{"type_id": "74", "type_name": "集多🌠其他"}],
"list": [],
"filters": {"67": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"68": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"70": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"71": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"73": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"80": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"84": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"85": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"74": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}]}}
return result
def homeVideoContent(self):
videos = []
try:
detail = requests.get(url=xurl + "/p/66", headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="row")
for soup in soups:
vods = soup.find_all('div', class_="col-xl-2")
for vod in vods:
names = vod.find('div', class_="lines")
name = names.find('a').text
ids = vod.find('div', class_="embed-responsive")
id = ids.find('a')['href']
pic = vod.find('img')['src']
if 'http' not in pic:
pic = xurl + pic
remarks = vod.find('div', class_="imagelabel")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
return result
except:
pass
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
if '年代' in ext.keys():
NdType = ext['年代']
else:
NdType = ''
if page == 1:
url = f'{xurl}/p/66/c/{cid}'
else:
url = f'{xurl}/p/66/c/{cid}?year={NdType}&page={str(page)}'
try:
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="row")
for soup in soups:
vods = soup.find_all('div', class_="col-xl-2")
for vod in vods:
names = vod.find('div', class_="lines")
name = names.find('a').text
ids = vod.find('div', class_="embed-responsive")
id = ids.find('a')['href']
pic = vod.find('img')['src']
if 'http' not in pic:
pic = xurl + pic
remarks = vod.find('div', class_="imagelabel")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
except:
pass
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
global pm
did = ids[0]
result = {}
videos = []
if 'http' not in did:
did = xurl + did
res = requests.get(url=did, headers=headerx)
res.encoding = "utf-8"
res = res.text
url = 'http://rihou.cc:88/je.json'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
content = '集多🎉为您介绍剧情📢' + self.extract_middle_text(res,'劇情介紹</h3>','</p>', 0)
content = content.replace('<p>', '').replace(' ', '')
actor = self.extract_middle_text(res, '領銜主演</h3>', '<h3 class="mt-3">',1,'href=".*?">(.*?)</a>')
remarks = self.extract_middle_text(res, '狀態</th><td>', '</td>', 0)
year = self.extract_middle_text(res, '年代</th><td>', '</td>', 0)
area = self.extract_middle_text(res, '>國家</th><td>', '</td>', 0)
if name not in content:
bofang = Jumps
else:
if '/p/1' in res or '/p/53' in res:
doc = BeautifulSoup(res, "lxml")
soups = doc.find('div', class_="col-5")
bofang = soups.find('a')['href']
if 'http' not in bofang:
bofang = xurl + bofang
else:
bofang = self.extract_middle_text(res, '<div class="seqs mb-4">', '</div>', 3,'href="(.*?)">(.*?)</a>')
videos.append({
"vod_id": did,
"vod_actor": actor,
"vod_remarks": remarks,
"vod_year": year,
"vod_area": area,
"vod_content": content,
"vod_play_from": "请观看",
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
parts = id.split("http")
xiutan = 0
if xiutan == 0:
if len(parts) > 1:
before_https, after_https = parts[0], 'http' + parts[1]
if '/tp/jd.m3u8' in after_https:
url = after_https
else:
res = requests.get(url=after_https, headers=headerx)
res = res.text
url = self.extract_middle_text(res, '"contentUrl":"', '"', 0).replace('\\', '')
result = {}
result["parse"] = xiutan
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
return result
def searchContentPage(self, key, quick, page):
result = {}
videos = []
if not page:
page = '1'
if page == '1':
url = f'{xurl}/node/search?title={key}'
else:
url = f'{xurl}/q/{key}?page={str(page)}'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="row")
for soup in soups:
vods = soup.find_all('div', class_="col-xl-2")
for vod in vods:
names = vod.find('div', class_="lines")
name = names.find('a').text
ids = vod.find('div', class_="embed-responsive")
id = ids.find('a')['href']
pic = vod.find('img')['src']
if 'http' not in pic:
pic = xurl + pic
remarks = vod.find('div', class_="imagelabel")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = page
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
Binary file not shown.
+315
View File
@@ -0,0 +1,315 @@
# coding = utf-8
# !/usr/bin/python
# 新时代青年 2025.06.25 getApp第三版
import re,sys,uuid,json,base64,urllib3
from Crypto.Cipher import AES
from base.spider import Spider
from Crypto.Util.Padding import pad,unpad
sys.path.append('..')
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
class Spider(Spider):
xurl,key,iv,init_data,search_verify = '','','','',''
headerx = {
'User-Agent': 'okhttp/3.10.0' # okhttp/3.14.9
}
def getName(self):
return "首页"
def init(self, extend):
js1=json.loads(extend)
host = js1['host']
if not re.match(r'^https?:\/\/[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(:\d+)?(\/)?$',host):
host = self.fetch(host, headers=self.headerx, timeout=10, verify=False).text.rstrip('/')
api = js1.get('api','/api.php/getappapi')
if str(api) == '2':
api = '/api.php/qijiappapi'
self.xurl = host + api
self.key = js1['datakey']
self.iv = js1.get('dataiv',self.key)
res = self.fetch(self.xurl + '.index/initV119', headers=self.headerx, verify=False).json()
encrypted_data = res['data']
response = self.decrypt(encrypted_data)
init_data = json.loads(response)
self.init_data = init_data
self.search_verify = init_data['config'].get('system_search_verify_status',False)
def homeContent(self, filter):
kjson = self.init_data
result = {"class": [], "filters": {}}
for i in kjson['type_list']:
if not(i['type_name'] in {'全部', 'QQ', 'juo.one'} or '企鹅群' in i['type_name']):
result['class'].append({
"type_id": i['type_id'],
"type_name": i['type_name']
})
name_mapping = {'class': '类型', 'area': '地区', 'lang': '语言', 'year': '年份', 'sort': '排序'}
filter_items = []
for filter_type in i.get('filter_type_list', []):
filter_name = filter_type.get('name')
values = filter_type.get('list', [])
if not values:
continue
value_list = [{"n": value, "v": value} for value in values]
display_name = name_mapping.get(filter_name, filter_name)
key = 'by' if filter_name == 'sort' else filter_name
filter_items.append({
"key": key,
"name": display_name,
"value": value_list
})
type_id = i.get('type_id')
if filter_items:
result["filters"][str(type_id)] = filter_items
return result
def homeVideoContent(self):
videos = []
kjson = self.init_data
for i in kjson['type_list']:
for item in i['recommend_list']:
vod_id = item['vod_id']
name = item['vod_name']
pic = item['vod_pic']
remarks = item['vod_remarks']
video = {
"vod_id": vod_id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remarks
}
videos.append(video)
return {'list': videos}
def categoryContent(self, cid, pg, filter, ext):
videos = []
payload = {
'area': ext.get('area','全部'),
'year': ext.get('year','全部'),
'type_id': cid,
'page': str(pg),
'sort': ext.get('sort','最新'),
'lang': ext.get('lang','全部'),
'class': ext.get('class','全部')
}
url = f'{self.xurl}.index/typeFilterVodList'
res = self.post(url=url, headers=self.headerx,data=payload, verify=False).json()
encrypted_data = res['data']
kjson = self.decrypt(encrypted_data)
kjson1 = json.loads(kjson)
for i in kjson1['recommend_list']:
id = i['vod_id']
name = i['vod_name']
pic = i['vod_pic']
remarks = i['vod_remarks']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remarks
}
videos.append(video)
return {'list': videos, 'page': pg, 'pagecount': 9999, 'limit': 90, 'total': 999999}
def detailContent(self, ids):
did = ids[0]
payload = {
'vod_id': did,
}
api_endpoints = ['vodDetail', 'vodDetail2']
for endpoint in api_endpoints:
url = f'{self.xurl}.index/{endpoint}'
response = self.post(url=url, headers=self.headerx, data=payload, verify=False)
if response.status_code == 200:
response_data = response.json()
encrypted_data = response_data['data']
kjson1 = self.decrypt(encrypted_data)
kjson = json.loads(kjson1)
break
videos = []
play_form = ''
play_url = ''
lineid = 1
name_count = {}
for line in kjson['vod_play_list']:
keywords = {'防走丢', '', '防失群', '官网'}
player_show = line['player_info']['show']
if any(keyword in player_show for keyword in keywords):
player_show = f'{lineid}线'
line['player_info']['show'] = player_show
count = name_count.get(player_show, 0) + 1
name_count[player_show] = count
if count > 1:
line['player_info']['show'] = f"{player_show}{count}"
play_form += line['player_info']['show'] + '$$$'
parse = line['player_info']['parse']
parse_type = line['player_info']['parse_type']
player_parse_type = line['player_info']['player_parse_type']
kurls = ""
for vod in line['urls']:
token = 'token+' + vod['token']
kurls += f"{str(vod['name'])}${parse},{vod['url']},{token},{player_parse_type},{parse_type}#"
kurls = kurls.rstrip('#')
play_url += kurls + '$$$'
lineid += 1
play_form = play_form.rstrip('$$$')
play_url = play_url.rstrip('$$$')
videos.append({
"vod_id": did,
"vod_name": kjson['vod']['vod_name'],
"vod_actor": kjson['vod']['vod_actor'].replace('演员', ''),
"vod_director": kjson['vod'].get('vod_director', '').replace('导演', ''),
"vod_content": kjson['vod']['vod_content'],
"vod_remarks": kjson['vod']['vod_remarks'],
"vod_year": kjson['vod']['vod_year'] + '',
"vod_area": kjson['vod']['vod_area'],
"vod_play_from": play_form,
"vod_play_url": play_url
})
return {'list': videos}
def playerContent(self, flag, id, vipFlags):
url = ''
aid = id.split(',')
uid = aid[0]
kurl = aid[1]
token = aid[2].replace('token+', '')
player_parse_type = aid[3]
parse_type = aid[4]
if parse_type == '0':
res = {"parse": 0, "url": kurl, "header": {'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 14; 23113RK12C Build/SKQ1.231004.001)'}}
elif parse_type == '2':
res = {"parse": 1, "url": uid+kurl, "header": {'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 14; 23113RK12C Build/SKQ1.231004.001)'}}
elif player_parse_type == '2':
response = self.fetch(url=f'{uid}{kurl}',verify=False)
if response.status_code == 200:
kjson1 = response.json()
res = {"parse": 0, "url": kjson1['url'], "header": {'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 14; 23113RK12C Build/SKQ1.231004.001)'}}
else:
id1 = self.encrypt(kurl)
payload = {
'parse_api': uid,
'url': id1,
'player_parse_type': player_parse_type,
'token': token
}
url1 = f"{self.xurl}.index/vodParse"
response = self.post(url=url1, headers=self.headerx, data=payload, verify=False)
if response.status_code == 200:
response_data = response.json()
encrypted_data = response_data['data']
kjson = self.decrypt(encrypted_data)
kjson1 = json.loads(kjson)
kjson2 = kjson1['json']
kjson3 = json.loads(kjson2)
url = kjson3['url']
res = {"parse": 0, "playUrl": '', "url": url, "header": {'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 14; 23113RK12C Build/SKQ1.231004.001)'}}
return res
def searchContent(self, key, quick, pg="1"):
videos = []
if 'xiaohys.com' in self.xurl:
host = self.xurl.split('api.php')[0]
data = self.fetch(f'{host}index.php/ajax/suggest?mid=1&wd={key}').json()
for i in data['list']:
videos.append({
"vod_id": i['id'],
"vod_name": i['name'],
"vod_pic": i.get('pic')
})
else:
payload = {
'keywords': key,
'type_id': "0",
'page': str(pg)
}
if self.search_verify:
verifi = self.verification()
if verifi is None:
return {'list':[]}
payload['code'] = verifi['code']
payload['key'] = verifi['uuid']
url = f'{self.xurl}.index/searchList'
res = self.post(url=url, data=payload, headers=self.headerx, verify=False).json()
if not res.get('data'):
return {'list':[] ,'msg': res.get('msg')}
encrypted_data = res['data']
kjson = self.decrypt(encrypted_data)
kjson1 = json.loads(kjson)
for i in kjson1['search_list']:
id = i['vod_id']
name = i['vod_name']
pic = i['vod_pic']
remarks = i['vod_year'] + ' ' + i['vod_class']
videos.append({
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remarks
})
return {'list': videos, 'page': pg, 'pagecount': 9999, 'limit': 90, 'total': 999999}
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def decrypt(self, encrypted_data_b64):
key_bytes = self.key.encode('utf-8')
iv_bytes = self.iv.encode('utf-8')
encrypted_data = base64.b64decode(encrypted_data_b64)
cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
decrypted_padded = cipher.decrypt(encrypted_data)
decrypted = unpad(decrypted_padded, AES.block_size)
return decrypted.decode('utf-8')
def encrypt(self, sencrypted_data):
key_bytes = self.key.encode('utf-8')
iv_bytes = self.iv.encode('utf-8')
data_bytes = sencrypted_data.encode('utf-8')
padded_data = pad(data_bytes, AES.block_size)
cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
encrypted_bytes = cipher.encrypt(padded_data)
encrypted_data_b64 = base64.b64encode(encrypted_bytes).decode('utf-8')
return encrypted_data_b64
def ocr(self, base64img):
dat2 = self.post("https://api.nn.ci/ocr/b64/text", data=base64img, headers=self.headerx, verify=False).text
if dat2:
return dat2
else:
return None
def verification(self):
random_uuid = str(uuid.uuid4())
dat = self.fetch(f'{self.xurl}.verify/create?key={random_uuid}',headers=self.headerx, verify=False).content
base64_img = base64.b64encode(dat).decode('utf-8')
if not dat:
return None
code = self.ocr(base64_img)
if not code:
return None
code = self.replace_code(code)
if not (len(code) == 4 and code.isdigit()):
return None
return {'uuid': random_uuid, 'code': code}
def replace_code(self, text):
replacements = {'y': '9', '': '0', 'q': '0', 'u': '0', 'o': '0', '>': '1', 'd': '0', 'b': '8', '': '2','D': '0', '': '5'}
if len(text) == 3:
text = text.replace('566', '5066')
text = text.replace('066', '1666')
return ''.join(replacements.get(c, c) for c in text)
+354
View File
@@ -0,0 +1,354 @@
var il = 'jsjiami.com.v6',
il_ = ['il'],
lIIIl1ll = [il, '\x6f\x6b\x68\x74\x74\x70\x2f\x33\x2e\x31\x35', '\x69\x6e\x64\x65\x78\x4f\x66', '\x24\x24\x24', '\x73\x70\x6c\x69\x74', '\x74\x72\x69\x6d', '\x26\x26\x26', '\x3a\x2f\x2f', '\x6c\x6f\x67', '\x70\x69\x63\x55\x72\x6c\x3a\x20', '\x72\x65\x70\x6c\x61\x63\x65', '\x70\x75\x73\x68', '\x2f\x66\x69\x6c\x65\x2f\x6c\x69\x76\x65\x73\x6f\x75\x72\x63\x65\x6c\x69\x73\x74', '\x2f\x6c\x69\x76\x65\x73\x6f\x75\x72\x63\x65\x6c\x69\x73\x74', '\x47\x45\x54', '\x70\x61\x72\x73\x65', '\x63\x6f\x6e\x74\x65\x6e\x74', '\x73\x75\x62\x73\x74\x72\x69\x6e\x67', '\x6c\x61\x73\x74\x49\x6e\x64\x65\x78\x4f\x66', '\x6e\x61\x6d\x65', '\x75\x72\x6c', '\x3d\x3d\x3d\x3d\x20\x3e\x3e\x3e\x20', '\x73\x74\x72\x69\x6e\x67\x69\x66\x79', '\x65\x78\x65\x63', '\x74\x65\x73\x74', '\x6d\x61\x74\x63\x68', '\x63\x68\x61\x6e\x6e\x65\x6c', '\x2c\x23\x67\x65\x6e\x72\x65\x23\x0a', '\x75\x72\x6c\x73', '\x64\x61\x74\x61', '\x64\x61\x74\x61\x6c\x69\x73\x74', '\x70\x72\x6f\x76', '\x6c\x69\x73\x74', '\x2d\x2d\x2d', '\x6c\x69\x6e\x65', '\x77\x65\x62\x50\x69\x63\x55\x72\x6c\x3a\x20', '\x23\x45\x58\x54\x4d\x33\x55', '\x22\x63\x68\x61\x6e\x6e\x65\x6c\x22', '\x22\x75\x72\x6c\x73\x22', '\x22\x64\x61\x74\x61\x6c\x69\x73\x74\x22', '\x6c\x65\x6e\x67\x74\x68', '\x23\x67\x65\x6e\x72\x65\x23', '\x7b\x6e\x61\x6d\x65\x7d', '\x7b\x63\x61\x74\x65\x7d', '\u76f4\u64ad\u5217\u8868', '\x6e\x75\x6c\x6c', '\x74\x79\x70\x65\x5f\x69\x64', '\x76\x6f\x64\x5f\x70\x6c\x61\x79\x5f\x75\x72\x6c', '\x68\x61\x73\x4f\x77\x6e\x50\x72\x6f\x70\x65\x72\x74\x79', '\x6a\x6f\x69\x6e', '\x76\x6f\x64\x5f\x70\x6c\x61\x79\x5f\x66\x72\x6f\x6d', '\x6a\x43\x50\x73\x4e\x6a\x77\x69\x4a\x61\x51\x6d\x69\x2e\x63\x6f\x4e\x4f\x6d\x47\x72\x2e\x76\x56\x36\x41\x46\x67\x79\x74\x74\x3d\x3d'];
function Ii1l1III(_0x3b13df, _0x346a54) {
_0x3b13df = ~~'0x' ['concat'](_0x3b13df['slice'](0x0));
var _0x4db44b = lIIIl1ll[_0x3b13df];
return _0x4db44b;
};
(function(_0x209161, _0x5eaa4a) {
var _0x42ecdf = 0x0;
for (_0x5eaa4a = _0x209161['shift'](_0x42ecdf >> 0x2); _0x5eaa4a && _0x5eaa4a !== (_0x209161['pop'](_0x42ecdf >> 0x3) + '')['replace'](/[CPNwJQNOGrVAFgytt=]/g, ''); _0x42ecdf++) {
_0x42ecdf = _0x42ecdf ^ 0x127efd;
}
}(lIIIl1ll, Ii1l1III));
let headers = {
'User-Agent': Ii1l1III('0')
};
let classes = [];
let cates = {};
let picUrl = '';
let webPaths = {};
function init(IiIIi1i) {
let i1Ii11I1 = '';
if (IiIIi1i[Ii1l1III('1')](Ii1l1III('2')) > 0x0) {
i1Ii11I1 = IiIIi1i[Ii1l1III('3')](Ii1l1III('2'))[0x0][Ii1l1III('4')]();
IiIIi1i = IiIIi1i[Ii1l1III('3')](Ii1l1III('2'))[0x1][Ii1l1III('4')]();
}
if (IiIIi1i[Ii1l1III('1')](Ii1l1III('5')) > 0x0) {
picUrl = IiIIi1i[Ii1l1III('3')](Ii1l1III('5'))[0x1][Ii1l1III('4')]();
if (picUrl[Ii1l1III('1')](Ii1l1III('6')) < 0x0) {
picUrl = i1Ii11I1 + picUrl;
}
IiIIi1i = IiIIi1i[Ii1l1III('3')](Ii1l1III('5'))[0x0][Ii1l1III('4')]();
}
console[Ii1l1III('7')](Ii1l1III('8') + picUrl);
let IIlIlI1I = IiIIi1i[Ii1l1III('3')]('\x23');
for (const IlII1I1 of IIlIlI1I) {
if (IlII1I1[Ii1l1III('1')]('\x24') > 0x0) {
let illIl111 = IlII1I1;
let Ill1iIi = IlII1I1[Ii1l1III('3')]('\x24')[0x0];
if (illIl111[Ii1l1III('1')](Ii1l1III('6')) < 0x0) {
illIl111 = illIl111[Ii1l1III('9')]('\x24', '\x24' + i1Ii11I1);
}
classes[Ii1l1III('a')]({
'type_id': illIl111,
'type_name': Ill1iIi[Ii1l1III('9')]('\x21\x21', '')
});
} else {
let II1lIlli = IlII1I1;
if (II1lIlli[Ii1l1III('1')](Ii1l1III('6')) < 0x0) {
II1lIlli = i1Ii11I1 + II1lIlli;
}
II1lIlli = II1lIlli[Ii1l1III('9')](Ii1l1III('b'), Ii1l1III('c'));
let Illi11ll = req(II1lIlli, {
'\x6d\x65\x74\x68\x6f\x64': Ii1l1III('d'),
'\x68\x65\x61\x64\x65\x72\x73': headers
});
try {
let l1lIiill = JSON[Ii1l1III('e')](Illi11ll[Ii1l1III('f')]);
let lillI11l = II1lIlli[Ii1l1III('10')](0x0, II1lIlli[Ii1l1III('11')]('\x2f') + 0x1);
for (const i1iilII1 of l1lIiill) {
let Iillil = i1iilII1[Ii1l1III('12')];
let lI1iIl = i1iilII1[Ii1l1III('13')];
let illIl111 = Iillil + '\x24' + (lI1iIl[Ii1l1III('1')](Ii1l1III('6')) < 0x0 ? lillI11l : '') + lI1iIl;
classes[Ii1l1III('a')]({
'type_id': illIl111,
'type_name': Iillil[Ii1l1III('9')]('\x21\x21', '')
});
webPaths[illIl111] = lillI11l;
}
} catch (Ii1Ii11) {
console[Ii1l1III('7')](Ii1l1III('14') + Ii1Ii11);
}
}
}
}
function home(I1iiIiIl) {
return JSON[Ii1l1III('15')]({
'class': classes,
'filters': null
});
}
function parseM3u(iIi1Ii1I, I1IlIIIi) {
let iI1iiIii = {};
let iiI11111 = /(#EXTINF:.+?),([^,]+?)\s*\n(.+?)\s*\n/g;
let ii1iilil = null;
while ((ii1iilil = iiI11111[Ii1l1III('16')](iIi1Ii1I)) != null) {
let lllli1iI = ii1iilil[0x1];
let il1Ili1I = ii1iilil[0x2];
let liIlll1l = ii1iilil[0x3];
if (il1Ili1I == null || liIlll1l == null || il1Ili1I == '' || liIlll1l == '') {
continue;
}
il1Ili1I = il1Ili1I[Ii1l1III('4')]();
liIlll1l = liIlll1l[Ii1l1III('4')]();
let IiI1lI1l = I1IlIIIi;
let ilIl1i1i = /group-title="(.*?)"/;
if (ilIl1i1i[Ii1l1III('17')](lllli1iI)) {
IiI1lI1l = lllli1iI[Ii1l1III('18')](ilIl1i1i)[0x1];
}
if (!iI1iiIii[IiI1lI1l]) {
iI1iiIii[IiI1lI1l] = [];
}
iI1iiIii[IiI1lI1l][Ii1l1III('a')](il1Ili1I + '\x2c' + liIlll1l);
}
let ll11III1 = '';
for (const li1Ili in iI1iiIii) {
ll11III1 += li1Ili + '\x0a';
let IlIil1ll = iI1iiIii[li1Ili];
for (const li1iI11 of IlIil1ll) {
ll11III1 += li1iI11 + '\x0a';
}
}
return ll11III1;
}
function parseFm(IliiIl1I) {
let lliiI1i1 = '';
let Iii1ll = JSON[Ii1l1III('e')](IliiIl1I);
for (const i1lIlli1 of Iii1ll) {
let I111Il1l = i1lIlli1[Ii1l1III('12')];
let ilI11li = i1lIlli1[Ii1l1III('19')];
lliiI1i1 += I111Il1l + Ii1l1III('1a');
for (const iiilI1iI of ilI11li) {
let I11111l1 = iiilI1iI[Ii1l1III('12')];
let IlI1l1I1 = iiilI1iI[Ii1l1III('1b')];
for (const l1II1lll of IlI1l1I1) {
lliiI1i1 += I11111l1 + '\x2c' + l1II1lll + '\x0a';
}
}
}
return lliiI1i1;
}
function parseLu(iIliI1lI) {
let IIlilI1i = '';
let I11ilI1i = JSON[Ii1l1III('e')](iIliI1lI)[Ii1l1III('1c')];
for (const i1Ii1l1 of I11ilI1i[Ii1l1III('1d')]) {
let I11111l = i1Ii1l1[Ii1l1III('1e')];
let IiIiii1l = i1Ii1l1[Ii1l1III('1f')];
IIlilI1i += I11111l + Ii1l1III('1a');
for (const l1111lI of IiIiii1l) {
let lIlI1iI = l1111lI[Ii1l1III('12')];
let ll11i1II = l1111lI[Ii1l1III('1b')];
for (const Iliilii of ll11i1II) {
IIlilI1i += lIlI1iI + Ii1l1III('20') + Iliilii[Ii1l1III('21')] + '\x2c' + Iliilii[Ii1l1III('13')] + '\x0a';
}
}
}
return IIlilI1i;
}
function getCateData(IliI1i) {
let iI1I1I1I = picUrl;
if (IliI1i[Ii1l1III('1')](Ii1l1III('5')) > 0x0) {
iI1I1I1I = IliI1i[Ii1l1III('3')](Ii1l1III('5'))[0x1][Ii1l1III('4')]();
if (iI1I1I1I[Ii1l1III('1')](Ii1l1III('6')) < 0x0 && webPaths[IliI1i]) {
iI1I1I1I = webPaths[IliI1i] + iI1I1I1I;
}
IliI1i = IliI1i[Ii1l1III('3')](Ii1l1III('5'))[0x0][Ii1l1III('4')]();
}
console[Ii1l1III('7')](Ii1l1III('22') + iI1I1I1I);
let ll1iIiiI = IliI1i[Ii1l1III('3')]('\x24')[0x1];
let i1I1l1i = IliI1i[Ii1l1III('3')]('\x24')[0x0];
if (!cates[IliI1i]) {
cates[IliI1i] = [];
let iIl11Iii = headers;
if (ll1iIiiI[Ii1l1III('1')]('\x7c') > 0x0) {
let ii111I1I = decodeURIComponent(ll1iIiiI[Ii1l1III('3')]('\x7c')[0x1]);
ll1iIiiI = ll1iIiiI[Ii1l1III('3')]('\x7c')[0x0];
for (const II1Ii1l of ii111I1I[Ii1l1III('3')]('\x26')) {
if (II1Ii1l[Ii1l1III('1')]('\x3d') > 0x0) {
let lI1lliii = II1Ii1l[Ii1l1III('3')]('\x3d')[0x0];
let I11Iii1i = II1Ii1l[Ii1l1III('3')]('\x3d')[0x1];
iIl11Iii[lI1lliii] = I11Iii1i;
}
}
}
let I111lilI = req(ll1iIiiI, {
'\x6d\x65\x74\x68\x6f\x64': Ii1l1III('d'),
'\x68\x65\x61\x64\x65\x72\x73': iIl11Iii
});
I111lilI = I111lilI[Ii1l1III('f')][Ii1l1III('4')]();
if (I111lilI[Ii1l1III('1')](Ii1l1III('23')) >= 0x0) {
I111lilI = parseM3u(I111lilI, i1I1l1i);
} else if (I111lilI[Ii1l1III('1')](Ii1l1III('24')) > 0x0 && I111lilI[Ii1l1III('1')](Ii1l1III('25')) > 0x0) {
I111lilI = parseFm(I111lilI);
} else if (I111lilI[Ii1l1III('1')](Ii1l1III('26')) > 0x0 && I111lilI[Ii1l1III('1')](Ii1l1III('25')) > 0x0) {
I111lilI = parseLu(I111lilI);
}
let li1IiiII = (i1I1l1i + '\x0a' + I111lilI[Ii1l1III('9')]('\x0d', ''))[Ii1l1III('3')]('\x0a');
let lli11iI = i1I1l1i;
let IiiIIiIi = null;
let iiiI1l = '';
for (let i1ii1IIl = 0x0; i1ii1IIl < li1IiiII[Ii1l1III('27')]; i1ii1IIl++) {
let lIliIii = li1IiiII[i1ii1IIl][Ii1l1III('9')](/\s+/g, '');
if (lIliIii != '' && lIliIii[Ii1l1III('1')](Ii1l1III('6')) < 0x0 && (lIliIii[Ii1l1III('1')]('\x2c') < 0x0 || lIliIii[Ii1l1III('1')](Ii1l1III('28')) > 0x0)) {
if (iiiI1l != '') {
let ilIIIl = iI1I1I1I[Ii1l1III('9')](Ii1l1III('29'), encodeURIComponent(lli11iI))[Ii1l1III('9')](Ii1l1III('2a'), encodeURIComponent(i1I1l1i));
let ilI1ilI = ilIIIl[Ii1l1III('1')]('\x3c');
let iili1I1i = ilIIIl[Ii1l1III('11')]('\x3e');
if (ilI1ilI > -0x1 && iili1I1i > ilI1ilI) {
let I11Ilili = ilIIIl[Ii1l1III('10')](ilI1ilI, iili1I1i + 0x1);
let I1liliII = new RegExp(I11Ilili[Ii1l1III('9')](/<|>/g, ''));
let lii11liI = lli11iI[Ii1l1III('9')](I1liliII, function(Ili1lIi1, iiliII1l) {
return iiliII1l;
});
ilIIIl = ilIIIl[Ii1l1III('9')](I11Ilili, lii11liI);
console[Ii1l1III('7')](lli11iI + '\x2c\x20' + ilIIIl);
}
let IiiIIiIi = {
'vod_id': IliI1i + Ii1l1III('2') + cates[IliI1i][Ii1l1III('27')],
'vod_name': lli11iI,
'vod_pic': ilIIIl,
'vod_remarks': '',
'type_name': Ii1l1III('2b'),
'vod_year': '',
'vod_area': '',
'vod_actor': '',
'vod_director': '',
'vod_content': '',
'vod_play_from': i1I1l1i,
'vod_play_url': iiiI1l
};
cates[IliI1i][Ii1l1III('a')](IiiIIiIi);
}
lli11iI = lIliIii[Ii1l1III('3')]('\x2c')[0x0][Ii1l1III('4')]();
iiiI1l = '';
} else if (lIliIii[Ii1l1III('1')]('\x2c') > 0x0 && /http|rtmp|rtsp|rsp/ [Ii1l1III('17')](lIliIii)) {
let l1iiI1ii = lIliIii[Ii1l1III('3')]('\x2c');
if (iiiI1l != '') {
iiiI1l += '\x23';
}
iiiI1l += l1iiI1ii[0x0][Ii1l1III('4')]() + '\x24' + l1iiI1ii[0x1][Ii1l1III('4')]();
}
}
if (iiiI1l != '') {
let II1Iliil = iI1I1I1I[Ii1l1III('9')](Ii1l1III('29'), encodeURIComponent(lli11iI))[Ii1l1III('9')](Ii1l1III('2a'), encodeURIComponent(i1I1l1i));
let ilI1ilI = II1Iliil[Ii1l1III('1')]('\x3c');
let iili1I1i = II1Iliil[Ii1l1III('11')]('\x3e');
if (ilI1ilI > -0x1 && iili1I1i > ilI1ilI) {
let I11Ilili = II1Iliil[Ii1l1III('10')](ilI1ilI, iili1I1i + 0x1);
let I1liliII = new RegExp(I11Ilili[Ii1l1III('9')](/<|>/g, ''));
let lii11liI = I1liliII[Ii1l1III('17')](lli11iI) ? lli11iI[Ii1l1III('18')](I1liliII)[0x1] : Ii1l1III('2c');
II1Iliil = II1Iliil[Ii1l1III('9')](I11Ilili, lii11liI);
}
let IiiIIiIi = {
'vod_id': IliI1i + Ii1l1III('2') + cates[IliI1i][Ii1l1III('27')],
'vod_name': lli11iI,
'vod_pic': II1Iliil,
'vod_remarks': '',
'type_name': Ii1l1III('2b'),
'vod_year': '',
'vod_area': '',
'vod_actor': '',
'vod_director': '',
'vod_content': '',
'vod_play_from': i1I1l1i,
'vod_play_url': iiiI1l
};
cates[IliI1i][Ii1l1III('a')](IiiIIiIi);
}
}
return cates[IliI1i];
}
function homeVod(liIIlIl1) {
let iIl1IIii = getCateData(classes[0x0][Ii1l1III('2d')]);
let I1l1iil = JSON[Ii1l1III('15')]({
'list': iIl1IIii
});
return I1l1iil;
}
function category(I1l1i1Ii, l1IiiIli, IIi1Illi, lilIliIl) {
let IIi1i1ll = [];
if (l1IiiIli == 0x1) {
IIi1i1ll = getCateData(I1l1i1Ii);
}
let iIiiIi1i = JSON[Ii1l1III('15')]({
'list': IIi1i1ll
});
return iIiiIi1i;
}
function detail(lIl11iii) {
let I1IIIil = lIl11iii[Ii1l1III('3')](Ii1l1III('2'));
let liiiil1i = I1IIIil[0x0];
let l1l111II = liiiil1i[Ii1l1III('3')]('\x24')[0x0];
let Il1li11i = parseInt(I1IIIil[0x1]);
let Iill11Ii = getCateData(liiiil1i)[Il1li11i];
console[Ii1l1III('7')](JSON[Ii1l1III('15')](Iill11Ii));
if (l1l111II[Ii1l1III('1')]('\x21\x21') >= 0x0) {
l1l111II = l1l111II[Ii1l1III('9')]('\x21\x21', '');
const ii1l1iil = Iill11Ii[Ii1l1III('2e')][Ii1l1III('3')]('\x23');
console[Ii1l1III('7')](JSON[Ii1l1III('15')](ii1l1iil));
let i1Ili1I = {};
let IIIllli1 = {};
for (const i1IiIlIl of ii1l1iil) {
let Ill1iii1 = i1IiIlIl[Ii1l1III('3')]('\x24')[0x0];
let IIiIII11 = l1l111II;
if (Ill1iii1[Ii1l1III('1')](Ii1l1III('20')) > 0x0) {
IIiIII11 = Ill1iii1[Ii1l1III('3')](Ii1l1III('20'))[0x1];
Ill1iii1 = Ill1iii1[Ii1l1III('3')](Ii1l1III('20'))[0x0];
}
if (!i1Ili1I[Ii1l1III('2f')](Ill1iii1)) {
i1Ili1I[Ill1iii1] = 0x1;
} else {
i1Ili1I[Ill1iii1]++;
}
IIiIII11 = l1l111II + (i1Ili1I[Ill1iii1] > 0x1 ? '\x20' + i1Ili1I[Ill1iii1] : '');
if (!IIIllli1[Ii1l1III('2f')](IIiIII11)) {
IIIllli1[IIiIII11] = [];
}
IIIllli1[IIiIII11][Ii1l1III('a')](Ill1iii1 + '\x24' + i1IiIlIl[Ii1l1III('3')]('\x24')[0x1]);
}
let III1i1ii = [];
let iii1lIIi = [];
for (let iliI1I1i in IIIllli1) {
III1i1ii[Ii1l1III('a')](iliI1I1i);
iii1lIIi[Ii1l1III('a')](IIIllli1[iliI1I1i][Ii1l1III('30')]('\x23'));
}
Iill11Ii[Ii1l1III('31')] = III1i1ii[Ii1l1III('30')](Ii1l1III('2'));
Iill11Ii[Ii1l1III('2e')] = iii1lIIi[Ii1l1III('30')](Ii1l1III('2'));
}
return JSON[Ii1l1III('15')]({
'list': [Iill11Ii]
});
}
function play(l1llIIii, illiiIII, lIIIiIiI) {
return JSON[Ii1l1III('15')]({
'parse': 0x0,
'url': illiiIII
});
}
function search(I1lll, lI1iiIII) {
return null;
}
__JS_SPIDER__ = {
'\x69\x6e\x69\x74': init,
'\x68\x6f\x6d\x65': home,
'\x68\x6f\x6d\x65\x56\x6f\x64': homeVod,
'\x63\x61\x74\x65\x67\x6f\x72\x79': category,
'\x64\x65\x74\x61\x69\x6c': detail,
'\x70\x6c\x61\x79': play,
'\x73\x65\x61\x72\x63\x68': search
};;
il = 'jsjiami.com.v6';
+768
View File
@@ -0,0 +1,768 @@
# -*- coding: utf-8 -*-
# by @嗷呜
import json
import re
import sys
import time
from base64 import b64decode, b64encode
from urllib.parse import parse_qs
import requests
from pyquery import PyQuery as pq
sys.path.append('..')
from base.spider import Spider
from concurrent.futures import ThreadPoolExecutor
class Spider(Spider):
def init(self, extend=""):
tid = 'douyin'
headers = self.gethr(0, tid)
response = requests.head(self.hosts[tid], headers=headers)
ttwid = response.cookies.get('ttwid')
headers.update({
'authority': self.hosts[tid].split('//')[-1],
'cookie': f'ttwid={ttwid}' if ttwid else ''
})
self.dyheaders = headers
pass
def getName(self):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def destroy(self):
pass
headers = [
{
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0"
},
{
"User-Agent": "Dart/3.4 (dart:io)"
}
]
excepturl = 'https://www.baidu.com'
hosts = {
"huya": ["https://www.huya.com","https://mp.huya.com"],
"douyin": "https://live.douyin.com",
"douyu": "https://www.douyu.com",
"wangyi": "https://cc.163.com",
"bili": ["https://api.live.bilibili.com", "https://api.bilibili.com"]
}
referers = {
"huya": "https://live.cdn.huya.com",
"douyin": "https://live.douyin.com",
"douyu": "https://m.douyu.com",
"bili": "https://live.bilibili.com"
}
playheaders = {
"wangyi": {
"User-Agent": "ExoPlayer",
"Connection": "Keep-Alive",
"Icy-MetaData": "1"
},
"bili": {
'Accept': '*/*',
'Icy-MetaData': '1',
'referer': referers['bili'],
'user-agent': headers[0]['User-Agent']
},
'douyin': {
'User-Agent': 'libmpv',
'Icy-MetaData': '1'
},
'huya': {
'User-Agent': 'ExoPlayer',
'Connection': 'Keep-Alive',
'Icy-MetaData': '1'
},
'douyu': {
'User-Agent': 'libmpv',
'Icy-MetaData': '1'
}
}
def process_bili(self):
try:
self.blfdata = self.fetch(
f'{self.hosts["bili"][0]}/room/v1/Area/getList?need_entrance=1&parent_id=0',
headers=self.gethr(0, 'bili')
).json()
return ('bili', [{'key': 'cate', 'name': '分类',
'value': [{'n': i['name'], 'v': str(i['id'])}
for i in self.blfdata['data']]}])
except Exception as e:
print(f"bili处理错误: {e}")
return 'bili', None
def process_douyin(self):
try:
data = self.getpq(self.hosts['douyin'], headers=self.dyheaders)('script')
for i in data.items():
if 'categoryData' in i.text():
content = i.text()
start = content.find('{')
end = content.rfind('}') + 1
if start != -1 and end != -1:
json_str = content[start:end]
json_str = json_str.replace('\\"', '"')
try:
self.dyifdata = json.loads(json_str)
return ('douyin', [{'key': 'cate', 'name': '分类',
'value': [{'n': i['partition']['title'],
'v': f"{i['partition']['id_str']}@@{i['partition']['title']}"}
for i in self.dyifdata['categoryData']]}])
except json.JSONDecodeError as e:
print(f"douyin解析错误: {e}")
return 'douyin', None
except Exception as e:
print(f"douyin请求或处理错误: {e}")
return 'douyin', None
def process_douyu(self):
try:
self.dyufdata = self.fetch(
f'{self.referers["douyu"]}/api/cate/list',
headers=self.headers[1]
).json()
return ('douyu', [{'key': 'cate', 'name': '分类',
'value': [{'n': i['cate1Name'], 'v': str(i['cate1Id'])}
for i in self.dyufdata['data']['cate1Info']]}])
except Exception as e:
print(f"douyu错误: {e}")
return 'douyu', None
def homeContent(self, filter):
result = {}
cateManual = {
"虎牙": "huya",
"哔哩": "bili",
"抖音": "douyin",
"斗鱼": "douyu",
"网易": "wangyi"
}
classes = []
filters = {
'huya': [{'key': 'cate', 'name': '分类',
'value': [{'n': '网游', 'v': '1'}, {'n': '单机', 'v': '2'},
{'n': '娱乐', 'v': '8'}, {'n': '手游', 'v': '3'}]}]
}
with ThreadPoolExecutor(max_workers=3) as executor:
futures = {
executor.submit(self.process_bili): 'bili',
executor.submit(self.process_douyin): 'douyin',
executor.submit(self.process_douyu): 'douyu'
}
for future in futures:
platform, filter_data = future.result()
if filter_data:
filters[platform] = filter_data
for k in cateManual:
classes.append({
'type_name': k,
'type_id': cateManual[k]
})
result['class'] = classes
result['filters'] = filters
return result
def homeVideoContent(self):
pass
def categoryContent(self, tid, pg, filter, extend):
vdata = []
result = {}
pagecount = 9999
result['page'] = pg
result['limit'] = 90
result['total'] = 999999
if tid == 'wangyi':
vdata, pagecount = self.wyccContent(tid, pg, filter, extend, vdata)
elif 'bili' in tid:
vdata, pagecount = self.biliContent(tid, pg, filter, extend, vdata)
elif 'huya' in tid:
vdata, pagecount = self.huyaContent(tid, pg, filter, extend, vdata)
elif 'douyin' in tid:
vdata, pagecount = self.douyinContent(tid, pg, filter, extend, vdata)
elif 'douyu' in tid:
vdata, pagecount = self.douyuContent(tid, pg, filter, extend, vdata)
result['list'] = vdata
result['pagecount'] = pagecount
return result
def wyccContent(self, tid, pg, filter, extend, vdata):
params = {
'format': 'json',
'start': (int(pg) - 1) * 20,
'size': '20',
}
response = self.fetch(f'{self.hosts[tid]}/api/category/live/', params=params, headers=self.headers[0]).json()
for i in response['lives']:
if i.get('cuteid'):
bvdata = self.buildvod(
vod_id=f"{tid}@@{i['cuteid']}",
vod_name=i.get('title'),
vod_pic=i.get('cover'),
vod_remarks=i.get('nickname'),
style={"type": "rect", "ratio": 1.33}
)
vdata.append(bvdata)
return vdata, 9999
def biliContent(self, tid, pg, filter, extend, vdata):
if extend.get('cate') and pg == '1' and 'click' not in tid:
for i in self.blfdata['data']:
if str(i['id']) == extend['cate']:
for j in i['list']:
v = self.buildvod(
vod_id=f"click_{tid}@@{i['id']}@@{j['id']}",
vod_name=j.get('name'),
vod_pic=j.get('pic'),
vod_tag=1,
style={"type": "oval", "ratio": 1}
)
vdata.append(v)
return vdata, 1
else:
path = f'/xlive/web-interface/v1/second/getListByArea?platform=web&sort=online&page_size=30&page={pg}'
if 'click' in tid:
ids = tid.split('_')[1].split('@@')
tid = ids[0]
path = f'/xlive/web-interface/v1/second/getList?platform=web&parent_area_id={ids[1]}&area_id={ids[-1]}&sort_type=&page={pg}'
data = self.fetch(f'{self.hosts[tid][0]}{path}', headers=self.gethr(0, tid)).json()
for i in data['data']['list']:
if i.get('roomid'):
data = self.buildvod(
f"{tid}@@{i['roomid']}",
i.get('title'),
i.get('cover'),
i.get('watched_show', {}).get('text_large'),
0,
i.get('uname'),
style={"type": "rect", "ratio": 1.33}
)
vdata.append(data)
return vdata, 9999
def huyaContent(self, tid, pg, filter, extend, vdata):
if extend.get('cate') and pg == '1' and 'click' not in tid:
id = extend.get('cate')
data = self.fetch(f'{self.referers[tid]}/liveconfig/game/bussLive?bussType={id}',
headers=self.headers[1]).json()
for i in data['data']:
v = self.buildvod(
vod_id=f"click_{tid}@@{int(i['gid'])}",
vod_name=i.get('gameFullName'),
vod_pic=f'https://huyaimg.msstatic.com/cdnimage/game/{int(i["gid"])}-MS.jpg',
vod_tag=1,
style={"type": "oval", "ratio": 1}
)
vdata.append(v)
return vdata, 1
else:
gid = ''
if 'click' in tid:
ids = tid.split('_')[1].split('@@')
tid = ids[0]
gid = f'&gameId={ids[1]}'
data = self.fetch(f'{self.hosts[tid][0]}/cache.php?m=LiveList&do=getLiveListByPage&tagAll=0{gid}&page={pg}',
headers=self.headers[1]).json()
for i in data['data']['datas']:
if i.get('profileRoom'):
v = self.buildvod(
f"{tid}@@{i['profileRoom']}",
i.get('introduction'),
i.get('screenshot'),
str(int(i.get('totalCount', '1')) / 10000) + '',
0,
i.get('nick'),
style={"type": "rect", "ratio": 1.33}
)
vdata.append(v)
return vdata, 9999
def douyinContent(self, tid, pg, filter, extend, vdata):
if extend.get('cate') and pg == '1' and 'click' not in tid:
ids = extend.get('cate').split('@@')
for i in self.dyifdata['categoryData']:
c = i['partition']
if c['id_str'] == ids[0] and c['title'] == ids[1]:
vlist = i['sub_partition'].copy()
vlist.insert(0, {'partition': c})
for j in vlist:
j = j['partition']
v = self.buildvod(
vod_id=f"click_{tid}@@{j['id_str']}@@{j['type']}",
vod_name=j.get('title'),
vod_pic='https://p3-pc-weboff.byteimg.com/tos-cn-i-9r5gewecjs/pwa_v3/512x512-1.png',
vod_tag=1,
style={"type": "oval", "ratio": 1}
)
vdata.append(v)
return vdata, 1
else:
path = f'/webcast/web/partition/detail/room/?aid=6383&app_name=douyin_web&live_id=1&device_platform=web&count=15&offset={(int(pg) - 1) * 15}&partition=720&partition_type=1'
if 'click' in tid:
ids = tid.split('_')[1].split('@@')
tid = ids[0]
path = f'/webcast/web/partition/detail/room/?aid=6383&app_name=douyin_web&live_id=1&device_platform=web&count=15&offset={(int(pg) - 1) * 15}&partition={ids[1]}&partition_type={ids[-1]}&req_from=2'
data = self.fetch(f'{self.hosts[tid]}{path}', headers=self.dyheaders).json()
for i in data['data']['data']:
v = self.buildvod(
vod_id=f"{tid}@@{i['web_rid']}",
vod_name=i['room'].get('title'),
vod_pic=i['room']['cover'].get('url_list')[0],
vod_year=i.get('user_count_str'),
vod_remarks=i['room']['owner'].get('nickname'),
style={"type": "rect", "ratio": 1.33}
)
vdata.append(v)
return vdata, 9999
def douyuContent(self, tid, pg, filter, extend, vdata):
if extend.get('cate') and pg == '1' and 'click' not in tid:
for i in self.dyufdata['data']['cate2Info']:
if str(i['cate1Id']) == extend['cate']:
v = self.buildvod(
vod_id=f"click_{tid}@@{i['cate2Id']}",
vod_name=i.get('cate2Name'),
vod_pic=i.get('icon'),
vod_remarks=i.get('count'),
vod_tag=1,
style={"type": "oval", "ratio": 1}
)
vdata.append(v)
return vdata, 1
else:
path = f'/japi/weblist/apinc/allpage/6/{pg}'
if 'click' in tid:
ids = tid.split('_')[1].split('@@')
tid = ids[0]
path = f'/gapi/rkc/directory/mixList/2_{ids[1]}/{pg}'
url = f'{self.hosts[tid]}{path}'
data = self.fetch(url, headers=self.headers[1]).json()
for i in data['data']['rl']:
v = self.buildvod(
vod_id=f"{tid}@@{i['rid']}",
vod_name=i.get('rn'),
vod_pic=i.get('rs16'),
vod_year=str(int(i.get('ol', 1)) / 10000) + '',
vod_remarks=i.get('nn'),
style={"type": "rect", "ratio": 1.33}
)
vdata.append(v)
return vdata, 9999
def detailContent(self, ids):
ids = ids[0].split('@@')
if ids[0] == 'wangyi':
vod = self.wyccDetail(ids)
elif ids[0] == 'bili':
vod = self.biliDetail(ids)
elif ids[0] == 'huya':
vod = self.huyaDetail(ids)
elif ids[0] == 'douyin':
vod = self.douyinDetail(ids)
elif ids[0] == 'douyu':
vod = self.douyuDetail(ids)
return {'list': [vod]}
def wyccDetail(self, ids):
try:
vdata = self.getpq(f'{self.hosts[ids[0]]}/{ids[1]}', self.headers[0])('script').eq(-1).text()
def get_quality_name(vbr):
if vbr <= 600:
return "标清"
elif vbr <= 1000:
return "高清"
elif vbr <= 2000:
return "超清"
else:
return "蓝光"
data = json.loads(vdata)['props']['pageProps']['roomInfoInitData']
name = data['live'].get('title', ids[0])
vod = self.buildvod(vod_name=data.get('keywords_suffix'), vod_remarks=data['live'].get('title'),
vod_content=data.get('description_suffix'))
resolution_data = data['live']['quickplay']['resolution']
all_streams = {}
sorted_qualities = sorted(resolution_data.items(),
key=lambda x: x[1]['vbr'],
reverse=True)
for quality, data in sorted_qualities:
vbr = data['vbr']
quality_name = get_quality_name(vbr)
for cdn_name, url in data['cdn'].items():
if cdn_name not in all_streams and type(url) == str and url.startswith('http'):
all_streams[cdn_name] = []
if isinstance(url, str) and url.startswith('http'):
all_streams[cdn_name].extend([quality_name, url])
plists = []
names = []
for i, (cdn_name, stream_list) in enumerate(all_streams.items(), 1):
names.append(f'线路{i}')
pstr = f"{name}${ids[0]}@@{self.e64(json.dumps(stream_list))}"
plists.append(pstr)
vod['vod_play_from'] = "$$$".join(names)
vod['vod_play_url'] = "$$$".join(plists)
return vod
except Exception as e:
return self.handle_exception(e)
def biliDetail(self, ids):
try:
vdata = self.fetch(
f'{self.hosts[ids[0]][0]}/xlive/web-room/v1/index/getInfoByRoom?room_id={ids[1]}&wts={int(time.time())}',
headers=self.gethr(0, ids[0])).json()
v = vdata['data']['room_info']
vod = self.buildvod(
vod_name=v.get('title'),
type_name=v.get('parent_area_name') + '/' + v.get('area_name'),
vod_remarks=v.get('tags'),
vod_play_from=v.get('title'),
)
data = self.fetch(
f'{self.hosts[ids[0]][0]}/xlive/web-room/v2/index/getRoomPlayInfo?room_id={ids[1]}&protocol=0%2C1&format=0%2C1%2C2&codec=0%2C1&platform=web',
headers=self.gethr(0, ids[0])).json()
vdnams = data['data']['playurl_info']['playurl']['g_qn_desc']
all_accept_qns = []
streams = data['data']['playurl_info']['playurl']['stream']
for stream in streams:
for format_item in stream['format']:
for codec in format_item['codec']:
if 'accept_qn' in codec:
all_accept_qns.append(codec['accept_qn'])
max_accept_qn = max(all_accept_qns, key=len) if all_accept_qns else []
quality_map = {
item['qn']: item['desc']
for item in vdnams
}
quality_names = [f"{quality_map.get(qn)}${ids[0]}@@{ids[1]}@@{qn}" for qn in max_accept_qn]
vod['vod_play_url'] = "#".join(quality_names)
return vod
except Exception as e:
return self.handle_exception(e)
def huyaDetail(self, ids):
try:
vdata = self.fetch(f'{self.hosts[ids[0]][1]}/cache.php?m=Live&do=profileRoom&roomid={ids[1]}',
headers=self.headers[0]).json()
v = vdata['data']['liveData']
vod = self.buildvod(
vod_name=v.get('introduction'),
type_name=v.get('gameFullName'),
vod_director=v.get('nick'),
vod_remarks=v.get('contentIntro'),
)
data = dict(reversed(list(vdata['data']['stream'].items())))
names = []
plist = []
for stream_type, stream_data in data.items():
if isinstance(stream_data, dict) and 'multiLine' in stream_data and 'rateArray' in stream_data:
names.append(f"线路{len(names) + 1}")
qualities = sorted(
stream_data['rateArray'],
key=lambda x: (x['iBitRate'], x['sDisplayName']),
reverse=True
)
cdn_urls = []
for cdn in stream_data['multiLine']:
quality_urls = []
for quality in qualities:
quality_name = quality['sDisplayName']
bit_rate = quality['iBitRate']
base_url = cdn['url']
if bit_rate > 0:
if '.m3u8' in base_url:
new_url = base_url.replace(
'ratio=2000',
f'ratio={bit_rate}'
)
else:
new_url = base_url.replace(
'imgplus.flv',
f'imgplus_{bit_rate}.flv'
)
else:
new_url = base_url
quality_urls.extend([quality_name, new_url])
encoded_urls = self.e64(json.dumps(quality_urls))
cdn_urls.append(f"{cdn['cdnType']}${ids[0]}@@{encoded_urls}")
if cdn_urls:
plist.append('#'.join(cdn_urls))
vod['vod_play_from'] = "$$$".join(names)
vod['vod_play_url'] = "$$$".join(plist)
return vod
except Exception as e:
return self.handle_exception(e)
def douyinDetail(self, ids):
url = f'{self.hosts[ids[0]]}/webcast/room/web/enter/?aid=6383&app_name=douyin_web&live_id=1&device_platform=web&enter_from=web_live&web_rid={ids[1]}&room_id_str=&enter_source=&Room-Enter-User-Login-Ab=0&is_need_double_stream=false&cookie_enabled=true&screen_width=1980&screen_height=1080&browser_language=zh-CN&browser_platform=Win32&browser_name=Edge&browser_version=125.0.0.0'
data = self.fetch(url, headers=self.dyheaders).json()
try:
vdata = data['data']['data'][0]
vod = self.buildvod(
vod_name=vdata['title'],
vod_remarks=vdata['user_count_str'],
)
resolution_data = vdata['stream_url']['live_core_sdk_data']['pull_data']['options']['qualities']
stream_json = vdata['stream_url']['live_core_sdk_data']['pull_data']['stream_data']
stream_json = json.loads(stream_json)
available_types = []
if any(sdk_key in stream_json['data'] and 'main' in stream_json['data'][sdk_key] for sdk_key in
stream_json['data']):
available_types.append('main')
if any(sdk_key in stream_json['data'] and 'backup' in stream_json['data'][sdk_key] for sdk_key in
stream_json['data']):
available_types.append('backup')
plist = []
for line_type in available_types:
format_arrays = {'flv': [], 'hls': [], 'lls': []}
qualities = sorted(resolution_data, key=lambda x: x['level'], reverse=True)
for quality in qualities:
sdk_key = quality['sdk_key']
if sdk_key in stream_json['data'] and line_type in stream_json['data'][sdk_key]:
stream_info = stream_json['data'][sdk_key][line_type]
if stream_info.get('flv'):
format_arrays['flv'].extend([quality['name'], stream_info['flv']])
if stream_info.get('hls'):
format_arrays['hls'].extend([quality['name'], stream_info['hls']])
if stream_info.get('lls'):
format_arrays['lls'].extend([quality['name'], stream_info['lls']])
format_urls = []
for format_name, url_array in format_arrays.items():
if url_array:
encoded_urls = self.e64(json.dumps(url_array))
format_urls.append(f"{format_name}${ids[0]}@@{encoded_urls}")
if format_urls:
plist.append('#'.join(format_urls))
names = ['线路1', '线路2'][:len(plist)]
vod['vod_play_from'] = "$$$".join(names)
vod['vod_play_url'] = "$$$".join(plist)
return vod
except Exception as e:
return self.handle_exception(e)
def douyuDetail(self, ids):
headers = self.gethr(0, zr=f'{self.hosts[ids[0]]}/{ids[1]}')
try:
data = self.fetch(f'{self.hosts[ids[0]]}/betard/{ids[1]}', headers=headers).json()
vname = data['room']['room_name']
vod = self.buildvod(
vod_name=vname,
vod_remarks=data['room'].get('second_lvl_name'),
vod_director=data['room'].get('nickname'),
)
vdata = self.fetch(f'{self.hosts[ids[0]]}/swf_api/homeH5Enc?rids={ids[1]}', headers=headers).json()
json_body = vdata['data']
json_body = {"html": self.douyu_text(json_body[f'room{ids[1]}']), "rid": ids[1]}
sign = self.post('http://alive.nsapps.cn/api/AllLive/DouyuSign', json=json_body, headers=self.headers[1]).json()['data']
body = f'{sign}&cdn=&rate=-1&ver=Douyu_223061205&iar=1&ive=1&hevc=0&fa=0'
body=self.params_to_json(body)
nubdata = self.post(f'{self.hosts[ids[0]]}/lapi/live/getH5Play/{ids[1]}', data=body, headers=headers).json()
plist = []
names = []
for i,x in enumerate(nubdata['data']['cdnsWithName']):
names.append(f'线路{i+1}')
d = {'sign': sign, 'cdn': x['cdn'], 'id': ids[1]}
plist.append(
f'{vname}${ids[0]}@@{self.e64(json.dumps(d))}@@{self.e64(json.dumps(nubdata["data"]["multirates"]))}')
vod['vod_play_from'] = "$$$".join(names)
vod['vod_play_url'] = "$$$".join(plist)
return vod
except Exception as e:
return self.handle_exception(e)
def douyu_text(self, text):
function_positions = [m.start() for m in re.finditer('function', text)]
total_functions = len(function_positions)
if total_functions % 2 == 0:
target_index = total_functions // 2 + 1
else:
target_index = (total_functions - 1) // 2 + 1
if total_functions >= target_index:
cut_position = function_positions[target_index - 1]
ctext = text[4:cut_position]
return re.sub(r'eval\(strc\)\([\w\d,]+\)', 'strc', ctext)
return text
def searchContent(self, key, quick, pg="1"):
pass
def playerContent(self, flag, id, vipFlags):
try:
ids = id.split('@@')
p = 1
if ids[0] in ['wangyi', 'douyin','huya']:
p, url = 0, json.loads(self.d64(ids[1]))
elif ids[0] == 'bili':
p, url = self.biliplay(ids)
elif ids[0] == 'huya':
p, url = 0, json.loads(self.d64(ids[1]))
elif ids[0] == 'douyu':
p, url = self.douyuplay(ids)
return {'parse': p, 'url': url, 'header': self.playheaders[ids[0]]}
except Exception as e:
return {'parse': 1, 'url': self.excepturl, 'header': self.headers[0]}
def biliplay(self, ids):
try:
data = self.fetch(
f'{self.hosts[ids[0]][0]}/xlive/web-room/v2/index/getRoomPlayInfo?room_id={ids[1]}&protocol=0,1&format=0,2&codec=0&platform=web&qn={ids[2]}',
headers=self.gethr(0, ids[0])).json()
urls = []
line_index = 1
for stream in data['data']['playurl_info']['playurl']['stream']:
for format_item in stream['format']:
for codec in format_item['codec']:
for url_info in codec['url_info']:
full_url = f"{url_info['host']}/{codec['base_url'].lstrip('/')}{url_info['extra']}"
urls.extend([f"线路{line_index}", full_url])
line_index += 1
return 0, urls
except Exception as e:
return 1, self.excepturl
def douyuplay(self, ids):
try:
sdata = json.loads(self.d64(ids[1]))
headers = self.gethr(0, zr=f'{self.hosts[ids[0]]}/{sdata["id"]}')
ldata = json.loads(self.d64(ids[2]))
result_obj = {}
with ThreadPoolExecutor(max_workers=len(ldata)) as executor:
futures = [
executor.submit(
self.douyufp,
sdata,
quality,
headers,
self.hosts[ids[0]],
result_obj
) for quality in ldata
]
for future in futures:
future.result()
result = []
for bit in sorted(result_obj.keys(), reverse=True):
result.extend(result_obj[bit])
if result:
return 0, result
return 1, self.excepturl
except Exception as e:
return 1, self.excepturl
def douyufp(self, sdata, quality, headers, host, result_obj):
try:
body = f'{sdata["sign"]}&cdn={sdata["cdn"]}&rate={quality["rate"]}'
body=self.params_to_json(body)
data = self.post(f'{host}/lapi/live/getH5Play/{sdata["id"]}',
data=body, headers=headers).json()
if data.get('data'):
play_url = data['data']['rtmp_url'] + '/' + data['data']['rtmp_live']
bit = quality.get('bit', 0)
if bit not in result_obj:
result_obj[bit] = []
result_obj[bit].extend([quality['name'], play_url])
except Exception as e:
print(f"Error fetching {quality['name']}: {str(e)}")
def localProxy(self, param):
pass
def e64(self, text):
try:
text_bytes = text.encode('utf-8')
encoded_bytes = b64encode(text_bytes)
return encoded_bytes.decode('utf-8')
except Exception as e:
print(f"Base64编码错误: {str(e)}")
return ""
def d64(self, encoded_text):
try:
encoded_bytes = encoded_text.encode('utf-8')
decoded_bytes = b64decode(encoded_bytes)
return decoded_bytes.decode('utf-8')
except Exception as e:
print(f"Base64解码错误: {str(e)}")
return ""
def josn_to_params(self, params, skip_empty=False):
query = []
for k, v in params.items():
if skip_empty and not v:
continue
query.append(f"{k}={v}")
return "&".join(query)
def params_to_json(self, query_string):
parsed_data = parse_qs(query_string)
result = {key: value[0] for key, value in parsed_data.items()}
return result
def buildvod(self, vod_id='', vod_name='', vod_pic='', vod_year='', vod_tag='', vod_remarks='', style='',
type_name='', vod_area='', vod_actor='', vod_director='',
vod_content='', vod_play_from='', vod_play_url=''):
vod = {
'vod_id': vod_id,
'vod_name': vod_name,
'vod_pic': vod_pic,
'vod_year': vod_year,
'vod_tag': 'folder' if vod_tag else '',
'vod_remarks': vod_remarks,
'style': style,
'type_name': type_name,
'vod_area': vod_area,
'vod_actor': vod_actor,
'vod_director': vod_director,
'vod_content': vod_content,
'vod_play_from': vod_play_from,
'vod_play_url': vod_play_url
}
vod = {key: value for key, value in vod.items() if value}
return vod
def getpq(self, url, headers=None, cookies=None):
data = self.fetch(url, headers=headers, cookies=cookies).text
try:
return pq(data)
except Exception as e:
print(f"解析页面错误: {str(e)}")
return pq(data.encode('utf-8'))
def gethr(self, index, rf='', zr=''):
headers = self.headers[index]
if zr:
headers['referer'] = zr
else:
headers['referer'] = f"{self.referers[rf]}/"
return headers
def handle_exception(self, e):
print(f"报错: {str(e)}")
return {'vod_play_from': '哎呀翻车啦', 'vod_play_url': f'翻车啦${self.excepturl}'}
+192
View File
@@ -0,0 +1,192 @@
#coding=utf-8
#!/usr/bin/python
import sys
sys.path.append('..')
from base.spider import Spider
import json
import time
import base64
import re
class Spider(Spider): # 元类 默认的元类 type
def getName(self):
return "央视片库"
def init(self,extend=""):
print("============{0}============".format(extend))
pass
def isVideoFormat(self,url):
pass
def manualVideoCheck(self):
pass
def homeContent(self,filter):
result = {}
cateManual = {
"动画片": "动画片",
#"特别节目": "特别节目"
}
classes = []
for k in cateManual:
classes.append({
'type_name':k,
'type_id':cateManual[k]
})
result['class'] = classes
if(filter):
result['filters'] = self.config['filter']
return result
def homeVideoContent(self):
result = {
'list':[]
}
return result
def categoryContent(self,tid,pg,filter,extend):
result = {}
month = ""
year = ""
if 'month' in extend.keys():
month = extend['month']
if 'year' in extend.keys():
year = extend['year']
if year == '':
month = ''
prefix = year + month
url="https://api.cntv.cn/list/getVideoAlbumList?channelid=CHAL1460955899450127&area=&sc=&fc=%E5%8A%A8%E7%94%BB%E7%89%87&letter=&p={0}&n=24&serviceId=tvcctv&topv=1&t=json"
if tid=="电视剧":
url="https://api.cntv.cn/list/getVideoAlbumList?channelid=CHAL1460955853485115&area=&sc=&fc=%E7%94%B5%E8%A7%86%E5%89%A7&year=&letter=&p={0}&n=24&serviceId=tvcctv&topv=1&t=json"
elif tid=="纪录片":
url="https://api.cntv.cn/list/getVideoAlbumList?channelid=CHAL1460955924871139&fc=%E7%BA%AA%E5%BD%95%E7%89%87&channel=&sc=&year=&letter=&p={0}&n=24&serviceId=tvcctv&topv=1&t=json"
elif tid=="4":
url="https://api.cntv.cn/list/getVideoAlbumList?channelid=CHAL1460955953877151&channel=&sc=&fc=%E7%89%B9%E5%88%AB%E8%8A%82%E7%9B%AE&bigday=&letter=&p={0}&n=24&serviceId=tvcctv&topv=1&t=json"
suffix = ""
jo = self.fetch(url.format(pg),headers=self.header).json()
vodList=jo["data"]["list"]
videos = []
for vod in vodList:
lastVideo =vod['url']
brief=vod['brief']
if len(brief) == 0:
brief = ' '
if len(lastVideo) == 0:
lastVideo = '_'
guid = tid+'###'+vod["title"]+'###'+lastVideo+'###'+vod['image']+'###'+brief
title = vod["title"]
img = vod['image']
videos.append({
"vod_id":guid,
"vod_name":title,
"vod_pic":img,
"vod_remarks":''
})
result['list'] = videos
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self,array):
aid = array[0].split('###')
if aid[2].find("http")<0:
return {}
tid = aid[0]
logo = aid[3]
lastVideo = aid[2]
title = aid[1]
date = aid[0]
if lastVideo == '_':
return {}
rsp = self.fetch(lastVideo)
htmlTxt=rsp.text
column_id = ""
videoList = []
patternTxt=r"'title':\s*'(.+?)',\n{0,1}\s*'img':\s*'(.+?)',\n{0,1}\s*'brief':\s*'(.+?)',\n{0,1}\s*'url':\s*'(.+?)'"
titleIndex=0
UrlIndex=3
if tid=="电视剧" or tid=="纪录片":
patternTxt=r"'title':\s*'(.+?)',\n{0,1}\s*'brief':\s*'(.+?)',\n{0,1}\s*'img':\s*'(.+?)',\n{0,1}\s*'url':\s*'(.+?)'"
titleIndex=0
UrlIndex=3
elif tid=="特别节目":
patternTxt=r'class="tp1"><a\s*href="(https://.+?)"\s*target="_blank"\s*title="(.+?)"></a></div>'
titleIndex=1
UrlIndex=0
#https://api.cntv.cn/NewVideo/getVideoListByAlbumIdNew?id=VIDA3YcIusJ9mh4c9mw5XHyx230113&serviceId=tvcctv//由于方式不同暂时不做
pattern = re.compile(patternTxt)
ListRe=pattern.findall(htmlTxt)
for value in ListRe:
videoList.append(value[titleIndex]+"$"+value[UrlIndex])
if len(videoList) == 0:
return {}
vod = {
"vod_id":array[0],
"vod_name":title,
"vod_pic":logo,
"type_name":tid,
"vod_year":date,
"vod_area":"",
"vod_remarks":date,
"vod_actor":"",
"vod_director":column_id,
"vod_content":aid[4]
}
vod['vod_play_from'] = 'CCTV'
vod['vod_play_url'] = "#".join(videoList)
result = {
'list':[
vod
]
}
return result
def searchContent(self,key,quick):
result = {
'list':[]
}
return result
def playerContent(self,flag,id,vipFlags):
result = {}
rsp = self.fetch(id)
htmlTxt=rsp.text
pattern = re.compile(r'var\sguid\s*=\s*"(.+?)";')
ListRe=pattern.findall(htmlTxt)
if ListRe==[]:
return result
url = "https://vdn.apps.cntv.cn/api/getHttpVideoInfo.do?pid={0}".format(ListRe[0])
jo = self.fetch(url,headers=self.header).json()
link = jo['hls_url'].strip()
rsp = self.fetch(link,headers=self.header)
content = rsp.text.strip()
arr = content.split('\n')
urlPrefix = self.regStr(link,'(http[s]?://[a-zA-z0-9.]+)/')
subUrl = arr[-1].split('/')
subUrl[3] = '1200'
subUrl[-1] = '1200.m3u8'
hdUrl = urlPrefix + '/'.join(subUrl)
url = urlPrefix + arr[-1]
hdRsp = self.fetch(hdUrl,headers=self.header)
if hdRsp.status_code == 200:
url = hdUrl
result["parse"] = 0
result["playUrl"] = ''
result["url"] = url
result["header"] = ''
return result
config = {
"player": {},
"filter": {"CCTV":[{"key":"cid","name":"频道","value":[{"n":"全部","v":""},{"n":"CCTV-1综合","v":"EPGC1386744804340101"},{"n":"CCTV-2财经","v":"EPGC1386744804340102"},{"n":"CCTV-3综艺","v":"EPGC1386744804340103"},{"n":"CCTV-4中文国际","v":"EPGC1386744804340104"},{"n":"CCTV-5体育","v":"EPGC1386744804340107"},{"n":"CCTV-6电影","v":"EPGC1386744804340108"},{"n":"CCTV-7国防军事","v":"EPGC1386744804340109"},{"n":"CCTV-8电视剧","v":"EPGC1386744804340110"},{"n":"CCTV-9纪录","v":"EPGC1386744804340112"},{"n":"CCTV-10科教","v":"EPGC1386744804340113"},{"n":"CCTV-11戏曲","v":"EPGC1386744804340114"},{"n":"CCTV-12社会与法","v":"EPGC1386744804340115"},{"n":"CCTV-13新闻","v":"EPGC1386744804340116"},{"n":"CCTV-14少儿","v":"EPGC1386744804340117"},{"n":"CCTV-15音乐","v":"EPGC1386744804340118"},{"n":"CCTV-16奥林匹克","v":"EPGC1634630207058998"},{"n":"CCTV-17农业农村","v":"EPGC1563932742616872"},{"n":"CCTV-5+体育赛事","v":"EPGC1468294755566101"}]},{"key":"fc","name":"分类","value":[{"n":"全部","v":""},{"n":"新闻","v":"新闻"},{"n":"体育","v":"体育"},{"n":"综艺","v":"综艺"},{"n":"健康","v":"健康"},{"n":"生活","v":"生活"},{"n":"科教","v":"科教"},{"n":"经济","v":"经济"},{"n":"农业","v":"农业"},{"n":"法治","v":"法治"},{"n":"军事","v":"军事"},{"n":"少儿","v":"少儿"},{"n":"动画","v":"动画"},{"n":"纪实","v":"纪实"},{"n":"戏曲","v":"戏曲"},{"n":"音乐","v":"音乐"},{"n":"影视","v":"影视"}]},{"key":"fl","name":"字母","value":[{"n":"全部","v":""},{"n":"A","v":"A"},{"n":"B","v":"B"},{"n":"C","v":"C"},{"n":"D","v":"D"},{"n":"E","v":"E"},{"n":"F","v":"F"},{"n":"G","v":"G"},{"n":"H","v":"H"},{"n":"I","v":"I"},{"n":"J","v":"J"},{"n":"K","v":"K"},{"n":"L","v":"L"},{"n":"M","v":"M"},{"n":"N","v":"N"},{"n":"O","v":"O"},{"n":"P","v":"P"},{"n":"Q","v":"Q"},{"n":"R","v":"R"},{"n":"S","v":"S"},{"n":"T","v":"T"},{"n":"U","v":"U"},{"n":"V","v":"V"},{"n":"W","v":"W"},{"n":"X","v":"X"},{"n":"Y","v":"Y"},{"n":"Z","v":"Z"}]},{"key":"year","name":"年份","value":[{"n":"全部","v":""},{"n":"2022","v":"2022"},{"n":"2021","v":"2021"},{"n":"2020","v":"2020"},{"n":"2019","v":"2019"},{"n":"2018","v":"2018"},{"n":"2017","v":"2017"},{"n":"2016","v":"2016"},{"n":"2015","v":"2015"},{"n":"2014","v":"2014"},{"n":"2013","v":"2013"},{"n":"2012","v":"2012"},{"n":"2011","v":"2011"},{"n":"2010","v":"2010"},{"n":"2009","v":"2009"},{"n":"2008","v":"2008"},{"n":"2007","v":"2007"},{"n":"2006","v":"2006"},{"n":"2005","v":"2005"},{"n":"2004","v":"2004"},{"n":"2003","v":"2003"},{"n":"2002","v":"2002"},{"n":"2001","v":"2001"},{"n":"2000","v":"2000"}]},{"key":"month","name":"月份","value":[{"n":"全部","v":""},{"n":"12","v":"12"},{"n":"11","v":"11"},{"n":"10","v":"10"},{"n":"09","v":"09"},{"n":"08","v":"08"},{"n":"07","v":"07"},{"n":"06","v":"06"},{"n":"05","v":"05"},{"n":"04","v":"04"},{"n":"03","v":"03"},{"n":"02","v":"02"},{"n":"01","v":"01"}]}]}
}
header = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36",
"Origin": "https://tv.cctv.com",
"Referer": "https://tv.cctv.com/"
}
def localProxy(self,param):
return [200, "video/MP2T", action, ""]
+213
View File
@@ -0,0 +1,213 @@
# coding=utf-8
# !/usr/bin/python
# 嗷呜
import sys
from base64 import b64encode, b64decode
from Crypto.Hash import MD5, SHA256
sys.path.append("..")
from base.spider import Spider
from Crypto.Cipher import AES
import json
import time
class Spider(Spider):
def getName(self):
return "lav"
def init(self, extend=""):
self.id = self.ms(self.t)[:16]
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def action(self, action):
pass
def destroy(self):
pass
host = "http://sir_new.tiansexyl.tv"
t = str(int(time.time() * 1000))
headers = {'User-Agent': 'okhttp-okgo/jeasonlzy', 'Connection': 'Keep-Alive',
'Content-Type': 'application/x-www-form-urlencoded'}
def homeContent(self, filter):
cateManual = {"演员": "actor", "分类": "avsearch", }
classes = []
for k in cateManual:
classes.append({'type_name': k, 'type_id': cateManual[k]})
j = {'code': 'homePage', 'mod': 'down', 'channel': 'self', 'via': 'agent', 'bundleId': 'com.tvlutv',
'app_type': 'rn', 'os_version': '12.0.5', 'version': '3.2.3', 'oauth_type': 'android_rn',
'oauth_id': self.id}
body = self.aes(j)
data = self.post(f'{self.host}/api.php?t={self.t}', data=body, headers=self.headers).json()['data']
data1 = self.aes(data, False)['data']
self.r = data1['r']
for i, d in enumerate(data1['avTag']):
# if i == 4:
# break
classes.append({'type_name': d['name'], 'type_id': d['tag']})
resutl = {}
resutl["class"] = classes
return resutl
def homeVideoContent(self):
pass
def categoryContent(self, tid, pg, filter, extend):
id = tid.split("@@")
result = {}
result["page"] = pg
result["pagecount"] = 9999
result["limit"] = 90
result["total"] = 999999
if id[0] == 'avsearch':
if pg == '1':
j = {'code': 'avsearch', 'mod': 'search', 'channel': 'self', 'via': 'agent', 'bundleId': 'com.tvlutv',
'app_type': 'rn', 'os_version': '12.0.5', 'version': '3.2.3', 'oauth_type': 'android_rn',
'oauth_id': self.id}
if len(id) > 1:
j = {'code': 'find', 'mod': 'tag', 'channel': 'self', 'via': 'agent', 'bundleId': 'com.tvlutv',
'app_type': 'rn', 'os_version': '12.0.5', 'version': '3.2.3', 'oauth_type': 'android_rn',
'oauth_id': self.id, 'type': 'av', 'dis': 'new', 'page': str(pg), 'tag': id[1]}
elif id[0] == 'actor':
j = {'mod': 'actor', 'channel': 'self', 'via': 'agent', 'bundleId': 'com.tvlutv', 'app_type': 'rn',
'os_version': '12.0.5', 'version': '3.2.3', 'oauth_type': 'android_rn', 'oauth_id': self.id,
'page': str(pg), 'filter': ''}
if len(id) > 1:
j = {'code': 'eq', 'mod': 'actor', 'channel': 'self', 'via': 'agent', 'bundleId': 'com.tvlutv',
'app_type': 'rn', 'os_version': '12.0.5', 'version': '3.2.3', 'oauth_type': 'android_rn',
'oauth_id': self.id, 'page': str(pg), 'id': id[1], 'actor': id[2]}
else:
j = {'code': 'search', 'mod': 'av', 'channel': 'self', 'via': 'agent', 'bundleId': 'com.tvlutv',
'app_type': 'rn', 'os_version': '12.0.5', 'version': '3.2.3', 'oauth_type': 'android_rn',
'oauth_id': self.id, 'page': str(pg), 'tag': id[0]}
body = self.aes(j)
data = self.post(f'{self.host}/api.php?t={self.t}', data=body, headers=self.headers).json()['data']
data1 = self.aes(data, False)['data']
videos = []
if tid == 'avsearch' and len(id) == 1:
for item in data1:
videos.append({"vod_id": id[0] + "@@" + str(item.get('tags')), 'vod_name': item.get('name'),
'vod_pic': self.imgs(item.get('ico')), 'vod_tag': 'folder',
'style': {"type": "rect", "ratio": 1.33}})
elif tid == 'actor' and len(id) == 1:
for item in data1:
videos.append({"vod_id": id[0] + "@@" + str(item.get('id')) + "@@" + item.get('name'),
'vod_name': item.get('name'), 'vod_pic': self.imgs(item.get('cover')),
'vod_tag': 'folder', 'style': {"type": "oval"}})
else:
for item in data1:
if item.get('_id'):
videos.append({"vod_id": str(item.get('id')), 'vod_name': item.get('title'),
'vod_pic': self.imgs(item.get('cover_thumb') or item.get('cover_full')),
'vod_remarks': item.get('good'), 'style': {"type": "rect", "ratio": 1.33}})
result["list"] = videos
return result
def detailContent(self, ids):
id = ids[0]
j = {'code': 'detail', 'mod': 'av', 'channel': 'self', 'via': 'agent', 'bundleId': 'com.tvlutv',
'app_type': 'rn', 'os_version': '12.0.5', 'version': '3.2.3', 'oauth_type': 'android_rn',
'oauth_id': self.id, 'id': id}
body = self.aes(j)
data = self.post(f'{self.host}/api.php?t={self.t}', data=body, headers=self.headers).json()['data']
data1 = self.aes(data, False)['line']
vod = {}
play = []
for itt in data1:
a = itt['line'].get('s720')
if a:
b = a.split('.')
b[0] = 'https://m3u8'
a = '.'.join(b)
play.append(itt['info']['tips'] + "$" + a)
break
vod["vod_play_from"] = 'LAV'
vod["vod_play_url"] = "#".join(play)
result = {"list": [vod]}
return result
def searchContent(self, key, quick, pg="1"):
pass
def playerContent(self, flag, id, vipFlags):
url = self.getProxyUrl() + "&url=" + b64encode(id.encode('utf-8')).decode('utf-8') + "&type=m3u8"
self.hh = {'User-Agent': 'dd', 'Connection': 'Keep-Alive', 'Referer': self.r}
result = {}
result["parse"] = 0
result["url"] = url
result["header"] = self.hh
return result
def localProxy(self, param):
url = param["url"]
if param.get('type') == "m3u8":
return self.vod(b64decode(url).decode('utf-8'))
else:
return self.img(url)
def vod(self, url):
data = self.fetch(url, headers=self.hh).text
key = bytes.fromhex("13d47399bda541b85e55830528d4e66f1791585b2d2216f23215c4c63ebace31")
iv = bytes.fromhex(data[:32])
data = data[32:]
cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
data_bytes = bytes.fromhex(data)
decrypted = cipher.decrypt(data_bytes)
encoded = decrypted.decode("utf-8").replace("\x08", "")
return [200, "application/vnd.apple.mpegur", encoded]
def imgs(self, url):
return self.getProxyUrl() + '&url=' + url
def img(self, url):
type = url.split('.')[-1]
data = self.fetch(url).text
key = bytes.fromhex("ba78f184208d775e1553550f2037f4af22cdcf1d263a65b4d5c74536f084a4b2")
iv = bytes.fromhex(data[:32])
data = data[32:]
cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
data_bytes = bytes.fromhex(data)
decrypted = cipher.decrypt(data_bytes)
return [200, f"image/{type}", decrypted]
def ms(self, data, m=False):
h = MD5.new()
if m:
h = SHA256.new()
h.update(data.encode('utf-8'))
return h.hexdigest()
def aes(self, data, operation=True):
key = bytes.fromhex("620f15cfdb5c79c34b3940537b21eda072e22f5d7151456dec3932d7a2b22c53")
t = str(int(time.time()))
ivt = self.ms(t)
if operation:
data = json.dumps(data, separators=(',', ':'))
iv = bytes.fromhex(ivt)
else:
iv = bytes.fromhex(data[:32])
data = data[32:]
cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
if operation:
data_bytes = data.encode('utf-8')
encrypted = cipher.encrypt(data_bytes)
ep = f'{ivt}{encrypted.hex()}'
edata = f"data={ep}&timestamp={t}0d27dfacef1338483561a46b246bf36d"
sign = self.ms(self.ms(edata, True))
edata = f"timestamp={t}&data={ep}&sign={sign}"
return edata
else:
data_bytes = bytes.fromhex(data)
decrypted = cipher.decrypt(data_bytes)
return json.loads(decrypted.decode('utf-8'))
+440
View File
@@ -0,0 +1,440 @@
# coding=utf-8
# !/usr/bin/python
"""
作者 丢丢喵推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from datetime import datetime
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import datetime
import binascii
import requests
import hashlib
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://api-store.qmplaylet.com"
xurl1 = "https://api-read.qmplaylet.com"
keys = "d3dGiJc651gSQ8w1"
data = {
"static_score": "0.8",
"uuid": "00000000-7fc7-08dc-0000-000000000000",
"device-id": "20250220125449b9b8cac84c2dd3d035c9052a2572f7dd0122edde3cc42a70",
"mac": "",
"sourceuid": "aa7de295aad621a6",
"refresh-type": "0",
"model": "22021211RC",
"wlb-imei": "",
"client-id": "aa7de295aad621a6",
"brand": "Redmi",
"oaid": "",
"oaid-no-cache": "",
"sys-ver": "12",
"trusted-id": "",
"phone-level": "H",
"imei": "",
"wlb-uid": "aa7de295aad621a6",
"session-id": str(int(time.time() * 1000)),
}
json_str = json.dumps(data, separators=(',', ':'))
encoded = base64.b64encode(json_str.encode()).decode()
char_map = {
'+': 'P', '/': 'X', '0': 'M', '1': 'U', '2': 'l', '3': 'E', '4': 'r',
'5': 'Y', '6': 'W', '7': 'b', '8': 'd', '9': 'J', 'A': '9', 'B': 's',
'C': 'a', 'D': 'I', 'E': '0', 'F': 'o', 'G': 'y', 'H': '_', 'I': 'H',
'J': 'G', 'K': 'i', 'L': 't', 'M': 'g', 'N': 'N', 'O': 'A', 'P': '8',
'Q': 'F', 'R': 'k', 'S': '3', 'T': 'h', 'U': 'f', 'V': 'R', 'W': 'q',
'X': 'C', 'Y': '4', 'Z': 'p', 'a': 'm', 'b': 'B', 'c': 'O', 'd': 'u',
'e': 'c', 'f': '6', 'g': 'K', 'h': 'x', 'i': '5', 'j': 'T', 'k': '-',
'l': '2', 'm': 'z', 'n': 'S', 'o': 'Z', 'p': '1', 'q': 'V', 'r': 'v',
's': 'j', 't': 'Q', 'u': '7', 'v': 'D', 'w': 'w', 'x': 'n', 'y': 'L',
'z': 'e'
}
qm_params = ''
for c in encoded:
qm_params += char_map.get(c, c)
params_str = (
"AUTHORIZATION=" +
"app-version=10001" +
"application-id=com.duoduo.read" +
"channel=unknown" +
"is-white=" +
"net-env=5" +
"platform=android" +
f"qm-params={qm_params}" +
f"reg={keys}"
)
signs = hashlib.md5(params_str.encode()).hexdigest()
headerx = {
'net-env': '5',
'reg': '',
'channel': 'unknown',
'is-white': '',
'platform': 'android',
'application-id': 'com.duoduo.read',
'authorization': '',
'app-version': '10001',
'user-agent': 'webviewversion/0',
'qm-params': qm_params,
'sign': signs
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
class Spider(Spider):
global xurl
global xurl1
global keys
global headerx
global headers
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {"class": []}
sign_string = f"operation=1playlet_privacy=1tag_id=0{keys}"
sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest()
url = f"{xurl}/api/v1/playlet/index?tag_id=0&playlet_privacy=1&operation=1&sign={sign}"
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
data = detail.json()
duoxuan = ['0', '1', '2', '3', '4']
for duo in duoxuan:
js = data['data']['tag_categories'][int(duo)]['tags']
for vod in js:
name = vod['tag_name']
if "推荐" in name:
continue
id = vod['tag_id']
result["class"].append({"type_id": id, "type_name": "集多🌠" + name})
return result
def homeVideoContent(self):
videos = []
sign_string = f"operation=1playlet_privacy=1tag_id=0{keys}"
sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest()
url = f"{xurl}/api/v1/playlet/index?tag_id=0&playlet_privacy=1&operation=1&sign={sign}"
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
data = detail.json()
data = data['data']['list']
for vod in data:
name = vod['title']
id = vod['playlet_id']
pic = vod['image_link']
remark = vod['hot_value']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
return result
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
if page == 1:
sign_string = f"operation=1playlet_privacy=1tag_id={cid}{keys}"
sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest()
url = f'{xurl}/api/v1/playlet/index?tag_id={cid}&playlet_privacy=1&operation=1&sign={sign}'
else:
sign_string = f"next_id={str(page)}operation=1playlet_privacy=1tag_id={cid}{keys}"
sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest()
url = f'{xurl}/api/v1/playlet/index?tag_id={cid}&next_id={str(page)}&playlet_privacy=1&operation=1&sign={sign}'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
data = detail.json()
data = data['data']['list']
for vod in data:
name = vod['title']
id = vod['playlet_id']
pic = vod['image_link']
remark = vod['hot_value']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = ids[0]
result = {}
videos = []
xianlu = ''
bofang = ''
sign_string = f"playlet_id={did}{keys}"
sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest()
urls = f'{xurl1}/player/api/v1/playlet/info?playlet_id={did}&sign={sign}'
detail = requests.get(url=urls, headers=headerx)
detail.encoding = "utf-8"
detail = detail.json()
url = 'http://rihou.cc:88/je.json'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
blurb = detail.get('data', {}).get('intro') or "未知"
content = '😸集多为您介绍剧情📢' + blurb
jisu = detail['data']['total_episode_num'] or "未知"
jisu = jisu + '全集'
leixing = detail['data']['tags'] or "未知"
remarks = leixing + " " + jisu
if name not in content:
bofang = Jumps
xianlu = '1'
else:
soup = detail['data']['play_list']
for sou in soup:
id = sou['video_url']
name = sou['sort']
bofang = bofang + name + '$' + id + '#'
bofang = bofang[:-1]
xianlu = '集多七猫专线'
videos.append({
"vod_id": did,
"vod_remarks": remarks,
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = id
result["header"] = headers
return result
def searchContentPage(self, key, quick, pg):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
sign_string = f"extend=page={str(page)}read_preference=0track_id=ec1280db127955061754851657967wd={key}{keys}"
sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest()
url = f'{xurl}/api/v1/playlet/search?extend=&page={str(page)}&wd={key}&read_preference=0&track_id=ec1280db127955061754851657967&sign={sign}'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
detail = detail.json()
data = detail['data']['list']
for vod in data:
name = vod['title']
name = re.sub(r'<[^>]+>', '', name)
name = ' '.join(name.split())
id = vod['id']
pic = vod['image_link']
remark = vod['total_num']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+263
View File
@@ -0,0 +1,263 @@
# coding=utf-8
# !/usr/bin/python
"""
内容均从互联网收集而来 仅供交流学习使用 严禁用于商业用途 请于24小时内删除
"""
from concurrent.futures import ThreadPoolExecutor
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from datetime import datetime
from bs4 import BeautifulSoup
from base64 import b64decode
import concurrent.futures
import urllib.request
import urllib.parse
import threading
import datetime
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl1 = "https://www.5544ww.com"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
detail = requests.get(url=xurl1, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
pattern = r"decodeURIComponent\('(.+?)'\)"
match = re.search(pattern, res)
if match:
extracted_string = match.group(1)
real_code = unquote(extracted_string)
domain_match = re.search(r'"(.*?)"', real_code)
if domain_match:
domain = domain_match.group(1)
xurl = f"https://www.{domain}"
headers = {
'accept': '*/*',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'cache-control': 'no-cache',
'content-type': 'application/json',
'pragma': 'no-cache',
'priority': 'u=1, i',
'referer': xurl,
'sec-ch-ua': '"Microsoft Edge";v="143", "Chromium";v="143", "Not A(Brand";v="24"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0',
}
session = requests.Session()
adapter = requests.adapters.HTTPAdapter(pool_connections=50, pool_maxsize=50, max_retries=1)
session.mount('https://', adapter)
session.mount('http://', adapter)
class Spider(Spider):
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def homeVideoContent(self):
pass
def searchContentPage(self, key, quick, pg):
pass
def decrypt_aes(self, data_b64, key_b64):
raw_data = base64.b64decode(data_b64)
key = base64.b64decode(key_b64)
iv = raw_data[:16]
ciphertext = raw_data[16:]
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted_data = unpad(cipher.decrypt(ciphertext), AES.block_size).decode('utf-8')
return decrypted_data
def homeContent(self, filter):
result = {"class": []}
data_bb = self.fetch_navigation_data()
self.process_navigation_items(data_bb, result)
return result
def fetch_navigation_data(self):
url = f"{xurl}/api/member/getnav?_v="
detail = requests.get(url=url, headers=headers)
detail.encoding = "utf-8"
data = detail.json()
data_b64 = data['data']['data']
key_b64 = data['data']['key']
data_bb = self.decrypt_aes(data_b64, key_b64)
return json.loads(data_bb)
def process_navigation_items(self, data_bb, result):
for vod in data_bb:
name = vod['name']
if self.should_skip_navigation_item(name):
continue
id = self.build_navigation_id(vod)
result["class"].append({"type_id": id, "type_name": name})
def should_skip_navigation_item(self, name):
skip_names = ["首页", "美图", "小说"]
return name in skip_names
def build_navigation_id(self, vod):
return f"{vod['child'][0]['id']}@{vod['child'][0]['fid']}"
def categoryContent(self, cid, pg, filter, ext):
page = self.parse_category_page(pg)
params = self.build_category_params(cid, page)
data_bb = self.fetch_category_data(params)
videos = self.process_category_videos(data_bb)
return self.build_category_result(videos, pg)
def parse_category_page(self, pg):
return int(pg) if pg else 1
def build_category_params(self, cid, page):
fenge = cid.split("@")
return {'cid': fenge[0], 'fcid': fenge[1], 'page_no': page, 'page_size': 42, 'tag': 'video', 'sort': 'new',
'_v': ''}
def fetch_category_data(self, params):
url = f"{xurl}/api/video/index"
detail = session.get(url, params=params, headers=headers, timeout=5)
detail.encoding = "utf-8"
data = detail.json()
data_b64 = data['data']['data']
key_b64 = data['data']['key']
data_bb = self.decrypt_aes(data_b64, key_b64)
return json.loads(data_bb)
def process_category_videos(self, data_bb):
with ThreadPoolExecutor(max_workers=32) as executor:
results = executor.map(self.process_single_vod, data_bb['lists'])
return [v for v in results if v]
def build_category_result(self, videos, pg):
return {'list': videos, 'page': pg, 'pagecount': 9999, 'limit': 90, 'total': 999999}
def process_single_vod(self, vod):
name = vod.get('title', '')
id = vod.get('id', '')
remark = vod.get('times', '暂无备注')
pic = self.extract_vod_pic(vod)
return {"vod_id": id, "vod_name": name, "vod_pic": pic, "vod_remarks": remark}
def extract_vod_pic(self, vod):
cover_value = vod.get('cover')
if not isinstance(cover_value, list) or not cover_value:
return ""
try:
pics_path = cover_value[0]
url_pic = f"https://ggfm.gszy12348.com/{pics_path}"
detail = session.get(url=url_pic, headers=headers, timeout=3)
if detail.status_code == 200:
detail.encoding = "utf-8"
pic_text = detail.text
if "base64" in pic_text[:50]:
pic_text = self.clean_pic_text(pic_text)
return pic_text
except Exception:
pass
return ""
def clean_pic_text(self, pic_text):
pic_text = pic_text.replace('\ufeff', '').strip()
pic_text = pic_text.replace("\\", "/")
pic_text = pic_text.replace("\r\n", "").replace("\n", "").replace("%0D%0A", "")
return pic_text
def detailContent(self, ids):
did = ids[0]
result = {}
videos = []
data_bb = self.fetch_video_detail_data(did)
content = self.extract_video_content(data_bb)
bofang = self.extract_play_url(data_bb)
videos.append({"vod_id": did, "vod_content": content, "vod_play_from": "七猫专线", "vod_play_url": bofang})
result['list'] = videos
return result
def fetch_video_detail_data(self, did):
params = {'id': did, '_v': ''}
url = f"{xurl}/api/videos/videodetail"
detail = requests.get(url=url, params=params, headers=headers)
detail.encoding = "utf-8"
data = detail.json()
data_b64 = data['data']['data']
key_b64 = data['data']['key']
data_bb = self.decrypt_aes(data_b64, key_b64)
return json.loads(data_bb)
def extract_video_content(self, data_bb):
update_time = data_bb.get('create_time', '暂无备注')
return '为您介绍剧情📢上架时间' + update_time
def extract_play_url(self, data_bb):
h264_url = data_bb['content'][0]['h264Url']
return f"https://h3.xinghun1.com/data/{h264_url}"
def playerContent(self, flag, id, vipFlags):
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = id
result["header"] = headerx
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+226
View File
@@ -0,0 +1,226 @@
import requests
from bs4 import BeautifulSoup
import re
import json
from urllib.parse import urljoin
from base.spider import Spider
import sys
sys.path.append('..')
xurl = "https://sxyqtx.cn"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Referer': xurl,
}
class Spider(Spider):
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def homeContent(self, filter):
return {"class": [
{"type_id": "6","type_name": "动作电影"},{"type_id": "7","type_name": "喜剧电影"},
{"type_id": "8","type_name": "爱情电影"},{"type_id": "9","type_name": "科幻电影"},
{"type_id": "10","type_name": "恐怖电影"},{"type_id": "11","type_name": "剧情电影"},
{"type_id": "12","type_name": "战争电影"},{"type_id": "24","type_name": "纪录电影"},
{"type_id": "44","type_name": "香港电影"},{"type_id": "45","type_name": "动漫电影"},
{"type_id": "13","type_name": "国产剧"},{"type_id": "14","type_name": "香港剧"},
{"type_id": "15","type_name": "台湾剧"},{"type_id": "16","type_name": "日本剧"},
{"type_id": "20","type_name": "泰国剧"},{"type_id": "21","type_name": "韩国剧"},
{"type_id": "22","type_name": "欧美剧"},{"type_id": "23","type_name": "海外剧"},
{"type_id": "25","type_name": "大陆综艺"},{"type_id": "26","type_name": "港台综艺"},
{"type_id": "27","type_name": "日韩综艺"},{"type_id": "28","type_name": "欧美综艺"},
{"type_id": "29","type_name": "国产动漫"},{"type_id": "30","type_name": "日韩动漫"},
{"type_id": "31","type_name": "港台动漫"},{"type_id": "32","type_name": "欧美动漫"},
{"type_id": "33","type_name": "有声动漫"},{"type_id": "34","type_name": "海外动漫"},
{"type_id": "35","type_name": "动画片"},{"type_id": "37","type_name": "女频恋爱"},
{"type_id": "38","type_name": "反转爽剧"},{"type_id": "39","type_name": "年代穿越"},
{"type_id": "40","type_name": "脑洞悬疑"},{"type_id": "41","type_name": "现代都市"},
{"type_id": "42","type_name": "古装仙侠"},{"type_id": "43","type_name": "热血剧情"}
]}
def _parse_video_items(self, soup):
videos = []
for li in soup.select('li.col-xs-4.col-md-3.col-lg-2'):
a = li.select_one('.pic a')
if not a:
continue
img = li.select_one('.img-wrapper')
pic = (img.get('data-original') or img.get('src') or '').strip()
if pic and not pic.startswith('http'):
pic = urljoin(xurl, pic)
remark = li.select_one('.item-status')
videos.append({
"vod_id": a.get('href'),
"vod_name": a.get('title'),
"vod_pic": pic,
"vod_remarks": remark.text.strip() if remark else ''
})
return videos
def homeVideoContent(self):
resp = requests.get(xurl, headers=headers, timeout=10)
soup = BeautifulSoup(resp.text, 'lxml')
return {'list': self._parse_video_items(soup)}
def categoryContent(self, cid, pg, filter, ext):
page = int(pg) if pg else 1
url = f'{xurl}/vodtype/{cid}.html' if page == 1 else f'{xurl}/vodtype/{cid}-{page}.html'
resp = requests.get(url, headers=headers, timeout=10)
soup = BeautifulSoup(resp.text, 'lxml')
return {
'list': self._parse_video_items(soup),
'page': pg,
'pagecount': 999,
'limit': 90,
'total': 99
}
def detailContent(self, ids):
did = ids[0]
if 'http' not in did:
did = xurl + did
resp = requests.get(url=did, headers=headers, timeout=10)
soup = BeautifulSoup(resp.text, "lxml")
vod = {}
vod["vod_id"] = did.split('/')[-1].replace('.html', '')
name_tag = soup.select_one('.info h3 a')
vod["vod_name"] = name_tag.get_text(strip=True) if name_tag else ''
img = soup.select_one('.pic img')
if img:
pic = img.get('data-original') or img.get('src') or ''
if pic and not pic.startswith('http'):
pic = urljoin(xurl, pic)
vod["vod_pic"] = pic
else:
vod["vod_pic"] = ''
status_tag = soup.select_one('.info p span:-soup-contains("状态")')
vod["vod_remarks"] = status_tag.get_text(strip=True).replace('状态:', '') if status_tag else ''
intro = soup.select_one('.more-box p') or soup.select_one('.info .text-row')
vod["vod_content"] = intro.get_text(strip=True).replace('\u3000', '') if intro else ''
category_tag = soup.select_one('.info p span:-soup-contains("分类")')
vod["type_name"] = category_tag.get_text(strip=True).replace('分类:', '') if category_tag else ''
area_tag = soup.select_one('.info p span:-soup-contains("地区")')
vod["vod_area"] = area_tag.get_text(strip=True).replace('地区:', '') if area_tag else ''
year_tag = soup.select_one('.info p span:-soup-contains("年份")')
vod["vod_year"] = year_tag.get_text(strip=True).replace('年份:', '') if year_tag else ''
director_tag = soup.select_one('.info p span:-soup-contains("导演")')
vod["vod_director"] = director_tag.get_text(strip=True).replace('导演:', '').replace('/', ' ') if director_tag else ''
actor_span = soup.select_one('.info p span:-soup-contains("主演")')
vod["vod_actor"] = ' '.join([a.get_text(strip=True) for a in actor_span.select('a')]) if actor_span else ''
tabs = soup.select('.playlist-tab .swiper-slide')
containers = soup.select('.ewave-playlist-content')
play_from = []
play_url = []
seen = set()
for i, tab in enumerate(tabs):
if i >= len(containers):
break
line_name = tab.get_text(strip=True)
line_name = re.sub(r'\s*\d+$', '', line_name).strip()
if not line_name or line_name in seen:
continue
seen.add(line_name)
container = containers[i]
eps = []
for a in container.select('a'):
href = a.get('href')
if href:
title = a.get_text(strip=True)
if not href.startswith('http'):
href = urljoin(xurl, href)
eps.append(f"{title}${href}")
if eps:
play_from.append(line_name)
play_url.append('#'.join(eps))
vod["vod_play_from"] = '$$$'.join(play_from)
vod["vod_play_url"] = '$$$'.join(play_url)
return {'list': [vod]}
def playerContent(self, flag, id, vipFlags):
try:
play_url = id if id.startswith('http') else xurl + id
resp = requests.get(play_url, headers=headers, timeout=10)
html = resp.text
pattern = r'var\s+player_\w+\s*=\s*(\{[\s\S]+?\});'
match = re.search(pattern, html)
video_url = ''
if match:
obj_str = match.group(1)
obj_str = re.sub(r'(\w+):', r'"\1":', obj_str)
try:
config = json.loads(obj_str)
video_url = config.get('url') or config.get('url_next') or ''
except json.JSONDecodeError:
pass
if not video_url:
url_match = re.search(r'"url":"([^"]+)"', html)
if url_match:
video_url = url_match.group(1)
if video_url and re.search(r'm3u8|mp4|mkv', video_url, re.I):
parse = 0
if not video_url.startswith('http'):
video_url = urljoin(xurl, video_url)
else:
parse = 1
video_url = play_url
return {"parse": parse, "playUrl": "", "url": video_url, "header": headers}
except Exception as e:
print(f"playerContent error: {e}")
return {"parse": 1, "playUrl": "", "url": xurl + id, "header": headers}
def searchContentPage(self, key, quick, page):
page = page or '1'
url = f'{xurl}/vodsearch/-------------.html?wd={key}'
if page != '1':
url += f'&page={page}'
resp = requests.get(url, headers=headers, timeout=10)
soup = BeautifulSoup(resp.text, 'lxml')
return {
'list': self._parse_video_items(soup),
'page': page,
'pagecount': 60,
'limit': 30,
'total': 999999
}
def searchContent(self, key, quick, page='1'):
return self.searchContentPage(key, quick, page)
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
if params['type'] == "media":
return self.proxyMedia(params)
if params['type'] == "ts":
return self.proxyTs(params)
return None
+361
View File
@@ -0,0 +1,361 @@
# coding=utf-8
# !/usr/bin/python
"""
作者 丢丢喵 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from datetime import datetime
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import datetime
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://www.duanju55.com"
headerx = {
'User-Agent': 'Mozilla/5.0 (Linux; U; Android 8.0.0; zh-cn; Mi Note 2 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.1.1'
}
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {"class": []}
detail = requests.get(url=xurl, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="home_browseBox")
for soup in soups:
vods = soup.find_all('a')
for vod in vods:
name = vod.text.strip()
id = vod['href']
result["class"].append({"type_id": id, "type_name": "集多🌠" + name})
return result
def homeVideoContent(self):
videos = []
detail = requests.get(url=xurl, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="FeaturedList_featuredBox")
for soup in soups:
vods = soup.find_all('div', class_="FeaturedList_featuredItem")
for vod in vods:
name = vod.find('img')['alt']
ids = vod.find('a', class_="FeaturedList_bookName")
id = ids['href']
pic = vod.find('img')['src']
if 'http' not in pic:
pic = xurl + pic
remarks = vod.find('a', class_="FeaturedList_lastChapter")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
return result
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
fenge = cid.split(".html")
url = f'{xurl}{fenge[0]}/page/{str(page)}.html'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="BrowseList_listBox")
for soup in soups:
vods = soup.find_all('div', class_="BrowseList_listItem")
for vod in vods:
names = vod.find('a', class_="BrowseList_bookName")
name = names.text.strip()
id = names['href']
pic = vod.find('img')['src']
if 'http' not in pic:
pic = xurl + pic
remarks = vod.find('a', class_="BrowseList_lastChapter")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = ids[0]
result = {}
videos = []
xianlu = ''
bofang = ''
if 'http' not in did:
did = xurl + did
res = requests.get(url=did, headers=headerx)
res.encoding = "utf-8"
res = res.text
doc = BeautifulSoup(res, "lxml")
url = 'http://rihou.cc:88/je.json'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
content = '集多为您介绍剧情📢' + self.extract_middle_text(res, 'introduction_introEllipsis" style="">', '<', 0)
content = content.replace(' ', '').replace('\n', '')
names = doc.find('div', class_="dramaDetail_tagsBox")
remarks = names.text.strip()
remarks = remarks.replace('\xa0', ' ')
if name not in content:
bofang = Jumps
xianlu = '专线'
else:
soups = doc.find_all('div', class_="adm-swiper-item CatalogList_content")
for item in soups:
vods = item.find_all('a')
for sou in vods:
id = sou['href']
if 'http' not in id:
id = xurl + id
name = sou.text.strip()
bofang = bofang + name + '$' + id + '#'
bofang = bofang[:-1]
xianlu = '短剧专线'
videos.append({
"vod_id": did,
"vod_remarks": remarks,
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
result = {}
result["parse"] = 1
result["playUrl"] = ''
result["url"] = id
result["header"] = headerx
return result
def searchContentPage(self, key, quick, pg):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
url = f'{xurl}/index.php/vod/search/page/{str(page)}/wd/{key}.html'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="MTagBookList_tagBookItem")
for vod in soups:
names = vod.find('a', class_="MTagBookList_bookName")
name = names.text.strip()
id = names['href']
pic = vod.find('img')['src']
if 'http' not in pic:
pic = xurl + pic
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic
}
videos.append(video)
result['list'] = videos
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+414
View File
@@ -0,0 +1,414 @@
# coding=utf-8
# !/usr/bin/python
"""
作者 丢丢喵 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from datetime import datetime
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import datetime
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://nnyy.la"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def split_id_by_at(self, id):
return id.split("@")
def split_first_part_by_comma(self, first_part):
return first_part.split(",")
def parse_url_dictionary(self, response_text):
pattern = r'urlDictionary\[(\d+)\]\[(\d+)\]\s*=\s*"([^"]+)"'
matches = re.findall(pattern, response_text)
url_dictionary = {}
for key1, key2, value in matches:
key1_int = int(key1)
key2_int = int(key2)
if key1_int not in url_dictionary:
url_dictionary[key1_int] = {}
url_dictionary[key1_int][key2_int] = value
return url_dictionary
def get_url_from_dictionary(self, url_dictionary, indices):
primary_index = int(indices[0].strip())
secondary_index = int(indices[1].strip())
return url_dictionary[primary_index][secondary_index]
def decrypt_url(self, encrypted_hex, key="i_love_you"):
encrypted_bytes = bytes.fromhex(encrypted_hex)
s = list(range(256))
j = 0
key_bytes = key.encode('utf-8')
key_length = len(key_bytes)
for i in range(256):
j = (j + s[i] + key_bytes[i % key_length]) % 256
s[i], s[j] = s[j], s[i]
i = 0
j = 0
decrypted_bytes = bytearray(len(encrypted_bytes))
for k in range(len(encrypted_bytes)):
i = (i + 1) % 256
j = (j + s[i]) % 256
s[i], s[j] = s[j], s[i]
keystream_byte = s[(s[i] + s[j]) % 256]
decrypted_bytes[k] = encrypted_bytes[k] ^ keystream_byte
return decrypted_bytes.decode('utf-8')
def _extract_play_sources(self, soups):
xianlu = ''
for item in soups:
vods = item.find_all('dt')
for sou in vods:
name = sou.text.strip()
xianlu = xianlu + name + '$$$'
xianlu = xianlu[:-3]
return xianlu
def _extract_play_urls(self, soups1, did):
bofang = ''
for item in soups1:
vods1 = item.find_all('a')
for sou1 in vods1:
id1 = sou1['onclick']
numbers = re.findall(r'\((.*?)\)', id1)[0] if re.findall(r'\((.*?)\)', id1) else ""
id = f"{numbers}@{did}"
name = sou1.text.strip()
bofang = bofang + name + '$' + id + '#'
bofang = bofang[:-1] + '$$$'
bofang = bofang[:-3]
return bofang
def _extract_content(self, res):
content_raw = self.extract_middle_text(res, '剧情简介:<span>', '<', 0).replace('\n', '')
return '😸丢丢为您介绍剧情📢' + (content_raw if content_raw is not None else "暂无剧情介绍")
def _extract_director(self, res):
director_raw = self.extract_middle_text(res, '导演:', '</div>', 1, 'href=".*?">(.*?)</a>')
return director_raw if director_raw is not None and director_raw.strip() != "" else "暂无导演介绍"
def _extract_actor(self, res):
actor_raw = self.extract_middle_text(res, '主演:', '</div>', 1, 'href=".*?">(.*?)</a>')
return actor_raw if actor_raw is not None and actor_raw.strip() != "" else "暂无主演介绍"
def _extract_remarks(self, res):
remarks_raw = self.extract_middle_text(res, '类型:', '</div>', 1, 'href=".*?">(.*?)</a>')
return remarks_raw if remarks_raw is not None and remarks_raw.strip() != "" else "暂无类型介绍"
def _extract_area(self, res):
area_raw = self.extract_middle_text(res, '制片国家/地区:', '</div>', 1, 'href=".*?">(.*?)</a>')
return area_raw if area_raw is not None and area_raw.strip() != "" else "暂无国家/地区介绍"
def _extract_year(self, doc):
years = doc.find('h1', class_="product-title")
year = years.text.strip() if years else '暂无年份介绍'
return year.replace('\n', '打分:')
def _extract_video_items(self, vods):
videos = []
for vod in vods:
name = vod.find('img')['alt']
ids = vod.find('a', class_="thumbnail")
id = ids['href']
pic = vod.find('img')['data-src']
remarks = vod.find('div', class_="note")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remark
}
videos.append(video)
return videos
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {"class": []}
detail = requests.get(url=xurl, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="nav")
for soup in soups:
vods = soup.find_all('a')
for vod in vods:
name = vod.text.strip()
skip_names = ["首页"]
if name in skip_names:
continue
id = vod['href'].replace('/', '')
result["class"].append({"type_id": id, "type_name": name})
result["class"].append({"type_id": "duanju", "type_name": "短剧"})
return result
def homeVideoContent(self):
videos = []
detail = requests.get(url=xurl, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find('div', class_="bd")
vods = soups.find_all('li')
videos = self._extract_video_items(vods)
result = {'list': videos}
return result
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
url = f'{xurl}/{cid}/?page={str(page)}'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="lists-content")
for soup in soups:
vods = soup.find_all('li')
videos = self._extract_video_items(vods)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = ids[0]
result = {}
videos = []
if 'http' not in did:
did = xurl + did
detail = requests.get(url=did, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
content = self._extract_content(res)
director = self._extract_director(res)
actor = self._extract_actor(res)
remarks = self._extract_remarks(res)
area = self._extract_area(res)
year = self._extract_year(doc)
soups = doc.find_all('div', class_="playlists")
xianlu = self._extract_play_sources(soups)
soups1 = doc.find_all('ul', class_="sort-list")
bofang = self._extract_play_urls(soups1, did)
videos.append({
"vod_id": did,
"vod_director": director,
"vod_actor": actor,
"vod_remarks": remarks,
"vod_year": year,
"vod_area": area,
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
fenge = self.split_id_by_at(id)
fenge1 = self.split_first_part_by_comma(fenge[0])
detail = requests.get(url=fenge[1], headers=headerx)
detail.encoding = "utf-8"
res = detail.text
url_dictionary = self.parse_url_dictionary(res)
result = self.get_url_from_dictionary(url_dictionary, fenge1)
url = self.decrypt_url(result)
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
return result
def searchContentPage(self, key, quick, pg):
result = {}
videos = []
url = f'{xurl}/search?wd={key}'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="lists-content")
for item in soups:
vods = item.find_all('li')
videos = self._extract_video_items(vods)
result['list'] = videos
result['page'] = pg
result['pagecount'] = 1
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+230
View File
@@ -0,0 +1,230 @@
import requests
from bs4 import BeautifulSoup
import re
import json
from urllib.parse import urljoin, quote
import sys
sys.path.append('..')
from base.spider import Spider
xurl = "https://tkys.one"
headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 13; M2102J2SC Build/TKQ1.221114.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/144.0.7559.31 Mobile Safari/537.36',
'Referer': xurl,
}
class Spider(Spider):
def getName(self):
return "天空影视"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def homeContent(self, filter):
return {
"class": [
{"type_id": "1", "type_name": "电影"},
{"type_id": "2", "type_name": "剧集"},
{"type_id": "3", "type_name": "综艺"},
{"type_id": "5", "type_name": "动漫"},
{"type_id": "4", "type_name": "短剧"},
],
"filters": {}
}
def _parse_video_items(self, soup):
videos = []
for li in soup.select('div.module'):
a = li.select_one('a.module-item')
if not a:
continue
href = a.get('href')
name = a.get('title')
pic = li.select_one('img.lazy.lazyload')
pic = pic.get('data-original', '') if pic else ''
if pic and not pic.startswith('http'):
pic = urljoin(xurl, pic)
remark = li.select_one('div.module-item-note')
remark = remark.get_text(strip=True) if remark else ''
if href and name:
videos.append({
"vod_id": urljoin(xurl, href),
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remark
})
return videos
def homeVideoContent(self):
resp = requests.get(xurl, headers=headers, timeout=10)
soup = BeautifulSoup(resp.text, 'lxml')
return {'list': self._parse_video_items(soup)}
def categoryContent(self, cid, pg, filter, ext):
page = int(pg) if pg else 1
if page == 1:
url = f"{xurl}/vodshow/{cid}--------1---.html"
else:
url = f"{xurl}/vodshow/{cid}--------{page}---.html"
resp = requests.get(url, headers=headers, timeout=10)
return {
'list': self._parse_video_items(BeautifulSoup(resp.text, 'lxml')),
'page': page,
'pagecount': page + 1,
'limit': 90,
'total': 9999
}
def detailContent(self, ids):
did = ids[0]
if not did.startswith('http'):
did = urljoin(xurl, did)
resp = requests.get(did, headers=headers, timeout=10)
soup = BeautifulSoup(resp.text, 'lxml')
info = {'vod_id': did}
thumb = soup.select_one('.lazy.lazyload')
if thumb:
pic = thumb.get('data-original') or thumb.get('src', '')
if pic and pic.startswith('//'):
pic = 'https:' + pic
elif pic and not pic.startswith('http'):
pic = urljoin(xurl, pic)
info['vod_pic'] = pic
detail_div = soup.select_one('.module-info-heading')
if detail_div:
title_h1 = detail_div.select_one('h1')
if title_h1:
raw_title = title_h1.get_text(strip=True).replace('\n', '')
info['vod_name'] = raw_title
for p in detail_div.select('p'):
text = p.get_text(strip=True)
if '演员:' in text:
info['vod_actor'] = text.split('演员:')[-1].strip()
if '类型:' in text:
info['type_name'] = text.split('类型:')[-1].strip()
if '导演:' in text:
info['vod_director'] = text.split('导演:')[-1].strip()
if '状态:' in text:
info['vod_remarks'] = text.split('状态:')[-1].strip()
if '年份:' in text:
info['vod_year'] = text.split('年份:')[-1].strip()
if '地区:' in text:
info['vod_area'] = text.split('地区:')[-1].strip()
content_div = soup.select_one('.module-info-tag')
if content_div:
p = content_div.find('p')
if p:
text = p.get_text(strip=True)
info['vod_content'] = text.strip()
else:
info['vod_content'] = content_div.get_text(strip=True)
else:
info['vod_content'] = ''
tabs = soup.select('.module-tab-item')
playlists = soup.select('.module-play-list-content')
play_from = []
play_url = []
seen = set()
for i, tab in enumerate(tabs):
if i >= len(playlists):
break
name = tab.get_text(strip=True)
name = re.sub(r'\s*\d+$', '', name).strip()
if name in ['猜您喜欢', '同类型', '同主演', ''] or name in seen:
continue
seen.add(name)
eps = []
for a in playlists[i].select('a'):
href = a.get('href')
ep_title = a.get_text(strip=True)
if href and '1080P' not in ep_title:
if not href.startswith('http'):
href = urljoin(xurl, href)
eps.append(f"{ep_title}${href}")
if eps:
play_from.append(name)
play_url.append('#'.join(eps))
info["vod_play_from"] = '$$$'.join(play_from)
info["vod_play_url"] = '$$$'.join(play_url)
return {'list': [info]}
def searchContent(self, key, quick, page='1'):
page = int(page) if page else 1
url = f"{xurl}/vodsearch/{key}----------{page}---.html"
resp = requests.get(url, headers=headers, timeout=10)
soup = BeautifulSoup(resp.text, 'lxml')
return {
'list': self._parse_video_items(soup),
'page': page,
'pagecount': page + 1,
'limit': 90,
'total': 9999
}
def playerContent(self, flag, id, vipFlags):
try:
play_url = id if id.startswith('http') else urljoin(xurl, id)
resp = requests.get(play_url, headers=headers, timeout=10)
html = resp.text
video_url = None
iframe_pattern = r'<iframe[^>]+src=["\']([^"\']+)["\']'
matches = re.findall(iframe_pattern, html)
for match in matches:
if match.startswith('http') and ('.m3u8' in match or '.mp4' in match):
video_url = match
break
if not video_url:
video_pattern = r'<video[^>]+src=["\']([^"\']+)["\']'
v_match = re.search(video_pattern, html)
if v_match:
video_url = v_match.group(1)
else:
var_pattern = r'var\s+player\w*\s*=\s*({[^;]+})'
var_match = re.search(var_pattern, html)
if var_match:
try:
config = json.loads(var_match.group(1).replace("'", '"'))
video_url = config.get('url', '')
except:
pass
if not video_url:
url_match = re.search(r'"url":"([^"]+)"', html)
if url_match:
video_url = url_match.group(1)
if video_url:
if not video_url.startswith('http'):
video_url = urljoin(play_url, video_url)
if re.search(r'\.(m3u8|mp4|mkv)', video_url, re.I):
parse = 0
else:
parse = 1
return {"parse": parse, "playUrl": "", "url": video_url, "header": headers}
else:
return {"parse": 1, "playUrl": "", "url": play_url, "header": headers}
except Exception as e:
print(f"playerContent error: {e}")
return {"parse": 1, "playUrl": "", "url": urljoin(xurl, id), "header": headers}
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
if params['type'] == "media":
return self.proxyMedia(params)
if params['type'] == "ts":
return self.proxyTs(params)
return None
+415
View File
@@ -0,0 +1,415 @@
# coding=utf-8
# !/usr/bin/python
"""
作者 丢丢喵 内容均从互联网收集而来 仅供交流学习使用 严禁用于商业用途 请于24小时内删除
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from bs4 import BeautifulSoup
from Crypto.Cipher import AES
from datetime import datetime
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import datetime
import binascii
import requests
import base64
import random
import json
import time
import ast
import sys
import re
import os
sys.path.append('..')
session = requests.Session()
xurl = "https://www.xinghetv.cc"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
headerz = {
'User-Agent': 'com.android.chrome/131.0.6778.200 (Linux;Android 9) AndroidXMedia3/1.8.0'
}
session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
'Referer': 'https://www.xinghetv.cc/',
'Origin': 'https://www.xinghetv.cc',
'sec-ch-ua': '"Google Chrome";v="123", "Not:A-Brand";v="8", "Chromium";v="123"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'Accept': 'application/json, text/javascript, */*; q=0.01',
'X-Requested-With': 'XMLHttpRequest'
})
headerw = {
'accept': 'text/html, */*; q=0.01',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'cache-control': 'no-cache',
'pragma': 'no-cache',
'priority': 'u=1, i',
'referer': 'https://www.xinghetv.cc/',
'sec-ch-ua': '"Microsoft Edge";v="143", "Chromium";v="143", "Not A(Brand";v="24"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0',
'x-requested-with': 'XMLHttpRequest',
}
class Spider(Spider):
def getName(self):
return "丢丢喵"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "1", "type_name": "电影"},
{"type_id": "2", "type_name": "剧集"},
{"type_id": "4", "type_name": "动漫"},
{"type_id": "3", "type_name": "综艺"}],
}
return result
def homeVideoContent(self):
pass
def _build_image_url(self, cover_url):
if 'http' not in cover_url:
return "https://image.baidu.com/search/down?url=https:" + cover_url
return cover_url
def _create_video_item(self, vod, cid):
name = vod['title']
video_id = vod['id'] + "@" + cid
pic = self._build_image_url(vod['cover'])
remark = vod.get('comment', '暂无备注')
return {
"vod_id": video_id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remark
}
def categoryContent(self, cid, pg, filter, ext):
videos = []
page = int(pg) if pg else 1
url = f'{xurl}/api/filter-list.php?catid={cid}&rank=rankhot&size=36&pageno={str(page)}'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
data = detail.json()
for vod in data['data']['movies']:
video = self._create_video_item(vod, cid)
videos.append(video)
result = {
'list': videos,
'page': pg,
'pagecount': 9999,
'limit': 90,
'total': 999999
}
return result
def _build_detail_url(self, fenge):
if '1' in fenge[1]:
return f'{xurl}/player.php?mid={fenge[0]}'
elif '2' in fenge[1]:
return f'{xurl}/player.php?tvid={fenge[0]}'
elif '3' in fenge[1]:
return f'{xurl}/player.php?vaid={fenge[0]}'
elif '4' in fenge[1]:
return f'{xurl}/player.php?ctid={fenge[0]}'
def _get_html_content(self, url):
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
return BeautifulSoup(res, "lxml")
def _extract_play_lines(self, doc):
xianlu = ''
soups = doc.find_all('ul', class_="am-tabs-nav")
for item in soups:
vods = item.find_all('li')
for sou in vods:
name = sou.text.strip()
xianlu = xianlu + name + '$$$'
if xianlu:
xianlu = xianlu[:-3]
else:
xianlu = "专线"
return xianlu
def _extract_play_urls(self, doc):
bofang = ''
soups = doc.find_all('div', class_="am-tab-panel")
for item in soups:
vods = item.find_all('button')
for sou in vods:
name = sou.text.strip()
skip_names = ["加载更多"]
if name in skip_names:
continue
id = sou['data-url']
bofang = bofang + name + '$' + id + '#'
bofang = bofang[:-1] + '$$$'
bofang = bofang[:-3]
return bofang
def detailContent(self, ids):
did = ids[0]
fenge = did.split("@")
url = self._build_detail_url(fenge)
doc = self._get_html_content(url)
xianlu = self._extract_play_lines(doc)
bofang = self._extract_play_urls(doc)
videos = [{
"vod_id": did,
"vod_play_from": xianlu,
"vod_play_url": bofang
}]
result = {'list': videos}
return result
def safe_b64decode(self, data):
if not data: return b""
data = data.replace('-', '+').replace('_', '/')
missing_padding = len(data) % 4
if missing_padding:
data += '=' * (4 - missing_padding)
return base64.b64decode(data)
def decrypt_m3u8(self, token, ciphertext, iv, tag):
try:
payload = json.loads(self.safe_b64decode(token.split('.')[0]))
cipher = AES.new(self.safe_b64decode(payload['key']), AES.MODE_GCM, nonce=self.safe_b64decode(iv))
return cipher.decrypt_and_verify(self.safe_b64decode(ciphertext), self.safe_b64decode(tag)).decode('utf-8')
except Exception as e:
return None
def get_verify_token(self):
url = 'https://www.xinghetv.cc/api/verify.php'
req_headers = headerz if 'headerz' in globals() else None
for i in range(5):
try:
resp = session.get(url, params={'action': 'challenge', 't': int(time.time() * 1000)},headers=req_headers).json()
if 'verify_token' in resp:
return resp['verify_token']
if 'challenge' in resp:
x = int(resp['targetX'])
y = int(resp['targetY'])
time.sleep(random.uniform(0.5, 1.0))
verify_data = {
'challenge': resp['challenge'],
'answer': f'{x + random.randint(-4, 4)},{y + random.randint(-4, 4)}'
}
v_resp = session.post(url, params={'action': 'verify'}, data=verify_data,headers=req_headers).json()
if v_resp.get('code') == 200:
continue
else:
print(f"验证提交失败,服务器返回: {v_resp}")
except Exception as e:
print(f"请求发生异常: {e}")
time.sleep(1)
return None
def get_xinghe_m3u8(self, video_url):
try:
v_token = self.get_verify_token()
if not v_token:
return "Error: Failed to get verify token"
req_headers = headerz if 'headerz' in globals() else None
auth_token = session.get('https://www.xinghetv.cc/api/token.php', headers=req_headers).json().get('token')
if not auth_token:
return "Error: Failed to get auth token"
resp = session.get('https://www.xinghetv.cc/api/parse.php', params={'url': video_url},headers={'x-auth-token': auth_token, 'x-verify-token': v_token,**(req_headers or {})}).json()
if 'ciphertext' in resp:
decrypted_str = self.decrypt_m3u8(auth_token, resp['ciphertext'], resp['iv'], resp['tag'])
if decrypted_str:
try:
data = json.loads(decrypted_str)
return data.get('url')
except json.JSONDecodeError:
return decrypted_str
return None
return f"Error: {resp.get('msg', 'Unknown error')}"
except Exception as e:
return f"Error: {str(e)}"
def playerContent(self, flag, id, vipFlags):
url = self.get_xinghe_m3u8(id)
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = url
result["header"] = headerz
return result
def _build_search_params(self, key, page):
return {
'wd': key,
'pageno': page,
'tab': 'official',
'ajax': '1',
}
def _fetch_search_data(self, params):
detail = requests.get('https://www.xinghetv.cc/search.php', params=params, headers=headerw)
detail.encoding = "utf-8-sig"
res = detail.text
return BeautifulSoup(res, "html.parser")
def _parse_id_from_href(self, href):
fenge = href.split("=")
if 'mid' in href:
return f"{fenge[1]}@1"
elif 'tvid' in href:
return f"{fenge[1]}@2"
elif 'vaid' in href:
return f"{fenge[1]}@3"
elif 'ctid' in href:
return f"{fenge[1]}@4"
def _parse_vod_item(self, vod):
name = vod.find('img')['alt']
ids = vod.find('div', class_="am-list-thumb")
id = self._parse_id_from_href(ids.find('a')['href'])
pic = vod.find('img')['data-original']
return {
"vod_id": id,
"vod_name": name,
"vod_pic": pic
}
def _build_result(self, videos, pg):
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContentPage(self, key, quick, pg):
page = int(pg) if pg else 1
params = self._build_search_params(key, page)
doc = self._fetch_search_data(params)
soups = doc.find_all('ul', class_="am-list")
videos = []
for item in soups:
vods = item.find_all('li')
for vod in vods:
video = self._parse_vod_item(vod)
videos.append(video)
return self._build_result(videos, pg)
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+348
View File
@@ -0,0 +1,348 @@
# coding = utf-8
# !/usr/bin/python
"""
作者 丢丢喵推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://app.whjzjx.cn"
headers = {
'User-Agent': 'Linux; Android 12; Pixel 3 XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.101 Mobile Safari/537.36'
}
headerf = {
"platform": "1",
"user_agent": "Mozilla/5.0 (Linux; Android 9; V1938T Build/PQ3A.190705.08211809; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/91.0.4472.114 Safari/537.36",
"content-type": "application/json; charset=utf-8"
}
times = int(time.time() * 1000)
data = {
"device": "2a50580e69d38388c94c93605241fb306",
"package_name": "com.jz.xydj",
"android_id": "ec1280db12795506",
"install_first_open": True,
"first_install_time": 1752505243345,
"last_update_time": 1752505243345,
"report_link_url": "",
"authorization": "",
"timestamp": times
}
plain_text = json.dumps(data, separators=(',', ':'), ensure_ascii=False)
key = "B@ecf920Od8A4df7"
key_bytes = key.encode('utf-8')
plain_bytes = plain_text.encode('utf-8')
cipher = AES.new(key_bytes, AES.MODE_ECB)
padded_data = pad(plain_bytes, AES.block_size)
ciphertext = cipher.encrypt(padded_data)
encrypted = base64.b64encode(ciphertext).decode('utf-8')
response = requests.post("https://u.shytkjgs.com/user/v3/account/login", headers=headerf, data=encrypted)
response_data = response.json()
Authorization = response_data['data']['token']
headerx = {
'authorization': Authorization,
'platform': '1',
'version_name': '3.8.3.1'
}
class Spider(Spider):
global xurl
global headerx
global headers
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "1", "type_name": "集多🌠剧场"},
{"type_id": "3", "type_name": "集多🌠新剧"},
{"type_id": "2", "type_name": "集多🌠热播"},
{"type_id": "7", "type_name": "集多🌠星选"},
{"type_id": "5", "type_name": "集多🌠阳光"}],
}
return result
def homeVideoContent(self):
videos = []
url= f'{xurl}/v1/theater/home_page?theater_class_id=1&class2_id=4&page_num=1&page_size=24'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
if detail.status_code == 200:
data = detail.json()
for vod in data['data']['list']:
name = vod['theater']['title']
id = vod['theater']['id']
pic = vod['theater']['cover_url']
remark = vod['theater']['play_amount_str']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
return result
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
url = f'{xurl}/v1/theater/home_page?theater_class_id={cid}&page_num={pg}&page_size=24'
detail = requests.get(url=url,headers=headerx)
detail.encoding = "utf-8"
if detail.status_code == 200:
data = detail.json()
for vod in data['data']['list']:
name = vod['theater']['title']
id = vod['theater']['id']
pic = vod['theater']['cover_url']
remark = vod['theater']['theme']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = ids[0]
result = {}
videos = []
xianlu = ''
bofang = ''
url = f'{xurl}/v2/theater_parent/detail?theater_parent_id={did}'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
if detail.status_code == 200:
data = detail.json()
url = 'https://fs-im-kefu.7moor-fs1.com/ly/4d2c3f00-7d4c-11e5-af15-41bf63ae4ea0/1732707176882/jiduo.txt'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
content = '集多🎉为您介绍剧情📢' + data['data']['introduction']
area = data['data']['desc_tags'][0]
remarks = data['data']['filing']
if name not in content:
bofang = Jumps
xianlu = '1'
else:
for sou in data['data']['theaters']:
id = sou['son_video_url']
name = sou['num']
bofang = bofang + str(name) + '$' + id + '#'
bofang = bofang[:-1]
xianlu = '集多专线'
videos.append({
"vod_id": did,
"vod_content": content,
"vod_remarks": remarks,
"vod_area": area,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = id
result["header"] = headers
return result
def searchContentPage(self, key, quick, page):
result = {}
videos = []
payload = {
"text": key
}
url = f"{xurl}/v3/search"
detail = requests.post(url=url, headers=headerx, json=payload)
if detail.status_code == 200:
detail.encoding = "utf-8"
data = detail.json()
for vod in data['data']['theater']['search_data']:
name = vod['title']
id = vod['id']
pic = vod['cover_url']
remark = vod['score_str']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = page
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+407
View File
@@ -0,0 +1,407 @@
# coding=utf-8
# !/usr/bin/python
"""
作者 丢丢喵 内容均从互联网收集而来 仅供交流学习使用 严禁用于商业用途 请于24小时内删除
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from datetime import datetime
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import datetime
import binascii
import requests
import hashlib
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://www.cycani.org"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
class Spider(Spider):
def getName(self):
return "丢丢喵"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def homeVideoContent(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
res = self.fetch_home_page()
doc = self.parse_html(res)
soups = self.find_home_categories(doc)
classes = self.extract_home_classes(soups)
return self.build_home_result(classes)
def fetch_home_page(self):
detail = requests.get(url=xurl, headers=headerx)
detail.encoding = "utf-8"
return detail.text
def parse_html(self, html):
return BeautifulSoup(html, "lxml")
def find_home_categories(self, doc):
return doc.find_all('li', class_="head-more-a")
def extract_home_classes(self, soups):
classes = []
for soup in soups:
for vod in soup.find_all('a'):
if self.should_skip_category(vod):
continue
classes.append(self.parse_home_class(vod))
return classes
def should_skip_category(self, vod):
name = vod.text.strip()
skip_names = ["更多", "首页", "4K专区"]
return name in skip_names
def parse_home_class(self, vod):
name = vod.text.strip()
id = vod['href']
return {"type_id": id, "type_name": name}
def build_home_result(self, classes):
result = {"class": classes}
return result
def categoryContent(self, cid, pg, filter, ext):
fenge = cid.split(".html")
page = self.get_page_number(pg)
url = self.build_category_url(fenge, page)
doc = self.fetch_category_document(url)
soups = doc.find_all('div', class_="border-box")
videos = self.extract_category_videos(soups)
return self.build_category_result(videos, pg)
def get_page_number(self, pg):
return int(pg) if pg else 1
def build_category_url(self, fenge, page):
return f'{xurl}{fenge[0]}/page/{str(page)}.html'
def fetch_category_document(self, url):
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
return BeautifulSoup(detail.text, "lxml")
def extract_category_videos(self, soups):
videos = []
for soup in soups:
for vod in soup.find_all('a', class_="public-list-exp"):
videos.append(self.parse_category_video(vod))
return videos
def parse_category_video(self, vod):
name = vod['title']
id = vod['href']
pic = vod.find('img')['data-src']
remarks = vod.find('i', class_="ft4")
remark = remarks.text.strip() if remarks else ""
return {"vod_id": id,"vod_name": name,"vod_pic": pic,"vod_remarks": remark}
def build_category_result(self, videos, pg):
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = self.prepare_did(ids[0])
res = self.fetch_detail_page(did)
doc = BeautifulSoup(res, "lxml")
content = self.build_content(res)
director = self.extract_director(res)
actor = self.extract_actor(res)
remarks = self.extract_remarks(res)
year = self.extract_year(res)
area = self.extract_area(res)
xianlu = self.extract_xianlu(doc)
bofang = self.extract_bofang(doc)
videos = [self.build_video_data(did, director, actor, remarks, year, area, content, xianlu, bofang)]
return {'list': videos}
def prepare_did(self, did):
return xurl + did if 'http' not in did else did
def fetch_detail_page(self, did):
detail = requests.get(url=did, headers=headerx)
detail.encoding = "utf-8"
return detail.text
def build_content(self, res):
return '😸丢丢为您介绍剧情📢' + self.extract_middle_text(res, '简介:</em>', '<', 0)
def extract_director(self, res):
return self.extract_middle_text(res, '导演:', '</li>', 1, 'target=".*?">(.*?)<')
def extract_actor(self, res):
return self.extract_middle_text(res, '主演:', '</li>', 1, 'target=".*?">(.*?)<')
def extract_remarks(self, res):
return self.extract_middle_text(res, '类型:', '</li>', 1, 'target=".*?">(.*?)<')
def extract_year(self, res):
return self.extract_middle_text(res, '年份:</em>', '<', 0)
def extract_area(self, res):
return self.extract_middle_text(res, '地区:</em>', '<', 0)
def extract_xianlu(self, doc):
soups = doc.find_all('div', class_="swiper-wrapper")
xianlu = ''
for item in soups:
for sou in item.find_all('a'):
xianlu += sou.text.strip() + '$$$'
return xianlu[:-3]
def extract_bofang(self, doc):
soups = doc.find_all('ul', class_="anthology-list-play")
bofang = ''
for item in soups:
for sou in item.find_all('a'):
id = sou['href']
if 'http' not in id:
id = xurl + id
bofang += sou.text.strip() + '$' + id + '#'
bofang = bofang[:-1] + '$$$'
return bofang[:-3]
def build_video_data(self, did, director, actor, remarks, year, area, content, xianlu, bofang):
return {"vod_id": did,"vod_director": director,"vod_actor": actor,"vod_remarks": remarks,"vod_year": year,"vod_area": area,"vod_content": content,"vod_play_from": xianlu,"vod_play_url": bofang}
def manual_decrypt(self, encrypted_url, raw_text, raw_sort):
secret_suffix = "YLwJVbXw77pk2eOrAnFdBo2c3mWkLtodMni2wk81GCnP94ZltW"
sorted_str = self.sort_and_combine_chars(raw_text, raw_sort)
final_str = self.add_salt_to_string(sorted_str, secret_suffix)
md5_hex = self.calculate_md5_hash(final_str)
iv, key = self.extract_iv_and_key(md5_hex)
real_url = self.perform_aes_decryption(encrypted_url, key, iv)
return real_url
def sort_and_combine_chars(self, raw_text, raw_sort):
pairs = []
min_len = min(len(raw_text), len(raw_sort))
for i in range(min_len):
pairs.append({'char': raw_text[i], 'sort': raw_sort[i]})
pairs.sort(key=lambda x: x['sort'])
return "".join([p['char'] for p in pairs])
def add_salt_to_string(self, sorted_str, salt):
return sorted_str + salt
def calculate_md5_hash(self, final_str):
return hashlib.md5(final_str.encode('utf-8')).hexdigest()
def extract_iv_and_key(self, md5_hex):
iv = md5_hex[0:16].encode('utf-8')
key = md5_hex[16:32].encode('utf-8')
return iv, key
def perform_aes_decryption(self, encrypted_url, key, iv):
cipher = AES.new(key, AES.MODE_CBC, iv)
encrypted_bytes = base64.b64decode(encrypted_url)
decrypted_bytes = cipher.decrypt(encrypted_bytes)
return unpad(decrypted_bytes, AES.block_size).decode('utf-8')
def playerContent(self, flag, id, vipFlags):
res = self.fetch_player_page(id)
url = self.extract_and_decode_url(res)
url2 = self.build_player_url(url)
res2 = self.fetch_player_iframe(url2)
raw_text = self.extract_raw_text(res2)
raw_sort = self.extract_raw_sort(res2)
encrypted_url = self.extract_encrypted_url(res2)
url5 = self.manual_decrypt(encrypted_url, raw_text, raw_sort)
return self.build_player_result(url5)
def fetch_player_page(self, id):
detail = requests.get(url=id, headers=headerx)
detail.encoding = "utf-8"
return detail.text
def extract_and_decode_url(self, res):
url = self.extract_middle_text(res, '},"url":"', '"', 0).replace('\\', '')
base64_decoded_bytes = base64.b64decode(url)
base64_decoded_string = base64_decoded_bytes.decode('utf-8')
return unquote(base64_decoded_string)
def build_player_url(self, url1):
return f"https://player.cycanime.com/?url={url1}"
def fetch_player_iframe(self, url2):
detail = requests.get(url=url2, headers=headerx)
detail.encoding = "utf-8"
return detail.text
def extract_raw_text(self, res2):
return self.extract_middle_text(res2, 'user-scalable=no" id="now_', '"', 0)
def extract_raw_sort(self, res2):
return self.extract_middle_text(res2, '"UTF-8" id="now_', '"', 0)
def extract_encrypted_url(self, res2):
return self.extract_middle_text(res2, '"url": "', '"', 0)
def build_player_result(self, url5):
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = url5
result["header"] = headerx
return result
def searchContentPage(self, key, quick, pg):
page = self.get_page_number(pg)
url = self.build_search_url(key, page)
data = self.fetch_search_json(url)
videos = self.parse_search_videos(data)
return self.build_search_result(videos, pg)
def get_page_number(self, pg):
return int(pg) if pg else 1
def build_search_url(self, key, page):
return f'{xurl}/index.php/ajax/suggest?mid=1&wd={key}&page={str(page)}&limit=30'
def fetch_search_json(self, url):
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
return detail.json()
def parse_search_videos(self, data):
videos = []
for vod in data['list']:
videos.append(self.parse_search_item(vod))
return videos
def parse_search_item(self, vod):
name = vod['name']
id = f"{xurl}/bangumi/{vod['id']}.html"
pic = vod['pic']
return {"vod_id": id,"vod_name": name,"vod_pic": pic}
def build_search_result(self, videos, pg):
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+425
View File
@@ -0,0 +1,425 @@
# coding = utf-8
# !/usr/bin/python
"""
作者 丢丢喵推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import binascii
import requests
import base64
import json
import time
import uuid
import sys
import re
import os
sys.path.append('..')
xurl = "https://freevideo.zqqds.cn"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
pm = ''
class Spider(Spider):
global xurl
global headers
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "53@精选", "type_name": "集多🌠精选"},
{"type_id": "54@古装", "type_name": "集多🌠古装"},
{"type_id": "55@重生", "type_name": "集多🌠重生"},
{"type_id": "56@家庭", "type_name": "集多🌠家庭"},
{"type_id": "57@恋爱", "type_name": "集多🌠恋爱"}],
}
return result
def decrypt(self, encrypted_data):
key = "ZHpramdmeXhnc2h5bGd6bQ=="
iv = "YXBpdXBkb3duZWRjcnlwdA=="
key_bytes = base64.b64decode(key)
iv_bytes = base64.b64decode(iv)
encrypted_bytes = base64.b64decode(encrypted_data)
cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
decrypted_padded_bytes = cipher.decrypt(encrypted_bytes)
decrypted_bytes = unpad(decrypted_padded_bytes, AES.block_size)
return decrypted_bytes.decode('utf-8')
def decrypt_wb(self, encrypted_data):
key_base64 = "ZHpramdmeXhnc2h5bGd6bQ=="
key_bytes = base64.b64decode(key_base64)
iv_base64 = "YXBpdXBkb3duZWRjcnlwdA=="
iv_bytes = base64.b64decode(iv_base64)
plaintext = encrypted_data
cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
ciphertext_bytes = cipher.encrypt(pad(plaintext.encode('utf-8'), AES.block_size))
ciphertext_base64 = base64.b64encode(ciphertext_bytes).decode('utf-8')
return ciphertext_base64
def encrypt_data(self):
random_uuid = uuid.uuid4()
key = "dzkjgfyxgshylgzm"
iv = "apiupdownedcrypt"
data = {
"version": "2.1.0",
"pname": "com.dz.hmjc",
"channelCode": "HMJC1000002",
"utdidTmp": "A20250528195953036srZcvA",
"token": "",
"utdid": "d5d959973340bb1325b551cce488a191",
"os": "android",
"osv": 28,
"brand": "vivo",
"model": "V1938T",
"manu": "vivo",
"userId": "2484393607",
"launch": "shortcut",
"mchid": "HMJC1000002",
"nchid": "VHSE1000000",
"session1": random_uuid,
"session2": random_uuid,
"startScene": "shortcut",
"recSwitch": True,
"installTime": 1748433575024,
"p": 30
}
def default(o):
if isinstance(o, uuid.UUID):
return str(o)
raise TypeError(f'Object of type {o.__class__.__name__} is not JSON serializable')
plaintext = json.dumps(data, separators=(',', ':'), ensure_ascii=False, default=default).encode('utf-8')
cipher = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
padded_data = pad(plaintext, AES.block_size)
ciphertext = cipher.encrypt(padded_data)
encrypted_b64 = base64.b64encode(ciphertext).decode('utf-8')
headerx = {
"alg": "HG45LKBS",
"datas": encrypted_b64,
"content-type": "application/json; charset=utf-8",
"user-agent": "okhttp/4.10.0"
}
return headerx
def homeVideoContent(self):
pass
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
fenge = cid.split("@")
di = f'{{"recSwitch":true,"storePageId":10002,"channelGroupId":"10","channelId":{fenge[0]},"channelName":"{fenge[1]}","lastColumnStyle":3,"fromColumnId":"1","pageFlag":"{str(page)}","theaterSubscriptSwitch":true}}'
detail = self.decrypt_wb(di)
url = f"{xurl}/free-video-portal/portal/1125"
response = requests.post(url=url, headers=self.encrypt_data(), data=detail)
if response.status_code == 200:
response_data = response.json()
data = response_data.get('data')
detail = self.decrypt(data)
detail = json.loads(detail)
js = detail['columnData'][0]['videoData']
for vod in js:
name = vod['bookName']
id = vod['bookId']
pic = vod['coverWap']
remark = vod['finishStatusCn']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
global pm
did = ids[0]
result = {}
videos = []
xianlu = ''
purl = ''
di = f'{{"bookId":"{did}","needNextChapter":0,"isNeedAlias":"","bookAlias":"","resolutionRate":"720P"}}'
detail = self.decrypt_wb(di)
url = f"{xurl}/free-video-portal/portal/1131"
response = requests.post(url=url, headers=self.encrypt_data(), data=detail)
if response.status_code == 200:
response_data = response.json()
data = response_data.get('data')
detail = self.decrypt(data)
detail = json.loads(detail)
url = 'http://rihou.cc:88/je.json'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
vod_content = '集多为您介绍剧情' + detail['videoInfo']['introduction']
vod_actor = detail['videoInfo']['protagonist']
vod_actor = ', '.join(vod_actor)
vod_actor = vod_actor.replace('[', '').replace(']', '').replace("'", "").replace(",", "")
vod_director = detail['videoInfo']['protagonist'][0]
bookTags = detail['videoInfo']['bookTags']
bookTags = ', '.join(bookTags)
bookTags = bookTags.replace(',', '')
vod_remarks = detail['videoInfo']['finishStatusCn']
vod_remarks = vod_remarks + " " + bookTags
year = detail['videoInfo']['utime']
area = "中国"
if name not in vod_content:
purl = Jumps
xianlu = '1'
else:
sz = len(detail['chapterList']) - 1
zhyj = detail['chapterList'][sz]['chapterId']
soups = detail['chapterList']
for vods in soups:
name = vods['chapterName']
parse = vods['chapterId']
parse = did + '@' + parse + '@' + zhyj
purl = purl + name + '$' + parse + '#'
purl = purl[:-1]
xianlu = '集多专线'
videos.append({
"vod_id": did,
"vod_actor": vod_actor,
"vod_director": vod_director,
"vod_content": vod_content,
"vod_remarks": vod_remarks,
"vod_year": year,
"vod_area": area,
"vod_play_from": xianlu,
"vod_play_url": purl
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
fenge = id.split("@")
di = '{"bookId":"","chapterIds":[""],"unClockType":"load","chapterId":"","resolutionRate":"720P"}'
data = json.loads(di)
data['bookId'] = fenge[0]
data['chapterIds'][0] = fenge[1]
data['chapterId'] = fenge[2]
new_di = json.dumps(data, ensure_ascii=False, indent=4)
detail2 = self.decrypt_wb(new_di)
url = f"{xurl}/free-video-portal/portal/1139"
res2 = requests.post(url=url, headers=self.encrypt_data(), data=detail2)
js = json.loads(res2.text)
data = js['data']
detail2 = self.decrypt(data)
detail = json.loads(detail2)
url = detail['chapterInfo'][0]['content']['mp4SwitchUrl'][0]
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = url
result["header"] = headers
return result
def searchContentPage(self, key, quick, pg):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
di = f'{{"keyword":"{key}","page":{str(page)},"size":15,"searchSource":"搜索按钮","hotWordType":2,"tagIds":"","reservationSwitch":true}}'
detail = self.decrypt_wb(di)
url = f"{xurl}/free-video-portal/portal/1803"
response = requests.post(url=url, headers=self.encrypt_data(), data=detail)
if response.status_code == 200:
response_data = response.json()
data = response_data.get('data')
detail = self.decrypt(data)
detail = json.loads(detail)
js = detail['searchVos']
for vod in js:
name = vod['bookName']
id = vod['bookId']
pic = vod['coverWap']
remark = vod['finishStatusCn']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
result['page'] = page
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+329
View File
@@ -0,0 +1,329 @@
# coding=utf-8
# !/usr/bin/python
"""
作者 丢丢喵推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from datetime import datetime
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import datetime
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://djw1.com"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {"class": []}
detail = requests.get(url=xurl + "/all/", headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('section', class_="container items")
for soup in soups:
vods = soup.find_all('li')
for vod in vods:
id = vod.find('a')['href']
name = vod.text.strip()
result["class"].append({"type_id": id, "type_name": "集多🌠" + name})
return result
def homeVideoContent(self):
pass
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
url = f'{cid}page/{str(page)}/'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('section', class_="container items")
for soup in soups:
vods = soup.find_all('li')
for vod in vods:
name = vod.find('img')['alt']
ids = vod.find('a', class_="image-line")
id = ids['href']
pic = vod.find('img')['src']
remark = self.extract_middle_text(str(vod), 'class="remarks light">', '<', 0)
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = ids[0]
result = {}
videos = []
xianlu = ''
bofang = ''
if 'http' not in did:
did = xurl + did
res = requests.get(url=did, headers=headerx)
res.encoding = "utf-8"
res = res.text
doc = BeautifulSoup(res, "lxml")
url = 'http://rihou.cc:88/je.json'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
content = '集多为您介绍剧情📢' + self.extract_middle_text(res,'class="info-detail">','<', 0)
remarks = self.extract_middle_text(res, 'class="info-mark">', '<', 0)
year = self.extract_middle_text(res, 'class="info-addtime">', '<', 0)
if name not in content:
bofang = Jumps
xianlu = '1'
else:
soups = doc.find('div', class_="ep-list-items")
soup = soups.find_all('a')
for sou in soup:
id = sou['href']
name = sou.text.strip()
bofang = bofang + name + '$' + id + '#'
bofang = bofang[:-1]
xianlu = '集多专线'
videos.append({
"vod_id": did,
"vod_remarks": remarks,
"vod_year": year,
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
res = requests.get(url=id, headers=headerx)
res.encoding = "utf-8"
res = res.text
url = self.extract_middle_text(res, '"wwm3u8":"', '"', 0).replace('\\', '')
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
return result
def searchContentPage(self, key, quick, pg):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
url = f'{xurl}/search/{key}/page/{str(page)}/'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('section', class_="container items")
for soup in soups:
vods = soup.find_all('li')
for vod in vods:
name = vod.find('img')['alt']
ids = vod.find('a', class_="image-line")
id = ids['href']
pic = vod.find('img')['src']
remark = self.extract_middle_text(str(vod), 'class="remarks light">', '<', 0)
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+355
View File
@@ -0,0 +1,355 @@
# coding = utf-8
# !/usr/bin/python
"""
作者 丢丢喵推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from datetime import datetime
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import datetime
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://new.tianjinzhitongdaohe.com"
headers = {
"Cache-Control": "no-cache",
"Content-Type": "application/json;charset=UTF-8",
"User-Agent": "okhttp/4.12.0"
}
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
class Spider(Spider):
global xurl
global headers
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {"class": []}
payload = {}
url = f"{xurl}/api/v1/app/screen/screenType"
response = requests.post(url=url, headers=headers, json=payload)
if response.status_code == 200:
data = response.json()
setup = data['data'][0]['children'][0]['children']
for vod in setup:
name = vod['name']
result["class"].append({"type_id": name, "type_name": "集多🌠" + name})
return result
def homeVideoContent(self):
pass
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
payload = {
"condition": {
"classify": cid,
"typeId": "S1"
},
"pageNum": str(page),
"pageSize": 40
}
url = f"{xurl}/api/v1/app/screen/screenMovie"
response = requests.post(url=url, headers=headers, json=payload)
if response.status_code == 200:
data = response.json()
setup = data['data']['records']
for vod in setup:
name = vod['name']
id = vod['id']
pic = vod['cover']
remark = vod['classify']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = ids[0]
result = {}
videos = []
xianlu = ''
bofang = ''
payload = {
"id": did,
"typeId": "S1"
}
url = f"{xurl}/api/v1/app/play/movieDesc"
response = requests.post(url=url, headers=headers, json=payload)
if response.status_code == 200:
data = response.json()
url = 'http://rihou.cc:88/je.json'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
content = '集多为您介绍剧情📢' + data.get('data', {}).get('introduce', '') if data.get('data', {}).get('introduce') is not None else '未知'
if name not in content:
bofang = Jumps
xianlu = '1'
else:
payload = {
"id": did,
"source": 0,
"typeId": "S1",
"userId": "223664"
}
url = f"{xurl}/api/v1/app/play/movieDetails"
response = requests.post(url=url, headers=headers, json=payload)
if response.status_code == 200:
data = response.json()
soup = data['data']['episodeList']
for sou in soup:
id = str(did) + "@" + str(sou['id'])
name = sou['episode']
bofang = bofang + name + '$' + str(id) + '#'
bofang = bofang[:-1]
xianlu = '集多专线'
videos.append({
"vod_id": did,
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
fenge = id.split("@")
payload = {
"episodeId": fenge[1],
"id": fenge[0],
"source": 0,
"typeId": "S1",
"userId": "223664"
}
url = f"{xurl}/api/v1/app/play/movieDetails"
response = requests.post(url=url, headers=headers, json=payload)
if response.status_code == 200:
data = response.json()
url = data['data']['url']
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
return result
def searchContentPage(self, key, quick, pg):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
payload = {
"condition": {
"typeId": "S1",
"value": key
},
"pageNum": str(page),
"pageSize": 40
}
url = f"{xurl}/api/v1/app/search/searchMovie"
response = requests.post(url=url, headers=headers, json=payload)
if response.status_code == 200:
data = response.json()
setup = data['data']['records']
for vod in setup:
name = vod['name']
id = vod['id']
pic = vod['cover']
remark = vod['year']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+279
View File
@@ -0,0 +1,279 @@
# coding=utf-8
# !/usr/bin/python
# by嗷呜(finally)
import sys
import os
sys.path.append("..")
import re
import hashlib
import hmac
import random
import string
from Crypto.Util.Padding import unpad
from concurrent.futures import ThreadPoolExecutor
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5, AES
from base64 import b64encode, b64decode
import json
import time
from base.spider import Spider
class Spider(Spider):
def getName(self):
return "电影猎手"
def init(self, extend=""):
self.device = self.device_id()
self.host = self.gethost()
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def action(self, action):
pass
def destroy(self):
pass
t = str(int(time.time()))
def homeContent(self, filter):
result = {}
filters = {}
classes = []
bba = self.url()
data = self.fetch(f"{self.host}/api/v1/app/config?pack={bba[0]}&signature={bba[1]}", headers=self.header()).text
data1 = self.aes(data)
dy = {"class":"类型","area":"地区","lang":"语言","year":"年份","letter":"字母","by":"排序","sort":"排序"}
data1['data']['movie_screen']['sort'].pop(0)
for item in data1['data']['movie_screen']['sort']:
item['n'] = item.pop('name')
item['v'] = item.pop('value')
for item in data1['data']['movie_screen']['filter']:
has_non_empty_field = False
classes.append({"type_name": item["name"], "type_id": str(item["id"])})
for key in dy:
if key in item and item[key]:
has_non_empty_field = True
break
if has_non_empty_field:
filters[str(item["id"])] = []
filters[str(item["id"])].append(
{"key": 'sort', "name": '排序', "value": data1['data']['movie_screen']['sort']})
for dkey in item:
if dkey in dy and item[dkey]:
item[dkey].pop(0)
value_array = [
{"n": value.strip(), "v": value.strip()}
for value in item[dkey]
if value.strip() != ""
]
filters[str(item["id"])].append(
{"key": dkey, "name": dy[dkey], "value": value_array}
)
result["class"] = classes
result["filters"] = filters
return result
def homeVideoContent(self):
bba = self.url()
url = f'{self.host}/api/v1/movie/index_recommend?pack={bba[0]}&signature={bba[1]}'
data = self.fetch(url, headers=self.header()).json()
videos = []
for item in data['data']:
if len(item['list']) > 0:
for it in item['list']:
try:
videos.append(self.voides(it))
except Exception as e:
continue
result = {"list": videos}
return result
def categoryContent(self, tid, pg, filter, extend):
body = {"type_id": tid, "sort": extend.get("sort", "by_default"), "class": extend.get("class", "类型"),
"area": extend.get("area", "地区"), "year": extend.get("year", "年份"), "page": str(pg),
"pageSize": "21"}
result = {}
list = []
bba = self.url(body)
url = f"{self.host}/api/v1/movie/screen/list?pack={bba[0]}&signature={bba[1]}"
data = self.fetch(url, headers=self.header()).json()['data']['list']
for item in data:
list.append(self.voides(item))
result["list"] = list
result["page"] = pg
result["pagecount"] = 9999
result["limit"] = 90
result["total"] = 999999
return result
def detailContent(self, ids):
body = {"id": ids[0]}
bba = self.url(body)
url = f'{self.host}/api/v1/movie/detail?pack={bba[0]}&signature={bba[1]}'
data = self.fetch(url, headers=self.header()).json()['data']
video = {'vod_name': data.get('name'),'type_name': data.get('type_name'),'vod_year': data.get('year'),'vod_area': data.get('area'),'vod_remarks': data.get('dynami'),'vod_content': data.get('content')}
play = []
names = []
tasks = []
for itt in data["play_from"]:
name = itt["name"]
a = []
if len(itt["list"]) > 0:
names.append(name)
play.append(self.playeach(itt['list']))
else:
tasks.append({"movie_id": ids[0], "from_code": itt["code"]})
names.append(name)
if tasks:
with ThreadPoolExecutor(max_workers=len(tasks)) as executor:
results = executor.map(self.playlist, tasks)
for result in results:
if result:
play.append(result)
else:
play.append("")
video["vod_play_from"] = "$$$".join(names)
video["vod_play_url"] = "$$$".join(play)
result = {"list": [video]}
return result
def searchContent(self, key, quick, pg=1):
body = {"keyword": key, "sort": "", "type_id": "0", "page": str(pg), "pageSize": "10",
"res_type": "by_movie_name"}
bba = self.url(body)
url = f"{self.host}/api/v1/movie/search?pack={bba[0]}&signature={bba[1]}"
data = self.fetch(url, headers=self.header()).json()['data'].get('list')
videos = []
for it in data:
try:
videos.append(self.voides(it))
except Exception as e:
continue
result = {"list": videos, "page": pg}
return result
def playerContent(self, flag, id, vipFlags):
url = id
if "m3u8" not in url and "mp4" not in url:
try:
add = id.split('|||')
data = {"from_code": add[0], "play_url": add[1], "episode_id": add[2], "type": "play"}
bba = self.url(data)
data2 = self.fetch(f"{self.host}/api/v1/movie_addr/parse_url?pack={bba[0]}&signature={bba[1]}",
headers=self.header()).json()['data']
url = data2.get('play_url') or data2.get('download_url')
try:
url1 = self.fetch(url, headers=self.header(), allow_redirects=False).headers['Location']
if url1 and "http" in url1:
url = url1
except:
pass
except Exception as e:
pass
if '.jpg' in url or '.jpeg' in url or '.png' in url:
url = self.getProxyUrl() + "&url=" + b64encode(url.encode('utf-8')).decode('utf-8') + "&type=m3u8"
result = {}
result["parse"] = 0
result["url"] = url
result["header"] = {'user-agent': 'okhttp/4.9.2'}
return result
def localProxy(self, param):
url = b64decode(param["url"]).decode('utf-8')
durl = url[:url.rfind('/')]
data = self.fetch(url, headers=self.header()).content.decode("utf-8")
lines = data.strip().split('\n')
for index, string in enumerate(lines):
# if 'URI="' in string and 'http' not in string:
# lines[index] = index
# 暂时预留,貌似用不到
if '#EXT' not in string and 'http' not in string:
lines[index] = durl + ('' if string.startswith('/') else '/') + string
data = '\n'.join(lines)
return [200, "application/vnd.apple.mpegur", data]
def device_id(self):
characters = string.ascii_lowercase + string.digits
random_string = ''.join(random.choices(characters, k=32))
return random_string
def gethost(self):
headers = {
'User-Agent': 'okhttp/4.9.2',
'Connection': 'Keep-Alive',
}
response = self.fetch('https://app-site.ecoliving168.com/domain_v5.json', headers=headers).json()
url = response['api_service'].replace('/api/', '')
return url
def header(self):
headers = {
'User-Agent': 'Android',
'Accept': 'application/prs.55App.v2+json',
'timestamp': self.t,
'x-client-setting': '{"pure-mode":1}',
'x-client-uuid': '{"device_id":' + self.device + '}, "type":1,"brand":"Redmi", "model":"M2012K10C", "system_version":30, "sdk_version":"3.1.0.7"}',
'x-client-version': '3096 '
}
return headers
def url(self, id=None):
if not id:
id = {}
id["timestamp"] = self.t
public_key = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA02F/kPg5A2NX4qZ5JSns+bjhVMCC6JbTiTKpbgNgiXU+Kkorg6Dj76gS68gB8llhbUKCXjIdygnHPrxVHWfzmzisq9P9awmXBkCk74Skglx2LKHa/mNz9ivg6YzQ5pQFUEWS0DfomGBXVtqvBlOXMCRxp69oWaMsnfjnBV+0J7vHbXzUIkqBLdXSNfM9Ag5qdRDrJC3CqB65EJ3ARWVzZTTcXSdMW9i3qzEZPawPNPe5yPYbMZIoXLcrqvEZnRK1oak67/ihf7iwPJqdc+68ZYEmmdqwunOvRdjq89fQMVelmqcRD9RYe08v+xDxG9Co9z7hcXGTsUquMxkh29uNawIDAQAB'
encrypted_text = json.dumps(id)
public_key = RSA.import_key(b64decode(public_key))
cipher = PKCS1_v1_5.new(public_key)
encrypted_message = cipher.encrypt(encrypted_text.encode('utf-8'))
encrypted_message_base64 = b64encode(encrypted_message).decode('utf-8')
result = encrypted_message_base64.replace('+', '-').replace('/', '_').replace('=', '')
key = '635a580fcb5dc6e60caa39c31a7bde48'
sign = hmac.new(key.encode(), result.encode(), hashlib.md5).hexdigest()
return result, sign
def playlist(self, body):
try:
bba = self.url(body)
url = f'{self.host}/api/v1/movie_addr/list?pack={bba[0]}&signature={bba[1]}'
data = self.fetch(url, headers=self.header()).json()['data']
return self.playeach(data)
except Exception:
return []
def playeach(self,data):
play_urls = []
for it in data:
if re.search(r"mp4|m3u8", it["play_url"]):
play_urls.append(f"{it['episode_name']}${it['play_url']}")
else:
play_urls.append(
f"{it['episode_name']}${it['from_code']}|||{it['play_url']}|||{it['episode_id']}"
)
return '#'.join(play_urls)
def voides(self, item):
if item['name'] or item['title']:
voide = {
"vod_id": item.get('id') or item.get('click'),
'vod_name': item.get('name') or item.get('title'),
'vod_pic': item.get('cover') or item.get('image'),
'vod_year': item.get('year') or item.get('label'),
'vod_remarks': item.get('dynamic') or item.get('sub_title')
}
return voide
def aes(self, text):
text = text.replace('-', '+').replace('_', '/') + '=='
key = b"e6d5de5fcc51f53d"
iv = b"2f13eef7dfc6c613"
cipher = AES.new(key, AES.MODE_CBC, iv)
pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size).decode("utf-8")
return json.loads(pt)
+228
View File
@@ -0,0 +1,228 @@
"""
作者 丢丢猫推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================kaiyuebinguan====================
"""
import requests
from bs4 import BeautifulSoup
import re
from base.spider import Spider
import sys
import json
import base64
import urllib.parse
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from Crypto.Util.Padding import unpad
import binascii
import os
import time
import urllib.request
sys.path.append('..')
xurl = "https://www.sdsrty.com"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
pm = ''
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{'📽️集多👉' + match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{'📽️集多👉' + match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'✨集多👉{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "32", "type_name": "集多🌠生活"},
{"type_id": "33", "type_name": "集多🌠古装"},
{"type_id": "34", "type_name": "集多🌠穿越"},
{"type_id": "35", "type_name": "集多🌠爱情"},
{"type_id": "36", "type_name": "集多🌠悬疑"},
{"type_id": "37", "type_name": "集多🌠逆袭"}
],
}
return result
def homeVideoContent(self):
videos = []
try:
detail = requests.get(url=xurl, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
result = {'list': videos}
return result
except:
pass
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
url = f'https://www.sdsrty.com/sw-alien/{cid}_{str(pg)}.html'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find('ul', class_="yystyle-vodlist clearfix").find_all('li')
for vod in soups:
name = vod.find('a')['title']
id = vod.find('a')['href']
pic = vod.find('img')['data-original']
rs=vod.find_all('span')
if len(rs) == 1:
remark =''
else:
remark = vod.find_all('span')[1].get_text()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
global pm
did = ids[0]
result = {}
videos = []
playurl = ''
if 'http' not in did:
did = xurl + did
did=did.replace('com/vd', 'com/vp')
res1 = requests.get(url=did, headers=headerx)
res1.encoding = "utf-8"
res = res1.text
content = '集多🎉为您介绍剧情📢本资源来源于网络🚓侵权请联系删除👉' + self.extract_middle_text(res,'免费在线观看。','喜欢免费', 0)
bofang=self.extract_middle_text(res,'var videoUrl = "','"', 0)
videos.append({
"vod_id": did,
"vod_actor": '集多和他的兄弟们',
"vod_director": '集多',
"vod_content": content,
"vod_play_from": '全集播放',
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = id
result["header"] = headerx
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+399
View File
@@ -0,0 +1,399 @@
# coding=utf-8
# !/usr/bin/python
"""
作者 丢丢喵推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from datetime import datetime
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import datetime
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://www.duanju2.com"
headerx = {
'User-Agent': 'Mozilla/5.0 (Linux; U; Android 8.0.0; zh-cn; Mi Note 2 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.1.1'
}
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {"class": []}
detail = requests.get(url=xurl + "/type/duanju.html", headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soup = doc.find('ul', class_="filter")
vods = soup.find_all('li')
for vod in vods:
name = vod.text.strip()
if name in ["全部", "分类:"]:
continue
id = vod.find('a')['href']
result["class"].append({"type_id": id, "type_name": "集多🌠" + name})
return result
def homeVideoContent(self):
videos = []
url = f"{xurl}/show/duanju-----------.html"
detail = requests.get(url=xurl, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="row")
for soup in soups:
vods = soup.find_all('div', class_="col-lg-2")
for vod in vods:
names = vod.find('div', class_="placeholder")
name = names.find('a')['title']
id = names.find('a')['href']
pic = vod.find('img')['data-src']
remarks = vod.find('span', class_="meta-post-type2")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
return result
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
fenge = cid.split("---.html")
url = f'{xurl}{fenge[0]}{str(page)}---.html'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="row")
for soup in soups:
vods = soup.find_all('div', class_="col-lg-2")
for vod in vods:
names = vod.find('div', class_="placeholder")
name = names.find('a')['title']
id = names.find('a')['href']
pic = vod.find('img')['data-src']
remarks = vod.find('span', class_="meta-post-type2")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = ids[0]
result = {}
videos = []
xianlu = ''
bofang = ''
if 'http' not in did:
did = xurl + did
res = requests.get(url=did, headers=headerx)
res.encoding = "utf-8"
res = res.text
doc = BeautifulSoup(res, "lxml")
url = 'http://rihou.cc:88/je.json'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
content = '集多为您介绍剧情📢' + self.extract_middle_text(res,'<meta name="description" content="','"', 0)
director = self.extract_middle_text(res,'导演:</span><b>','<', 0)
actor = self.extract_middle_text(res,'主演:</span><b>','<', 0)
remarks = self.extract_middle_text(res, '分类:', '</li>',1,'style=".*?">(.*?)</a>')
year = self.extract_middle_text(res,'年份:</span><b>','<', 0)
area = self.extract_middle_text(res,'地区:</span><b>','<', 0)
if name not in content:
bofang = Jumps
xianlu = '1'
else:
soups = doc.find('ul', class_="nav nav-pills")
soup = soups.find_all('a')[1:]
for sou in soup:
name = sou.text.strip()
xianlu = xianlu + name + '$$$'
xianlu = xianlu[:-3]
soups = doc.find_all('div', class_="tab-pane fade show")
for soup in soups:
vods = soup.find_all('a')
for sou in vods:
id = sou['href']
if 'http' not in id:
id = xurl + id
name = sou.text.strip()
bofang = bofang + name + '$' + id + '#'
bofang = bofang[:-1] + '$$$'
bofang = bofang[:-3]
videos.append({
"vod_id": did,
"vod_director": director,
"vod_actor": actor,
"vod_remarks": remarks,
"vod_year": year,
"vod_area": area,
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def unicode_escape_to_char(self,s):
return re.sub(r'\\?u([0-9a-fA-F]{4})', lambda m: chr(int(m.group(1), 16)), s)
def playerContent(self, flag, id, vipFlags):
res = requests.get(url=id, headers=headerx)
res = res.text
url = self.extract_middle_text(res, 'var player_aaaa={', '}',1,'"url":"(.*?)"').replace('\\', '')
if 'p.' in url or 'c1.' in url:
base_path = "/".join(url.split("/")[0:-2])
encoded_folder = url.split("/")[-2]
decoded_folder = self.unicode_escape_to_char(encoded_folder)
quoted_folder = quote(decoded_folder)
url = f"{base_path}/{quoted_folder}/index.m3u8"
else:
url = url
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
return result
def searchContentPage(self, key, quick, pg):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
url = f'{xurl}/search/{key}----------{str(page)}---.html'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="col-lg-12")
for vod in soups:
names = vod.find('div', class_="placeholder")
name = names.find('a')['title']
id = names.find('a')['href']
pic = vod.find('img')['data-src']
remarks = vod.find('span', class_="meta-post-type2")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+377
View File
@@ -0,0 +1,377 @@
"""
作者 丢丢猫推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================kaiyuebinguan====================
"""
from Crypto.Util.Padding import unpad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from base.spider import Spider
from bs4 import BeautifulSoup
import urllib.request
import urllib.parse
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://www.zywest263.com"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
pm = ''
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{'📽️集多👉' + match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{'📽️集多👉' + match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'✨集多👉{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "27", "type_name": "集多短剧🌠"}
],
"list": [],
"filters": {
"4": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}]}}
return result
def homeVideoContent(self):
videos = []
try:
detail = requests.get(url=xurl, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="tab-content")
for soup in soups:
vods = soup.find_all('li')
for vod in vods:
name = vod.find('a')['title']
id = vod.find('a')['href']
pic = vod.find('a')['data-original']
if 'http' not in pic:
pic = xurl + pic
remarks = vod.find('a', class_="lazyload")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多推荐▶️' + remark
}
videos.append(video)
result = {'list': videos}
return result
except:
pass
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
if '年代' in ext.keys():
NdType = ext['年代']
else:
NdType = ''
if page == '1':
url = f'{xurl}/zywtype/{cid}.html'
else:
url = f'{xurl}/search.html?page={str(page)}&searchtype=5&tid={cid}&year={NdType}'
try:
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('ul', class_="_9dbe81752a1dbf17-vodlist")
for soup in soups:
vods = soup.find_all('li')
for vod in vods:
name = vod.find('a')['title']
id = vod.find('a')['href']
pic = vod.find('a')['data-original']
if 'http' not in pic:
pic = xurl + pic
remarks = vod.find('a', class_="lazyload")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多推荐▶️' + remark
}
videos.append(video)
except:
pass
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
global pm
did = ids[0]
result = {}
videos = []
if 'http' not in did:
did = xurl + did
res1 = requests.get(url=did, headers=headerx)
res1.encoding = "utf-8"
res = res1.text
url = 'http://rihou.cc:88/je.json'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jump = self.extract_middle_text(code, "s2='", "'", 0)
content = '集多🎉为您介绍剧情📢本资源来源于网络🚓侵权请联系删除👉' + self.extract_middle_text(res,
'<meta name="description" content=',
'/>', 0)
if name not in content:
bofang = Jump
else:
bofang = self.extract_middle_text(res, '<ul class="_9dbe81752a1dbf17-content__playlist', '</ul>', 3,
'href="(.*?)" target=".*?">(.*?)</a>')
xianlu = self.extract_middle_text(res, '<ul class="dropdown-menu">', '</ul>', 2, 'data-toggle=".*?">(.*?)</a>')
videos.append({
"vod_id": did,
"vod_actor": '集多和他的兄弟们',
"vod_director": '集多',
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
parts = id.split("http")
xiutan = 0
if xiutan == 0:
if len(parts) > 1:
before_https, after_https = parts[0], 'http' + parts[1]
if '/tp/jd.m3u8' in after_https:
url3 = after_https
else:
res = requests.get(url=after_https, headers=headerx)
res = res.text
url = self.extract_middle_text(res, "' +',", ",", 0).replace('\\', '')
url1 = "https://jxj.fkowq.com/api/publicApi.php?&code=vip&next=&url=" + url
res1 = requests.get(url=url1, headers=headerx)
res1 = res1.text
url3 = self.extract_middle_text(res1, "var url = '", "'", 0)
result = {}
result["parse"] = xiutan
result["playUrl"] = ''
result["url"] = url3
result["header"] = headerx
return result
def searchContentPage(self, key, quick, page):
result = {}
videos = []
if not page:
page = '1'
if page == '1':
url = f'{xurl}/search.html?searchword={key}'
else:
url = f'{xurl}/search.html?page={str(page)}&searchword={key}&searchtype='
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('ul', class_="_9dbe81752a1dbf17-vodlist")
for soup in soups:
vods = soup.find_all('li')
for vod in vods:
name = vod.find('a')['title']
id = vod.find('a')['href']
pic = vod.find('a')['data-original']
if 'http' not in pic:
pic = xurl + pic
remarks = vod.find('a', class_="lazyload")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多推荐▶️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = page
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+325
View File
@@ -0,0 +1,325 @@
# coding = utf-8
# !/usr/bin/python
"""
作者 丢丢喵推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from datetime import datetime
from Crypto.Cipher import AES
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import binascii
import requests
import datetime
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://xifan-api-cn.youlishipin.com"
headerx = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 8.0; DUK-AL20 Build/HUAWEIDUK-AL20; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/044353 Mobile Safari/537.36 MicroMessenger/6.7.3.1360(0x26070333) NetType/WIFI Language/zh_CN Process/tools'
}
pm = ''
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {"class": []}
url = f'{xurl}/xifan/drama/portalPage?reqType=duanjuCategory&version=2001001&androidVersionCode=28'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
if detail.status_code == 200:
data = detail.json()
data = data['result']['elements'][0]['contents']
for vod in data:
categoryItemVo = vod.get('categoryItemVo', {})
subCategories = categoryItemVo.get('subCategories', None)
if subCategories:
continue
oppoCategory = vod['categoryItemVo']['oppoCategory']
categoryId = vod['categoryItemVo']['categoryId']
type_id = str(oppoCategory) + '@' + str(categoryId)
result["class"].append({"type_id": type_id, "type_name": "集多🌠" + oppoCategory})
return result
def homeVideoContent(self):
videos = []
current_timestamp = int(datetime.datetime.now().timestamp())
url = f"{xurl}/xifan/drama/portalPage?reqType=aggregationPage&offset=0&quickEngineVersion=-1&scene=&categoryNames=&categoryVersion=&density=1.5&pageID=page_theater&version=2001001&androidVersionCode=28&requestId={current_timestamp}d4aa487d53e646c2&appId=drama&teenMode=false&userBaseMode=false&session=eyJpbmZvIjp7InVpZCI6IiIsInJ0IjoiMTc0MDY0NjA2MiIsInVuIjoiT1BHXzYzZTYyMTdhZGJhMDQ4NGI5OWNmYTdkOWMyNmU2NTIwIiwiZnQiOiIxNzQwNjQ2MDYyIn19&feedssession=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1dHlwIjowLCJidWlkIjoxNjMzODY1NTEzMDAzNzYyNjg4LCJhdWQiOiJkcmFtYSIsInZlciI6MiwicmF0IjoxNzQwNjQ2MDYyLCJ1bm0iOiJPUEdfNjNlNjIxN2FkYmEwNDg0Yjk5Y2ZhN2Q5YzI2ZTY1MjAiLCJpZCI6Ijg4MmM2M2U3ZDRhYTQ4N2Q1M2U2NDZjMjQxMjg0NTcxIiwiZXhwIjoxNzQxMjUwODYyLCJkYyI6ImJqaHQifQ.zWhF-1Y92_NwuTzUQ_5dNoJwJN8g6UbMfVuH2QrSjjQ"
response = requests.get(url=url, headers=headerx)
if response.status_code == 200:
response_data = response.json()
js = response_data['result']['elements']
for soups in js:
for vod in soups['contents']:
name = vod['duanjuVo']['title']
id = vod['duanjuVo']['duanjuId']
id1 = vod['duanjuVo']['source']
pic = vod['duanjuVo']['coverImageUrl']
remark = "集多▶️推荐"
video = {
"vod_id": id + "#" + id1,
"vod_name": name,
"vod_remarks": remark,
"vod_pic": pic
}
videos.append(video)
result = {'list': videos}
return result
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
fenge = cid.split("@")
page_number = int(pg)
page = (page_number - 1) * 30
current_timestamp = int(datetime.datetime.now().timestamp())
url = f"{xurl}/xifan/drama/portalPage?reqType=aggregationPage&offset={page}&categoryId={fenge[1]}&quickEngineVersion=-1&scene=&categoryNames={fenge[0]}&categoryVersion=1&density=1.5&pageID=page_theater&version=2001001&androidVersionCode=28&requestId={current_timestamp}aa498144140ef297&appId=drama&teenMode=false&userBaseMode=false&session=eyJpbmZvIjp7InVpZCI6IiIsInJ0IjoiMTc0MDY1ODI5NCIsInVuIjoiT1BHXzFlZGQ5OTZhNjQ3ZTQ1MjU4Nzc1MTE2YzFkNzViN2QwIiwiZnQiOiIxNzQwNjU4Mjk0In19&feedssession=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1dHlwIjowLCJidWlkIjoxNjMzOTY4MTI2MTQ4NjQxNTM2LCJhdWQiOiJkcmFtYSIsInZlciI6MiwicmF0IjoxNzQwNjU4Mjk0LCJ1bm0iOiJPUEdfMWVkZDk5NmE2NDdlNDUyNTg3NzUxMTZjMWQ3NWI3ZDAiLCJpZCI6IjNiMzViZmYzYWE0OTgxNDQxNDBlZjI5N2JkMDY5NGNhIiwiZXhwIjoxNzQxMjYzMDk0LCJkYyI6Imd6cXkifQ.JS3QY6ER0P2cQSxAE_OGKSMIWNAMsYUZ3mJTnEpf-Rc"
response = requests.get(url=url, headers=headerx)
if response.status_code == 200:
response_data = response.json()
js = response_data['result']['elements']
for soups in js:
for vod in soups['contents']:
name = vod['duanjuVo']['title']
id = vod['duanjuVo']['duanjuId']
id1 = vod['duanjuVo']['source']
pic = vod['duanjuVo']['coverImageUrl']
remark = "集多▶️推荐"
video = {
"vod_id": id + "#" + id1,
"vod_name": name,
"vod_remarks": remark,
"vod_pic": pic
}
videos.append(video)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = ids[0]
result = {}
videos = []
xianlu = ""
bofang = ""
fenge = did.split("#")
url = f"{xurl}/xifan/drama/getDuanjuInfo?duanjuId={fenge[0]}&source={fenge[1]}&openFrom=homescreen&type=&pageID=page_inner_flow&density=1.5&version=2001001&androidVersionCode=28&requestId=1740658944980aa498144140ef297&appId=drama&teenMode=false&userBaseMode=false&session=eyJpbmZvIjp7InVpZCI6IiIsInJ0IjoiMTc0MDY1ODI5NCIsInVuIjoiT1BHXzFlZGQ5OTZhNjQ3ZTQ1MjU4Nzc1MTE2YzFkNzViN2QwIiwiZnQiOiIxNzQwNjU4Mjk0In19&feedssession=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1dHlwIjowLCJidWlkIjoxNjMzOTY4MTI2MTQ4NjQxNTM2LCJhdWQiOiJkcmFtYSIsInZlciI6MiwicmF0IjoxNzQwNjU4Mjk0LCJ1bm0iOiJPUEdfMWVkZDk5NmE2NDdlNDUyNTg3NzUxMTZjMWQ3NWI3ZDAiLCJpZCI6IjNiMzViZmYzYWE0OTgxNDQxNDBlZjI5N2JkMDY5NGNhIiwiZXhwIjoxNzQxMjYzMDk0LCJkYyI6Imd6cXkifQ.JS3QY6ER0P2cQSxAE_OGKSMIWNAMsYUZ3mJTnEpf-Rc"
response = requests.get(url=url, headers=headerx)
if response.status_code == 200:
response_data = response.json()
content = '集多为您介绍剧情📢' + response_data.get('result', {}).get('desc', '未知')
soup = response_data['result']['episodeList']
for sou in soup:
name = sou['index']
id = sou['playUrl']
bofang = bofang + str(name) + '$' + str(id) + '#'
bofang = bofang[:-1] + '$$$'
bofang = bofang[:-3]
xianlu = '集多短剧专线'
videos.append({
"vod_id": did,
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = id
result["header"] = headerx
return result
def searchContentPage(self, key, quick, page):
result = {}
videos = []
current_timestamp = int(datetime.datetime.now().timestamp())
url = f"{xurl}/xifan/search/getSearchList?keyword={key}84&pageIndex={page}&version=2001001&androidVersionCode=28&requestId={current_timestamp}ea3a14bc0317d76f&appId=drama&teenMode=false&userBaseMode=false&session=eyJpbmZvIjp7InVpZCI6IiIsInJ0IjoiMTc0MDY2ODk4NiIsInVuIjoiT1BHX2U5ODQ4NTgzZmM4ZjQzZTJhZjc5ZTcxNjRmZTE5Y2JjIiwiZnQiOiIxNzQwNjY4OTg2In19&feedssession=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1dHlwIjowLCJidWlkIjoxNjM0MDU3ODE4OTgxNDk5OTA0LCJhdWQiOiJkcmFtYSIsInZlciI6MiwicmF0IjoxNzQwNjY4OTg2LCJ1bm0iOiJPUEdfZTk4NDg1ODNmYzhmNDNlMmFmNzllNzE2NGZlMTljYmMiLCJpZCI6ImVhZGE1NmEyZWEzYTE0YmMwMzE3ZDc2ZmVjODJjNzc3IiwiZXhwIjoxNzQxMjczNzg2LCJkYyI6ImJqaHQifQ.IwuI0gK077RF4G10JRxgxx4GCG502vR8Z0W9EV4kd-c"
response = requests.get(url=url, headers=headerx)
if response.status_code == 200:
response_data = response.json()
js = response_data['result']['elements']
for soups in js:
for vod in soups['contents']:
name = vod['duanjuVo']['title']
cleaned_name = re.sub(r'<tag>|</tag>', '', name)
id = vod['duanjuVo']['duanjuId']
id1 = vod['duanjuVo']['source']
pic = vod['duanjuVo']['coverImageUrl']
remark = "集多▶️推荐"
video = {
"vod_id": id + "#" + id1,
"vod_name": cleaned_name,
"vod_remarks": remark,
"vod_pic": pic
}
videos.append(video)
result['list'] = videos
result['page'] = page
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+202
View File
@@ -0,0 +1,202 @@
# -*- coding: utf-8 -*-
import json
import sys
sys.path.append('..')
from base.spider import Spider
import requests
class Spider(Spider):
def init(self, extend=""):
self.host = 'https://ev5356.970xw.com'
self.headers = {
'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',
'Referer': self.host
}
self.ihost = self.imgsite()
self.skey = ''
self.stype = '3'
def getName(self):
return "JianPian"
def imgsite(self):
data = requests.get(f"{self.host}/api/appAuthConfig", headers=self.headers).json()
host = data['data']['imgDomain']
return f"https://{host}" if not host.startswith('http') else host
def homeContent(self, filter):
classes = [
{'type_id': '1', 'type_name': '电影'},
{'type_id': '2', 'type_name': '电视剧'},
{'type_id': '3', 'type_name': '动漫'},
{'type_id': '4', 'type_name': '综艺'}
]
filterObj = {
"1": [
{"key": "cateId", "name": "分类", "value": [
{"v": "1", "n": "剧情"}, {"v": "2", "n": "爱情"}, {"v": "3", "n": "动画"}, {"v": "4", "n": "喜剧"},
{"v": "5", "n": "战争"}, {"v": "6", "n": "歌舞"}, {"v": "7", "n": "古装"}, {"v": "8", "n": "奇幻"},
{"v": "9", "n": "冒险"}, {"v": "10", "n": "动作"}, {"v": "11", "n": "科幻"}, {"v": "12", "n": "悬疑"},
{"v": "13", "n": "犯罪"}, {"v": "14", "n": "家庭"}, {"v": "15", "n": "传记"}, {"v": "16", "n": "运动"},
{"v": "18", "n": "惊悚"}, {"v": "20", "n": "短片"}, {"v": "21", "n": "历史"}, {"v": "22", "n": "音乐"},
{"v": "23", "n": "西部"}, {"v": "24", "n": "武侠"}, {"v": "25", "n": "恐怖"}
]},
{"key": "area", "name": "地區", "value": [
{"v": "1", "n": "国产"}, {"v": "3", "n": "香港"}, {"v": "6", "n": "台湾"},
{"v": "5", "n": "美国"}, {"v": "18", "n": "韩国"}, {"v": "2", "n": "日本"}
]},
{"key": "year", "name": "年代", "value": [
{"v": "107", "n": "2025"}, {"v": "119", "n": "2024"}, {"v": "153", "n": "2023"},
{"v": "101", "n": "2022"}, {"v": "118", "n": "2021"}, {"v": "16", "n": "2020"},
{"v": "7", "n": "2019"}, {"v": "2", "n": "2018"}, {"v": "3", "n": "2017"},
{"v": "22", "n": "2016"}, {"v": "2015", "n": "2015以前"}
]},
{"key": "sort", "name": "排序", "value": [
{"v": "update", "n": "最新"}, {"v": "hot", "n": "最热"}, {"v": "rating", "n": "评分"}
]}
],
"2": [
{"key": "area", "name": "地區", "value": [
{"v": "1", "n": "国产"}, {"v": "3", "n": "香港"}, {"v": "6", "n": "台湾"},
{"v": "5", "n": "美国"}, {"v": "18", "n": "韩国"}, {"v": "2", "n": "日本"}
]},
{"key": "year", "name": "年代", "value": [
{"v": "107", "n": "2025"}, {"v": "119", "n": "2024"}, {"v": "153", "n": "2023"},
{"v": "101", "n": "2022"}, {"v": "118", "n": "2021"}, {"v": "16", "n": "2020"},
{"v": "7", "n": "2019"}, {"v": "2", "n": "2018"}, {"v": "3", "n": "2017"},
{"v": "22", "n": "2016"}, {"v": "2015", "n": "2015以前"}
]},
{"key": "sort", "name": "排序", "value": [
{"v": "update", "n": "最新"}, {"v": "hot", "n": "最热"}, {"v": "rating", "n": "评分"}
]}
],
"3": [
{"key": "area", "name": "地區", "value": [
{"v": "1", "n": "国产"}, {"v": "3", "n": "香港"}, {"v": "6", "n": "台湾"},
{"v": "5", "n": "美国"}, {"v": "18", "n": "韩国"}, {"v": "2", "n": "日本"}
]},
{"key": "year", "name": "年代", "value": [
{"v": "107", "n": "2025"}, {"v": "119", "n": "2024"}, {"v": "153", "n": "2023"},
{"v": "101", "n": "2022"}, {"v": "118", "n": "2021"}, {"v": "16", "n": "2020"},
{"v": "7", "n": "2019"}, {"v": "2", "n": "2018"}, {"v": "3", "n": "2017"},
{"v": "22", "n": "2016"}, {"v": "2015", "n": "2015以前"}
]},
{"key": "sort", "name": "排序", "value": [
{"v": "update", "n": "最新"}, {"v": "hot", "n": "最热"}, {"v": "rating", "n": "评分"}
]}
],
"4": [
{"key": "area", "name": "地區", "value": [
{"v": "1", "n": "国产"}, {"v": "3", "n": "香港"}, {"v": "6", "n": "台湾"},
{"v": "5", "n": "美国"}, {"v": "18", "n": "韩国"}, {"v": "2", "n": "日本"}
]},
{"key": "year", "name": "年代", "value": [
{"v": "107", "n": "2025"}, {"v": "119", "n": "2024"}, {"v": "153", "n": "2023"},
{"v": "101", "n": "2022"}, {"v": "118", "n": "2021"}, {"v": "16", "n": "2020"},
{"v": "7", "n": "2019"}, {"v": "2", "n": "2018"}, {"v": "3", "n": "2017"},
{"v": "22", "n": "2016"}, {"v": "2015", "n": "2015以前"}
]},
{"key": "sort", "name": "排序", "value": [
{"v": "update", "n": "最新"}, {"v": "hot", "n": "最热"}, {"v": "rating", "n": "评分"}
]}
]
}
return {
'class': classes,
'filters': filterObj
}
def homeVideoContent(self):
url = f"{self.host}/api/slide/list?pos_id=88"
data = requests.get(url, headers=self.headers).json()
videos = [{
'vod_id': item['jump_id'],
'vod_name': item['title'],
'vod_pic': f"{self.ihost}{item['thumbnail']}",
'vod_remarks': "",
'style': json.dumps({"type": "rect", "ratio": 1.33})
} for item in data['data']]
return {'list': videos}
def categoryContent(self, tid, pg, filter, extend):
params = {
'fcate_pid': tid,
'page': pg,
'category_id': extend.get('cateId', ''),
'area': extend.get('area', ''),
'year': extend.get('year', ''),
'type': extend.get('cateId', ''),
'sort': extend.get('sort', '')
}
url = f"{self.host}/api/crumb/list"
data = requests.get(url, params=params, headers=self.headers).json()
videos = [{
'vod_id': item['id'],
'vod_name': item['title'],
'vod_pic': f"{self.ihost}{item['path']}",
'vod_remarks': item['mask'],
'vod_year': ""
} for item in data['data']]
return {
'list': videos,
'page': pg,
'pagecount': 99999,
'limit': 15,
'total': 99999
}
def detailContent(self, ids):
id = ids[0]
url = f"{self.host}/api/video/detailv2?id={id}"
data = requests.get(url, headers=self.headers).json()
res = data['data']
play_from = ['老僧酿酒、边酿边播']
play_url = []
# 寻找并处理“常规线路”
for source in res.get('source_list_source', []):
if source['name'] == '常规线路':
parts = [f"{part.get('source_name', part.get('weight', ''))}${part['url']}" for part in source.get('source_list', [])]
play_url.append('#'.join(parts))
break # 找到后立即退出循环
vod = {
'vod_id': id,
'type_name': '/'.join([t['name'] for t in res.get('types', [])]),
'vod_year': res.get('year', ''),
'vod_area': res.get('area', ''),
'vod_remarks': res.get('mask', ''),
'vod_content': res.get('description', ''),
'vod_play_from': '$$$'.join(play_from),
'vod_play_url': '$$$'.join(play_url)
}
return {'list': [vod]}
def playerContent(self, flag, id, vipFlags):
if ".m3u8" in id:
return {'parse': 0, 'url': id}
else:
return {'parse': 0, 'url': f"tvbox-xg:{id}"}
def searchContent(self, key, quick, pg="1"):
url = f"{self.host}/api/v2/search/videoV2"
params = {'key': key, 'category_id': 88, 'page': pg, 'pageSize': 20}
data = requests.get(url, params=params, headers=self.headers).json()
videos = [{
'vod_id': item['id'],
'vod_name': item['title'],
'vod_pic': f"{self.ihost}{item['thumbnail']}",
'vod_remarks': item.get('mask', ''),
'vod_year': ""
} for item in data['data']]
return {
'list': videos,
'limit': 20
}
def isVideoFormat(self, url): pass
def manualVideoCheck(self): pass
def destroy(self): pass
def localProxy(self, param): pass
def liveContent(self, url): pass
+387
View File
@@ -0,0 +1,387 @@
# coding=utf-8
# !/usr/bin/python
"""
作者 丢丢喵 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from datetime import datetime
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import datetime
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://api.xingzhige.com" # 首页 http://play.ruanyazyk.com/drama.html
headerx = {
'User-Agent': 'Mozilla/5.0 (Linux; U; Android 8.0.0; zh-cn; Mi Note 2 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.1.1'
}
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "战神", "type_name": "集多🌠战神"},
{"type_id": "逆袭", "type_name": "集多🌠逆袭"},
{"type_id": "人物", "type_name": "集多🌠人物"},
{"type_id": "都市", "type_name": "集多🌠都市"},
{"type_id": "擦边", "type_name": "集多🌠擦边"},
{"type_id": "人妖", "type_name": "集多🌠人妖"},
{"type_id": "闪婚", "type_name": "集多🌠闪婚"}, {"type_id": "古装", "type_name": "集多🌠古装"},
{"type_id": "霸总", "type_name": "集多🌠霸总"},
{"type_id": "强者", "type_name": "集多🌠强者"},
{"type_id": "玄幻", "type_name": "集多🌠玄幻"},
{"type_id": "都市", "type_name": "集多🌠都市"},
{"type_id": "神豪", "type_name": "集多🌠神豪"},
{"type_id": "现代", "type_name": "集多🌠现代"},
{"type_id": "爱情", "type_name": "集多🌠爱情"},
{"type_id": "虐渣", "type_name": "集多🌠虐渣"},
{"type_id": "总裁", "type_name": "集多🌠总裁"},
{"type_id": "无敌", "type_name": "集多🌠无敌"},
{"type_id": "奇幻", "type_name": "集多🌠奇幻"}],
}
return result
def homeVideoContent(self):
videos = []
url = f"{xurl}/API/playlet/?keyword=擦边&page=1"
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
if detail.status_code == 200:
data = detail.text
items = re.split(r'\{', data)
for item in items:
if not item.strip().endswith('}'):
item += '}'
book_id = re.search(r'"book_id":\s*"(.*?)"', item)
title = re.search(r'"title":\s*"(.*?)"', item)
author = re.search(r'"author":\s*"(.*?)"', item)
type_ = re.search(r'"type":\s*"(.*?)"', item)
cover = re.search(r'"cover":\s*"(.*?)"', item)
remark = re.search(r'"category_schema":\s*"(.*?)"', item)
desc = re.search(r'"desc":\s*"(.*?)"', item)
if book_id and title and author and type_ and cover and remark and desc:
book_id = book_id.group(1)
title = title.group(1)
author = author.group(1)
type_ = type_.group(1)
cover = cover.group(1)
remark = remark.group(1)
desc = desc.group(1)
vod_id = f"{author}@{type_}@{desc}@{book_id}"
video = {
"vod_id": vod_id,
"vod_name": title,
"vod_pic": cover,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
return result
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
url = f"{xurl}/API/playlet/?keyword={cid}&page={str(page)}"
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
if detail.status_code == 200:
data = detail.text
items = re.split(r'\{', data)
for item in items:
if not item.strip().endswith('}'):
item += '}'
book_id = re.search(r'"book_id":\s*"(.*?)"', item)
title = re.search(r'"title":\s*"(.*?)"', item)
author = re.search(r'"author":\s*"(.*?)"', item)
type_ = re.search(r'"type":\s*"(.*?)"', item)
cover = re.search(r'"cover":\s*"(.*?)"', item)
remark = re.search(r'"category_schema":\s*"(.*?)"', item)
desc = re.search(r'"desc":\s*"(.*?)"', item)
if book_id and title and author and type_ and cover and remark and desc:
book_id = book_id.group(1)
title = title.group(1)
author = author.group(1)
type_ = type_.group(1)
cover = cover.group(1)
remark = remark.group(1)
desc = desc.group(1)
vod_id = f"{author}@{type_}@{desc}@{book_id}"
video = {
"vod_id": vod_id,
"vod_name": title,
"vod_pic": cover,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = ids[0]
result = {}
videos = []
xianlu = ''
bofang = ''
fenge = did.split("@")
url = 'http://rihou.cc:88/je.json'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
content = '集多为您介绍剧情📢' + fenge[2]
actor = fenge[0]
remarks = fenge[1]
if name not in content:
bofang = Jumps
xianlu = '1'
else:
url = f"{xurl}/API/playlet/?book_id={fenge[3]}"
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
if detail.status_code == 200:
detail = detail.json()
soup = detail['data']['video_list']
for sou in soup:
id = sou['video_id']
name = sou['title']
bofang = bofang + name + '$' + id + '#'
bofang = bofang[:-1]
xianlu = '集多专线'
videos.append({
"vod_id": did,
"vod_actor": actor,
"vod_remarks": remarks,
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
url = f"{xurl}/API/playlet/?video_id={id}&quality=1080p"
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
if detail.status_code == 200:
detail = detail.json()
url = detail['data']['video']['url']
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
return result
def searchContentPage(self, key, quick, pg):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
url = f"{xurl}/API/playlet/?keyword={key}&page={str(page)}"
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
if detail.status_code == 200:
data = detail.text
items = re.split(r'\{', data)
for item in items:
if not item.strip().endswith('}'):
item += '}'
book_id = re.search(r'"book_id":\s*"(.*?)"', item)
title = re.search(r'"title":\s*"(.*?)"', item)
author = re.search(r'"author":\s*"(.*?)"', item)
type_ = re.search(r'"type":\s*"(.*?)"', item)
cover = re.search(r'"cover":\s*"(.*?)"', item)
remark = re.search(r'"category_schema":\s*"(.*?)"', item)
desc = re.search(r'"desc":\s*"(.*?)"', item)
if book_id and title and author and type_ and cover and remark and desc:
book_id = book_id.group(1)
title = title.group(1)
author = author.group(1)
type_ = type_.group(1)
cover = cover.group(1)
remark = remark.group(1)
desc = desc.group(1)
vod_id = f"{author}@{type_}@{desc}@{book_id}"
video = {
"vod_id": vod_id,
"vod_name": title,
"vod_pic": cover,
"vod_remarks": '集多️▶️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+260
View File
@@ -0,0 +1,260 @@
import requests
from bs4 import BeautifulSoup
import re
import json
from urllib.parse import urljoin, quote
import sys
sys.path.append('..')
from base.spider import Spider
xurl = "http://m.padest.com/"
headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 13; M2102J2SC Build/TKQ1.221114.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/144.0.7559.31 Mobile Safari/537.36',
'Referer': xurl,
}
class Spider(Spider):
def getName(self):
return "达达兔影院"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def homeContent(self, filter):
return {
"class": [
{"type_id": "17", "type_name": "犯罪片"},
{"type_id": "6", "type_name": "喜剧片"},
{"type_id": "5", "type_name": "动作片"},
{"type_id": "7", "type_name": "爱情片"},
{"type_id": "8", "type_name": "科幻片"},
{"type_id": "9", "type_name": "恐怖片"},
{"type_id": "10", "type_name": "剧情片"},
{"type_id": "11", "type_name": "战争片"},
{"type_id": "12", "type_name": "惊悚片"},
{"type_id": "13", "type_name": "家庭片"},
{"type_id": "14", "type_name": "古装片"},
{"type_id": "15", "type_name": "历史片"},
{"type_id": "16", "type_name": "悬疑片"},
{"type_id": "18", "type_name": "灾难片"},
{"type_id": "19", "type_name": "记录片"},
{"type_id": "20", "type_name": "动画片"},
{"type_id": "21", "type_name": "理论"},
{"type_id": "39", "type_name": "日韩"},
{"type_id": "22", "type_name": "国产剧"},
{"type_id": "23", "type_name": "香港剧"},
{"type_id": "24", "type_name": "韩国剧"},
{"type_id": "25", "type_name": "欧美剧"},
{"type_id": "26", "type_name": "台湾剧"},
{"type_id": "27", "type_name": "日本剧"},
{"type_id": "28", "type_name": "海外剧"},
{"type_id": "29", "type_name": "泰国剧"},
{"type_id": "30", "type_name": "短剧"},
{"type_id": "31", "type_name": "大陆综艺"},
{"type_id": "32", "type_name": "港台综艺"},
{"type_id": "33", "type_name": "日韩综艺"},
{"type_id": "34", "type_name": "欧美综艺"},
{"type_id": "35", "type_name": "国产动漫"},
{"type_id": "36", "type_name": "欧美动漫"},
{"type_id": "37", "type_name": "日本动漫"},
{"type_id": "38", "type_name": "里番动漫"},
],
"filters": {}
}
def _parse_video_items(self, soup):
videos = []
for li in soup.select('div.col-xs-4'):
a = li.select_one('p.video-name a')
if not a:
continue
href = a.get('href')
name = a.get('title')
pic = li.select_one('a.video-img.lazyload')
pic = pic.get('data-original', '') if pic else ''
if pic and not pic.startswith('http'):
pic = urljoin(xurl, pic)
remark = li.select_one('header.video-header span.video-title')
remark = remark.get_text(strip=True) if remark else ''
if href and name:
videos.append({
"vod_id": urljoin(xurl, href),
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remark
})
return videos
def homeVideoContent(self):
resp = requests.get(xurl, headers=headers, timeout=10)
soup = BeautifulSoup(resp.text, 'lxml')
return {'list': self._parse_video_items(soup)}
def categoryContent(self, cid, pg, filter, ext):
page = int(pg) if pg else 1
if page == 1:
url = f"{xurl}/tvshow/{cid}.html"
else:
url = f"{xurl}/tvshow/{cid}.html?page={page}"
resp = requests.get(url, headers=headers, timeout=10)
return {
'list': self._parse_video_items(BeautifulSoup(resp.text, 'lxml')),
'page': page,
'pagecount': page + 1,
'limit': 90,
'total': 9999
}
def detailContent(self, ids):
did = ids[0]
if not did.startswith('http'):
did = urljoin(xurl, did)
resp = requests.get(did, headers=headers, timeout=10)
soup = BeautifulSoup(resp.text, 'lxml')
info = {'vod_id': did}
thumb = soup.select_one('.block-fea.lazyload')
if thumb:
pic = thumb.get('data-original') or thumb.get('src', '')
if pic and pic.startswith('//'):
pic = 'https:' + pic
elif pic and not pic.startswith('http'):
pic = urljoin(xurl, pic)
info['vod_pic'] = pic
detail_div = soup.select_one('.detail-info')
if detail_div:
title_h1 = detail_div.select_one('h1.detail-info-title a')
if title_h1:
raw_title = title_h1.get_text(strip=True).replace('\n', '')
info['vod_name'] = raw_title
for p in detail_div.select('p'):
text = p.get_text(strip=True)
if '演员:' in text:
info['vod_actor'] = text.split('演员:')[-1].strip()
if '类型:' in text:
info['type_name'] = text.split('类型:')[-1].strip()
if '导演:' in text:
info['vod_director'] = text.split('导演:')[-1].strip()
if '状态:' in text:
info['vod_remarks'] = text.split('状态:')[-1].strip()
if '年份:' in text:
info['vod_year'] = text.split('年份:')[-1].strip()
if '地区:' in text:
info['vod_area'] = text.split('地区:')[-1].strip()
content_div = soup.select_one('.show_text .entry-content')
if content_div:
p = content_div.find('p')
if p:
text = p.get_text(strip=True)
info['vod_content'] = text.strip()
else:
info['vod_content'] = content_div.get_text(strip=True)
else:
info['vod_content'] = ''
tabs = soup.select('.ewave-tab a')
playlists = soup.select('.ewave-playlist-content')
play_from = []
play_url = []
seen = set()
for i, tab in enumerate(tabs):
if i >= len(playlists):
break
name = tab.get_text(strip=True)
name = re.sub(r'\s*\d+$', '', name).strip()
if name in ['猜您喜欢', '同类型', '同主演', ''] or name in seen:
continue
seen.add(name)
eps = []
for a in playlists[i].select('li a'):
href = a.get('href')
ep_title = a.get_text(strip=True)
if href and '1080P' not in ep_title:
if not href.startswith('http'):
href = urljoin(xurl, href)
eps.append(f"{ep_title}${href}")
if eps:
play_from.append(name)
play_url.append('#'.join(eps))
info["vod_play_from"] = '$$$'.join(play_from)
info["vod_play_url"] = '$$$'.join(play_url)
return {'list': [info]}
def searchContent(self, key, quick, page='1'):
page = int(page) if page else 1
url = f"{xurl}/wd={key}&page={page}"
resp = requests.get(url, headers=headers, timeout=10)
soup = BeautifulSoup(resp.text, 'lxml')
return {
'list': self._parse_video_items(soup),
'page': page,
'pagecount': page + 1,
'limit': 90,
'total': 9999
}
def playerContent(self, flag, id, vipFlags):
try:
play_url = id if id.startswith('http') else urljoin(xurl, id)
resp = requests.get(play_url, headers=headers, timeout=10)
html = resp.text
video_url = None
iframe_pattern = r'<iframe[^>]+src=["\']([^"\']+)["\']'
matches = re.findall(iframe_pattern, html)
for match in matches:
if match.startswith('http') and ('.m3u8' in match or '.mp4' in match):
video_url = match
break
if not video_url:
video_pattern = r'<video[^>]+src=["\']([^"\']+)["\']'
v_match = re.search(video_pattern, html)
if v_match:
video_url = v_match.group(1)
else:
var_pattern = r'var\s+player\w*\s*=\s*({[^;]+})'
var_match = re.search(var_pattern, html)
if var_match:
try:
config = json.loads(var_match.group(1).replace("'", '"'))
video_url = config.get('url', '')
except:
pass
if not video_url:
url_match = re.search(r'"url":"([^"]+)"', html)
if url_match:
video_url = url_match.group(1)
if video_url:
if not video_url.startswith('http'):
video_url = urljoin(play_url, video_url)
if re.search(r'\.(m3u8|mp4|mkv)', video_url, re.I):
parse = 0
else:
parse = 1
return {"parse": parse, "playUrl": "", "url": video_url, "header": headers}
else:
return {"parse": 1, "playUrl": "", "url": play_url, "header": headers}
except Exception as e:
print(f"playerContent error: {e}")
return {"parse": 1, "playUrl": "", "url": urljoin(xurl, id), "header": headers}
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
if params['type'] == "media":
return self.proxyMedia(params)
if params['type'] == "ts":
return self.proxyTs(params)
return None
+343
View File
@@ -0,0 +1,343 @@
# coding=utf-8
# !/usr/bin/python
"""
作者 丢丢喵推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from datetime import datetime
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import datetime
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://api.jinlidj.com"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
headers = {
'Host': 'player.jinlidj.com',
'Connection': 'keep-alive',
'Pragma': 'no-cache',
'Cache-Control': 'no-cache',
'sec-ch-ua': '"Microsoft Edge";v="129", "Not=A?Brand";v="8", "Chromium";v="129"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Sec-Fetch-Site': 'same-site',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-User': '?1',
'Sec-Fetch-Dest': 'iframe',
'Referer': 'https://www.jinlidj.com/',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'Accept-Encoding': 'gzip, deflate'
}
class Spider(Spider):
global xurl
global headerx
global headers
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def fetch_search(self, payload):
videos = []
urlz = f'{xurl}/api/search'
response = requests.post(url=urlz, headers=headerx, json=payload)
data = response.json()
data = data['data']['list']
for vod in data:
name = vod['vod_name']
id = vod['vod_id']
pic = vod['vod_pic']
remark = vod['vod_time']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
return videos
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "1", "type_name": "集多🌠情感关系"},
{"type_id": "2", "type_name": "集多🌠成长逆袭"},
{"type_id": "3", "type_name": "集多🌠奇幻异能"},
{"type_id": "4", "type_name": "集多🌠战斗热血"},
{"type_id": "5", "type_name": "集多🌠伦理现实"},
{"type_id": "6", "type_name": "集多🌠时空穿越"},
{"type_id": "7", "type_name": "集多🌠谋权身份"}],
}
return result
def homeVideoContent(self):
payload = {
"page": 1,
"limit": 24,
"type_id": "",
"year": "",
"keyword": ""
}
videos = self.fetch_search(payload)
result = {'list': videos}
return result
def categoryContent(self, cid, pg, filter, ext):
result = {}
if pg:
page = int(pg)
else:
page = 1
payload = {
"page": str(page),
"limit": 24,
"type_id": cid,
"year": "",
"keyword": ""
}
videos = self.fetch_search(payload)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = ids[0]
result = {}
videos = []
xianlu = ''
bofang = ''
payload = {}
urlz = f'{xurl}/api/detail/{did}'
response = requests.post(url=urlz, headers=headerx, json=payload)
data = response.json()
url = 'http://rihou.cc:88/je.json'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
content = '集多🎉为您介绍剧情📢' + data['data']['vod_blurb'] or "未知"
director = data['data']['vod_director'] or "未知"
actor = data['data']['vod_actor'] or "未知"
remarks = data['data']['vod_tag'] or "未知"
year = data['data']['vod_year'] or "未知"
area = data['data']['vod_area'] or "未知"
if name not in content:
bofang = Jumps
xianlu = '1'
else:
soups = data['data']['player']
for sou in soups.items():
id = sou[1]
name = sou[0]
bofang = bofang + name + '$' + id + '#'
bofang = bofang[:-1]
xianlu = '集多短剧专线'
videos.append({
"vod_id": did,
"vod_director": director,
"vod_actor": actor,
"vod_remarks": remarks,
"vod_year": year,
"vod_area": area,
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
url1 = f"{id}&auto=1"
detail = requests.get(url=url1, headers=headers)
detail.encoding = "utf-8"
res = detail.text
url = self.extract_middle_text(res, '"url":"', '"', 0)
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
return result
def searchContentPage(self, key, quick, pg):
result = {}
if pg:
page = int(pg)
else:
page = 1
payload = {
"page": str(page),
"limit": 24,
"type_id": "",
"keyword": key
}
videos = self.fetch_search(payload)
result['list'] = videos
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+367
View File
@@ -0,0 +1,367 @@
# coding=utf-8
# !/usr/bin/python
"""
作者 丢丢喵推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from datetime import datetime
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import datetime
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "http://www.jibai5.com"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "22", "type_name": "集多🌠沙雕剧场"}]}
return result
def homeVideoContent(self):
videos = []
detail = requests.get(url=xurl, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('ul', class_="boxlist clearfix")
for soup in soups:
vods = soup.find_all('li')
for vod in vods:
remarks = vod.find('div', class_="duration")
remark = remarks.text.strip()
if "沙雕" not in remark:
continue
name = vod.find('a')['title']
id = vod.find('a')['href']
pic = vod.find('img')['src']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
return result
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
if page == 1:
url = f'{xurl}/vodtype/{cid}.html'
else:
url = f'{xurl}/vodtype/{cid}-{str(page)}.html'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('ul', class_="boxlist clearfix")
for soup in soups:
vods = soup.find_all('li')
for vod in vods:
name = vod.find('a')['title']
id = vod.find('a')['href']
pic = vod.find('img')['src']
remarks = vod.find('div', class_="duration")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = ids[0]
result = {}
videos = []
xianlu = ''
bofang = ''
if 'http' not in did:
did = xurl + did
res = requests.get(url=did, headers=headerx)
res.encoding = "utf-8"
res = res.text
url = 'http://rihou.cc:88/je.json'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
content = '😸集多为您介绍剧情📢' + self.extract_middle_text(res,'剧情:<p>','<', 0)
director = self.extract_middle_text(res, '导演:', '</dl>',1,'<span>(.*?)</span>')
actor = self.extract_middle_text(res, '主演:', '</dl>',1,'<span>(.*?)</span>')
remarks = self.extract_middle_text(res, '时长:', '</dl>',1,'<span>(.*?)</span>')
year = self.extract_middle_text(res, '年代:', '</dl>',1,'<span>(.*?)</span>')
area = "大陆"
if name not in content:
bofang = Jumps
xianlu = '1'
else:
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('ul', class_="dslist-group clearfix")
for soup in soups:
vods = soup.find_all('li')
for sou in vods:
name = sou.find('a')['title']
id = sou.find('a')['href']
if 'http' not in id:
id = xurl + id
bofang = bofang + name + '$' + id + '#'
bofang = bofang[:-1]
xianlu = '沙雕动漫专线'
videos.append({
"vod_id": did,
"vod_director": director,
"vod_actor": actor,
"vod_remarks": remarks,
"vod_year": year,
"vod_area": area,
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
res = requests.get(url=id, headers=headerx)
res.encoding = "utf-8"
res = res.text
url = self.extract_middle_text(res, '},"url":"', '"', 0).replace('\\', '')
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
return result
def searchContentPage(self, key, quick, pg):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
url = f'{xurl}/vodsearch/-------------.html?wd={key}'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('ul', class_="boxlist clearfix")
for item in soups:
vods = item.find_all('li')
for vod in vods:
remarks = vod.find('div', class_="duration")
remark = remarks.text.strip()
if "沙雕" not in remark:
continue
name = vod.find('a')['title']
id = vod.find('a')['href']
pic = vod.find('img')['src']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+336
View File
@@ -0,0 +1,336 @@
import requests
from bs4 import BeautifulSoup
import re
from base.spider import Spider
import sys
import json
import base64
import urllib.parse
sys.path.append('..')
xurl = "https://www.qlys.cc"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def homeContent(self, filter):
result = {}
result = {"class": [
{"type_id": "1", "type_name": "电影"},
{"type_id": "2", "type_name": "连续剧"},
{"type_id": "3", "type_name": "综艺"},
{"type_id": "4", "type_name": "动漫"},
{"type_id": "5", "type_name": "短剧"},
{"type_id": "46", "type_name": "少儿"}
]}
return result
def homeVideoContent(self):
#请求数据
源码 = BeautifulSoup(requests.get(url=xurl, headers=headerx).text, "lxml")
#print(源码)
# 查找所有视频列表
二次截取 = 源码.find_all('div', class_="public-list-box")
# 遍历数据
videos = []
for 数组 in 二次截取:
数组 = 数组.find_all('div', class_="public-list-div")
#print(数组)
# 遍历数据
for 数组 in 数组:
# 获取标题
标题 = 数组.find('a')['title']
#print(标题)
# 获取链接
链接 = 数组.find('a')['href']
#print(链接)
# 获取封面
图片 = 数组.find('img')['data-src']
if 'http' not in 图片:
图片 = xurl + 图片 # 补全封面URL
#print(图片)
# 获取副标题
副标题 = 数组.find('span', class_="public-list-prb hide ft2")
副标题 = 副标题.text.strip()
#print(副标题)
video = {
"vod_id": 链接,
"vod_name": 标题,
"vod_pic": 图片,
"vod_remarks": 副标题
}
videos.append(video)
#print(video)
result = {'list': videos}
return result
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
if page == '1':
url = f'{xurl}/index.php/vod/type/id/{cid}/1.html'
else:
url = f'{xurl}/index.php/vod/type/id/{cid}/page/{page}.html'
#请求数据
源码 = BeautifulSoup(requests.get(url=url, headers=headerx).text, "lxml")
#print(源码)
# 查找所有视频列表
二次截取 = 源码.find_all('div', class_="public-list-box")
# 遍历数据
videos = []
for 数组 in 二次截取:
数组 = 数组.find_all('div', class_="public-list-div")
#print(数组)
# 遍历数据
for 数组 in 数组:
# 获取标题
标题 = 数组.find('a')['title']
#print(标题)
# 获取链接
链接 = 数组.find('a')['href']
#print(链接)
# 获取封面
图片 = 数组.find('img')['data-src']
if 'http' not in 图片:
图片 = xurl + 图片 # 补全封面URL
#print(图片)
# 获取副标题
副标题 = 数组.find('span', class_="public-list-prb hide ft2")
副标题 = 副标题.text.strip()
#print(副标题)
video = {
"vod_id": 链接,
"vod_name": 标题,
"vod_pic": 图片,
"vod_remarks": 副标题
}
videos.append(video)
#print(video)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 99
result['limit'] = 90
result['total'] = 99
return result
def detailContent(self, ids):
global pm
did = ids[0]
result = {}
videos = []
playurl = ''
if 'http' not in did:
did = xurl + did
# 请求详情页
源码 = BeautifulSoup(requests.get(url=did, headers=headerx).text, "lxml")
# 初始化VOD字典
vod = {}
# ========== 提取视频基本信息 ==========
#视频ID
vod["vod_id"] = xurl
# 标题
vod["vod_name"] = 源码.select_one('div.this-desc-title').get_text()
# 类型
vod["type_name"] = 源码.select_one('.this-desc-tags').get_text().replace('类型:', '').replace('/', ' ').strip()
# 封面图
vod["vod_pic"] = 源码.select_one('.lazy').get('data-src', '').replace('', '').strip()
# 备注
vod["vod_remarks"] = 源码.select_one('.this-desc-info').get_text().replace('更新:', '').strip()
# 简介
vod["vod_content"] = 源码.select_one('.this-desc').get_text().replace('描述:', '').strip()
# ========== 提取播放列表 ==========
# 提取播放源标签
ktabs = []
线路数组 = 源码.select('.anthology-tab .swiper-wrapper a')
for XL in 线路数组:
线路标题 = XL.get_text()
线路标题 = re.sub(r'\s*\d+$', '', 线路标题).strip()
ktabs.append(线路标题)
vod["vod_play_from"] = '$$$'.join(ktabs)
# 提取播放列表
klists = []
播放数组 = 源码.select('.anthology-list-play')
for BF in 播放数组:
播放列表 = BF.select('a')
klist = []
for LB in 播放列表:
播放标题 = LB.get_text()
播放链接 = LB.get('href', '')
剧集 = f'{播放标题}${播放链接}'
klist.append(剧集)
# 用#连接同一播放源的剧集
klists.append('#'.join(klist))
# 用$$$连接不同播放源
vod["vod_play_url"] = '$$$'.join(klists)
result = {'list': [vod]}
#print(result)
return result
def playerContent(self, flag, id, vipFlags):
result = {}
try:
# 第一步:尝试提取直链播放
源码 = BeautifulSoup(requests.get(url=xurl + id, headers=headerx).text, "lxml")
url = re.search(r'var\s+now\s*=\s*"([^"]+)"', str(源码)).group(1)
# 正则提取成功,使用直链播放
result["parse"] = 0
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
except (AttributeError, Exception):
# 提取失败(正则未匹配到或请求异常),使用嗅探播放
result["parse"] = 1
result["playUrl"] = ''
result["url"] = xurl + id
result["header"] = headerx
return result
def searchContentPage(self, key, quick, page):
result = {}
videos = []
if not page:
page = '1'
if page == '1':
url = f'{xurl}/index.php/vod/search.html?wd={key}'
else:
url = f'{xurl}/index.php/vod/search/page/{page}/wd/{key}.html'
源码 = BeautifulSoup(requests.get(url=url, headers=headerx).text, "lxml")
#print(源码)
# 查找所有视频列表
二次截取 = 源码.find_all('div', class_="public-list-box")
# 遍历数据
videos = []
for 数组 in 二次截取:
数组 = 数组.find_all('div', class_="public-list-div")
#print(数组)
# 遍历数据
for 数组 in 数组:
# 获取标题
标题 = 数组.find('a')['title']
#print(标题)
# 获取链接
链接 = 数组.find('a')['href']
#print(链接)
# 获取封面
图片 = 数组.find('img')['data-src']
if 'http' not in 图片:
图片 = xurl + 图片 # 补全封面URL
#print(图片)
# 获取副标题
副标题 = 数组.find('span', class_="public-list-prb hide ft2")
副标题 = 副标题.text.strip()
#print(副标题)
video = {
"vod_id": 链接,
"vod_name": 标题,
"vod_pic": 图片,
"vod_remarks": 副标题
}
videos.append(video)
#print(video)
result = {'list': videos}
result['page'] = page
result['pagecount'] = 60
result['limit'] = 30
result['total'] = 999999
return result
def searchContent(self, key, quick, page='1'):
return self.searchContentPage(key, quick, page)
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
if __name__ == "__main__":
spider = Spider()
spider.init("")
# 调用首页视频内容测试
#result = spider.homeVideoContent()
#print("首页视频内容测试结果:")
#print(result)
# 调用分类内容测试
#category_result = spider.categoryContent("1", "1", {}, {})
#print("\n分类内容测试结果:")
#print(category_result)
# 调用详情内容测试
#detail_result = spider.detailContent(["/hanjuzaixian/4375.html"])
#print("\n详情内容测试结果:")
#print(detail_result)
# 调用播放内容测试
player_result = spider.playerContent("m3u8", "/play/4375-1-0.html", {})
#print("\n播放内容测试结果:")
print(player_result)
# 调用搜索内容测试
#search_result = spider.searchContent("橘子果酱", False)
# print("\n搜索内容测试结果:")
#print(search_result)