# -*- coding: utf-8 -*-
# by @Qist
"""
厂长资源 (4kcz.com) - 在线超清播放
"""
import re
import json
import base64
import requests
from urllib.parse import quote, unquote
from base.spider import Spider
try:
from Crypto.Cipher import AES
except ImportError:
AES = None
class Spider(Spider):
def getName(self):
return '厂长资源'
def init(self, extend=""):
self.host = 'https://www.4kcz.com'
if extend and extend.strip():
try:
r = requests.get(extend.strip(), headers={'User-Agent': 'Mozilla/5.0'}, timeout=15)
m = re.search(r'推荐访问]+>', '', html)).strip()
def _parse_videos(self, html):
"""解析 .bt_img.mi_ne_kd ul li 视频列表"""
videos = []
seen = set()
block = re.search(r'class="bt_img[^"]*mi_ne_kd[^"]*"[^>]*>(.*?)', html, re.S)
if not block:
return videos
for li in re.findall(r']+(?:data-original|src)="([^"]+)"', li)
if pm:
pic = pm.group(1)
remarks = ''
rm = re.search(r'class="jidi[^"]*"[^>]*>\s*]*>([^<]*)', li, re.S) \
or re.search(r'class="hdinfo[^"]*"[^>]*>\s*]*>([^<]*)', li, re.S)
if rm:
remarks = rm.group(1).strip()
mid = re.search(r'/movie/(\d+)\.html$', url)
videos.append({
'vod_id': mid.group(1) if mid else url,
'vod_name': name,
'vod_pic': pic,
'vod_remarks': remarks,
})
return videos
# ------------------------------------------------------------------ #
# 首页
# ------------------------------------------------------------------ #
def homeContent(self, filter):
result = {'class': [], 'list': []}
resp = self._safe_get(self.host + '/')
if not resp:
return result
html = resp.text
# 分类:导航菜单 + 常用细分分类
nav = re.search(r'class="navlist[^"]*"[^>]*>(.*?)', html, re.S)
if nav:
for a in re.findall(r']+href="([^"]+)"[^>]*>(.*?)', nav.group(1), re.S):
url, name = a[0], self._strip_tags(a[1])
if not name or name == '首页' or not url.startswith('/'):
continue
result['class'].append({'type_name': name, 'type_id': url.lstrip('/')})
# 补充细分分类(电影/剧集等)
for name, cid in [
('电影', 'movie_bt_series/dyy'), ('电视剧', 'movie_bt_series/dianshiju'),
('动画', 'movie_bt_series/dohua'), ('国产剧', 'movie_bt_series/guochanju'),
('日剧', 'movie_bt_series/rj'), ('韩剧', 'movie_bt_series/hj'),
('美剧', 'movie_bt_series/mj'), ('华语电影', 'movie_bt_series/huayudianying'),
('欧美电影', 'movie_bt_series/meiguodianying'), ('日本电影', 'movie_bt_series/ribendianying'),
('韩国电影', 'movie_bt_series/hanguodianying'),
]:
if not any(c['type_id'] == cid for c in result['class']):
result['class'].append({'type_name': name, 'type_id': cid})
# 首页推荐(取分类页 20 条)
cat = self._safe_get(f'{self.host}/movie_bt/')
if cat:
result['list'] = self._parse_videos(cat.text)[:20]
else:
result['list'] = self._parse_videos(html)[:20]
if filter and result['class']:
# 类型/分类筛选(movie_bt 主分类,按站点标签)
result['filters'] = {
'movie_bt': [
{'key': 'class', 'name': '类型', 'value': [
{'n': '全部', 'v': ''}, {'n': '动作', 'v': '/movie_bt_tags/dozuo'},
{'n': '喜剧', 'v': '/movie_bt_tags/xiju'}, {'n': '爱情', 'v': '/movie_bt_tags/aiqing'},
{'n': '科幻', 'v': '/movie_bt_tags/kh'}, {'n': '剧情', 'v': '/movie_bt_tags/juqing'},
{'n': '恐怖', 'v': '/movie_bt_tags/kubu'}, {'n': '悬疑', 'v': '/movie_bt_tags/xuanyi'},
{'n': '动画', 'v': '/movie_bt_tags/dhh'}, {'n': '纪录片', 'v': '/movie_bt_tags/jlpp'},
{'n': '战争', 'v': '/movie_bt_tags/zhanzhen'}, {'n': '武侠', 'v': '/movie_bt_tags/wuxia'},
{'n': '犯罪', 'v': '/movie_bt_tags/fanzui'}, {'n': '奇幻', 'v': '/movie_bt_tags/qihuan'},
]},
{'key': 'area', 'name': '分类', 'value': [
{'n': '全部', 'v': ''}, {'n': '电影', 'v': '/movie_bt_series/dyy'},
{'n': '电视剧', 'v': '/movie_bt_series/dianshiju'}, {'n': '动画', 'v': '/movie_bt_series/dohua'},
{'n': '国产剧', 'v': '/movie_bt_series/guochanju'}, {'n': '美剧', 'v': '/movie_bt_series/mj'},
{'n': '日剧', 'v': '/movie_bt_series/rj'}, {'n': '韩剧', 'v': '/movie_bt_series/hj'},
{'n': '华语电影', 'v': '/movie_bt_series/huayudianying'},
{'n': '欧美电影', 'v': '/movie_bt_series/meiguodianying'},
{'n': '日本电影', 'v': '/movie_bt_series/ribendianying'},
{'n': '韩国电影', 'v': '/movie_bt_series/hanguodianying'},
{'n': '会员专区', 'v': '/movie_bt_series/huiyuanzhuanqu'},
]},
],
}
return result
def homeVideoContent(self):
return {}
# ------------------------------------------------------------------ #
# 分类
# ------------------------------------------------------------------ #
def categoryContent(self, tid, pg, filter, extend):
pg = int(pg)
result = {'list': [], 'page': pg, 'pagecount': 999, 'limit': 0, 'total': 0}
tid = str(tid).strip('/')
extend = extend or {}
sub = (extend.get('class') or extend.get('area') or '').strip('/') if tid == 'movie_bt' else ''
path = f'{tid}/{sub}'.strip('/') if sub else tid
resp = self._safe_get(f'{self.host}/{path}/page/{pg}')
if not resp:
return result
videos = self._parse_videos(resp.text)
result['list'] = videos
result['limit'] = len(videos)
pagecount = 999
nums = [int(x) for x in re.findall(r'[^"]*page/(\d+)[^"]*"[^>]*>(?:»|>|下一页)', resp.text)]
if nums:
pagecount = max(nums)
result['pagecount'] = pagecount
result['total'] = pagecount * len(videos) if videos else 0
return result
# ------------------------------------------------------------------ #
# 详情
# ------------------------------------------------------------------ #
def detailContent(self, ids):
if not ids or not ids[0]:
return {'list': []}
vid = ids[0]
resp = self._safe_get(f'{self.host}/movie/{vid}.html')
if not resp:
return {'list': []}
html = resp.text
vod = {'vod_id': vid}
m = re.search(r'