Sync all projects
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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'))
|
||||
@@ -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'))
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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.
@@ -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)
|
||||
@@ -0,0 +1,354 @@
|
||||
var iil = 'jsjiami.com.v6',
|
||||
iil_ = ['iil'],
|
||||
lIIIl1ll = [iil, '\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
|
||||
};;
|
||||
iil = 'jsjiami.com.v6';
|
||||
@@ -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}'}
|
||||
|
||||
@@ -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, ""]
|
||||
@@ -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}×tamp={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'))
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user