Files
tvbox_collect/jaychouqq/yingshi/py2/ayf.py
T
2026-06-29 03:41:14 +00:00

330 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
# by @你猜
import json
import sys
import requests
import re
# Ensure bs4 is available or handled in your environment
try:
from bs4 import BeautifulSoup
except ImportError:
sys.exit("BeautifulSoup4 is required. Please install it via 'pip install beautifulsoup4'")
sys.path.append('..')
from base.spider import Spider
class Spider(Spider):
def init(self, extend=""):
self.host = "https://www.iyf.lv"
self.headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 11; SAMSUNG SM-G973U) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/14.2 Chrome/87.0.4280.141 Mobile Safari/537.36',
'Referer': self.host + '/',
'Origin': self.host
}
def getName(self):
return "爱壹帆"
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def destroy(self):
pass
def homeContent(self, filter):
# Mapping from JS: class_name='电影&剧集&综艺&动漫&更新&热榜', class_url='1&2&3&4&new&hot'
classes = [
{"type_name": "电影", "type_id": "1"},
{"type_name": "剧集", "type_id": "2"},
{"type_name": "综艺", "type_id": "3"},
{"type_name": "动漫", "type_id": "4"},
{"type_name": "更新", "type_id": "new"},
{"type_name": "热榜", "type_id": "hot"}
]
# JS says filterable: 0, so we return empty filters
return {'class': classes, 'filters': {}}
def homeVideoContent(self):
# JS Recommendation rule: .tab-list.active;a.module-poster-item.module-item
try:
html = self.fetch(self.host, headers=self.headers).text
soup = BeautifulSoup(html, 'html.parser')
# Locate the active tab list or default recommendation section
items = soup.select('.tab-list.active a.module-poster-item.module-item')
if not items:
items = soup.select('a.module-poster-item.module-item')[:10] # Fallback
vods = []
for item in items:
vod = self._parse_vod_item(item)
if vod:
vods.append(vod)
return {'list': vods}
except Exception as e:
return {'list': []}
def categoryContent(self, tid, pg, filter, extend):
# JS Logic:
# if new -> /label/new/
# if hot -> /label/hot/
# else -> /t/tid/
# paging -> url + 'page/' + pg + '/'
url = ""
if tid == 'new':
url = f"{self.host}/label/new/"
elif tid == 'hot':
url = f"{self.host}/label/hot/"
else:
url = f"{self.host}/t/{tid}/"
if int(pg) > 1:
url += f"page/{pg}/"
try:
html = self.fetch(url, headers=self.headers).text
soup = BeautifulSoup(html, 'html.parser')
items = soup.select('a.module-poster-item.module-item')
vods = []
for item in items:
vod = self._parse_vod_item(item)
if vod:
vods.append(vod)
return {
'list': vods,
'page': pg,
'pagecount': 9999,
'limit': 20,
'total': 99999
}
except Exception as e:
return {'list': []}
def detailContent(self, ids):
# JS Rule 二级 (Detail)
# title: h1
# img: .lazyload -> data-original
# content: .module-info-introduction
# tabs: .module-tab-item
# lists: .module-play-list
try:
url = ids[0]
if not url.startswith('http'):
url = self.host + url
html = self.fetch(url, headers=self.headers).text
soup = BeautifulSoup(html, 'html.parser')
vod = {}
vod['vod_id'] = ids[0]
# 标题
title_elem = soup.select_one('h1')
vod['vod_name'] = title_elem.get_text(strip=True) if title_elem else "未知"
# 图片 - 修复图片获取逻辑
img_elem = soup.select_one('.module-info-poster img.lazyload')
if not img_elem:
img_elem = soup.select_one('.module-item-pic img.lazyload')
if not img_elem:
img_elem = soup.select_one('.lazyload')
if img_elem:
# 优先获取data-original,如果没有则获取src
vod['vod_pic'] = img_elem.get('data-original') or img_elem.get('src') or ""
# 确保图片URL完整
if vod['vod_pic'] and not vod['vod_pic'].startswith('http'):
vod['vod_pic'] = self.host + vod['vod_pic']
else:
vod['vod_pic'] = ""
# 描述内容
desc_elem = soup.select_one('.module-info-introduction-content')
vod['vod_content'] = desc_elem.get_text(strip=True) if desc_elem else ""
# 提取详细信息
info_items = {}
info_elems = soup.select('.module-info-item')
for elem in info_elems:
title_elem = elem.select_one('.module-info-item-title')
content_elem = elem.select_one('.module-info-item-content')
if title_elem and content_elem:
title = title_elem.get_text(strip=True).replace('', '').replace(':', '')
info_items[title] = content_elem.get_text(strip=True)
# 构建详细信息字符串
vod['vod_actor'] = info_items.get('主演', '')
vod['vod_director'] = info_items.get('导演', '')
vod['vod_area'] = info_items.get('地区', '')
vod['vod_year'] = info_items.get('年份', '') or info_items.get('上映', '')
vod['vod_remarks'] = info_items.get('更新', '') or info_items.get('集数', '')
# Play Lists
tabs = [t.get_text(strip=True) for t in soup.select('.module-tab-item')]
play_lists = soup.select('.module-play-list')
vod_play_from = []
vod_play_url = []
for i, play_list in enumerate(play_lists):
# If tabs count matches lists, use tab name, else default
from_name = tabs[i] if i < len(tabs) else f"线路{i+1}"
vod_play_from.append(from_name)
links = []
for a in play_list.select('a'):
name = a.get_text(strip=True)
href = a.get('href')
if href:
if not href.startswith('http'):
href = self.host + href
links.append(f"{name}${href}")
if links:
vod_play_url.append("#".join(links))
if vod_play_from and vod_play_url:
vod['vod_play_from'] = "$$$".join(vod_play_from)
vod['vod_play_url'] = "$$$".join(vod_play_url)
return {'list': [vod]}
except Exception as e:
return {'list': []}
def searchContent(self, key, quick, pg="1"):
# JS SearchUrl: /s/**-------------/
url = f"{self.host}/s/{key}-------------.html"
if int(pg) > 1:
url += f"page/{pg}/"
try:
html = self.fetch(url, headers=self.headers).text
soup = BeautifulSoup(html, 'html.parser')
# 多种搜索结果选择器
items = soup.select('.module-search-item, .module-poster-item, .module-item')
if not items:
items = soup.select('a[href*="/iyftv/"]')
vods = []
for item in items:
vod = self._parse_vod_item(item, is_search=True)
if vod and vod.get('vod_id'):
vods.append(vod)
return {'list': vods, 'page': pg}
except Exception as e:
return {'list': []}
def playerContent(self, flag, id, vipFlags):
# JS Lazy Rule:
# 1. Match .m3u8
# 2. Match .mp4
url = id
if not url.startswith('http'):
url = self.host + url
try:
html = self.fetch(url, headers=self.headers).text
# 首先尝试从播放器配置中提取
player_match = re.search(r'var player_aaaa=({[^;]+});', html)
if player_match:
try:
player_data = json.loads(player_match.group(1))
if player_data.get('url'):
return {'parse': 0, 'url': player_data['url'], 'header': self.headers}
except:
pass
# 正则匹配视频地址
m3u8_match = re.search(r'(https?://[^\s"\'<>]+\.m3u8[^\s"\'<>]*)', html)
if m3u8_match:
return {'parse': 0, 'url': m3u8_match.group(1), 'header': self.headers}
mp4_match = re.search(r'(https?://[^\s"\'<>]+\.(mp4|m4a)[^\s"\'<>]*)', html)
if mp4_match:
return {'parse': 0, 'url': mp4_match.group(1), 'header': self.headers}
# Fallback: Return original url to let the player sniff it
return {'parse': 1, 'url': url, 'header': self.headers}
except Exception as e:
return {'parse': 1, 'url': url, 'header': self.headers}
def _parse_vod_item(self, item, is_search=False):
# Helper to extract vod data from a list item (<a> or div)
try:
link = item if item.name == 'a' else item.select_one('a')
if not link:
return {}
url = link.get('href')
if not url:
return {}
# 处理图片 - 修复图片获取逻辑
pic = ""
# 多种图片选择器
img_selectors = [
'.lazyload',
'.module-item-pic img',
'.module-item-cover img',
'img'
]
for selector in img_selectors:
img_elem = item.select_one(selector)
if img_elem:
# 优先获取data-original,如果没有则获取src
pic = img_elem.get('data-original') or img_elem.get('src') or ""
if pic:
break
# 确保图片URL完整
if pic and not pic.startswith('http'):
pic = self.host + pic
# 标题
title = ""
if is_search:
title_selectors = ['.module-card-item-title', '.module-poster-item-title', '.module-item-title']
for selector in title_selectors:
title_elem = item.select_one(selector)
if title_elem:
title = title_elem.get_text(strip=True)
break
else:
title = link.get('title') or ""
if not title:
title_elem = item.select_one('.module-poster-item-title')
title = title_elem.get_text(strip=True) if title_elem else ""
# 备注/更新信息
remarks = ""
remarks_selectors = ['.module-item-note', '.module-card-item-note', '.pic-text']
for selector in remarks_selectors:
remarks_elem = item.select_one(selector)
if remarks_elem:
remarks = remarks_elem.get_text(strip=True)
break
return {
'vod_id': url,
'vod_name': title,
'vod_pic': pic,
'vod_remarks': remarks
}
except Exception as e:
return {}
def localProxy(self, param):
pass