# coding=utf-8
# !/usr/bin/python
# by刁民 优化版-增加全分类筛选功能+播放详情修复
import random
import re
import sys
from base64 import b64encode, b64decode
from concurrent.futures import ThreadPoolExecutor, as_completed
from pprint import pprint
from urllib.parse import urlencode

sys.path.append('..')
from base.spider import Spider


class Spider(Spider):

   def init(self, extend=""):
       self.did = self.random_str(32)
       pass

   def getName(self):
       pass

   def isVideoFormat(self, url):
       pass

   def manualVideoCheck(self):
       pass

   def destroy(self):
       pass

   rhost = 'https://www.iqiyi.com'

   hhost='https://mesh.if.iqiyi.com'

   dhost='https://miniapp.iqiyi.com'

   # 新的分类内容API
   cate_api = 'https://pcw-api.iqiyi.com/search/recommend/list'

   headers = {
       'Origin': rhost,
       'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36',
       'Referer': f'{rhost}/',
   }

   # 频道ID映射
   CHANNEL_MAP = {
       '1': '电影',
       '2': '电视剧',
       '4': '动漫',
       '6': '综艺',
       '15': '儿童',
       '35': '微剧',
       '3': '纪录片',
       '37': '漫剧'
   }

   # 通用筛选器模板
   SORT_FILTER = {
       'key': 'mode',
       'name': '排序',
       'value': [
           {'n': '最热', 'v': '11'},
           {'n': '最新', 'v': '24'},
           {'n': '好评', 'v': '4'}
       ]
   }

   YEAR_FILTER = {
       'key': 'year',
       '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'}
       ]
   }

   FEE_FILTER = {
       'key': 'is_purchase',
       'name': '资费',
       'value': [
           {'n': '全部', 'v': ''},
           {'n': '免费', 'v': '0'},
           {'n': 'VIP', 'v': '1'}
       ]
   }

   # 电影类型筛选
   MOVIE_TYPE_FILTER = {
       'key': 'three_category_id',
       'name': '类型',
       'value': [
           {'n': '全部', 'v': ''},
           {'n': '喜剧', 'v': '1'},
           {'n': '动作', 'v': '11'},
           {'n': '爱情', 'v': '6'},
           {'n': '科幻', 'v': '14'},
           {'n': '战争', 'v': '7'},
           {'n': '恐怖', 'v': '10'},
           {'n': '奇幻', 'v': '12'},
           {'n': '犯罪', 'v': '11'},
           {'n': '动画', 'v': '9'},
           {'n': '其他', 'v': '5'}
       ]
   }

   # 剧集类型/地区筛选
   TV_TYPE_FILTER = {
       'key': 'three_category_id',
       'name': '类型',
       'value': [
           {'n': '全部', 'v': ''},
           {'n': '内地', 'v': '15'},
           {'n': '港剧', 'v': '16'},
           {'n': '韩剧', 'v': '17'},
           {'n': '美剧', 'v': '18'},
           {'n': '古装', 'v': '20'},
           {'n': '其他', 'v': '19'}
       ]
   }

   # 动漫类型筛选
   ANIME_TYPE_FILTER = {
       'key': 'three_category_id',
       'name': '类型',
       'value': [
           {'n': '全部', 'v': ''},
           {'n': '日本', 'v': '50'},
           {'n': '热血', 'v': '300'},
           {'n': '其他', 'v': '200'}
       ]
   }

   def homeContent(self, filter):
       result = {}
       cateManual = {
           "电影": "1",
           "剧集": "2",
           "综艺": "6",
           "动漫": "4",
           "儿童": "15",
           "微剧": "35",
           "纪录片": "3"
       }
       classes = []
       filters = {}
       for k in cateManual:
           tid = cateManual[k]
           classes.append({
               'type_name': k,
               'type_id': tid
           })
           # 为每个分类配置筛选器
           if tid == "1":
               # 电影：排序 + 年份 + 资费 + 类型
               filters[tid] = [self.SORT_FILTER, self.YEAR_FILTER, self.FEE_FILTER, self.MOVIE_TYPE_FILTER]
           elif tid == "2":
               # 剧集：排序 + 年份 + 资费 + 类型/地区
               filters[tid] = [self.SORT_FILTER, self.YEAR_FILTER, self.FEE_FILTER, self.TV_TYPE_FILTER]
           elif tid == "4":
               # 动漫：排序 + 年份 + 资费 + 类型
               filters[tid] = [self.SORT_FILTER, self.YEAR_FILTER, self.FEE_FILTER, self.ANIME_TYPE_FILTER]
           else:
               # 综艺、儿童、微剧、纪录片：排序 + 年份 + 资费
               filters[tid] = [self.SORT_FILTER, self.YEAR_FILTER, self.FEE_FILTER]
       
       result['class'] = classes
       result['filters'] = filters
       return result

   def homeVideoContent(self):
       data=self.fetch(f'{self.hhost}/portal/lw/v5/channel/recommend?v=13.014.21150', headers=self.headers).json()
       vlist = []
       for i in data['items']:
           # 从外层推荐位获取频道类型
           item_channel_id = i.get('channel_id') or i.get('channelId')
           for j in i['video'][0]['data']:
               display_name = j.get('display_name')
               if not display_name:
                   continue
               
               prevue = j.get('prevue', {})
               first_id = j.get('firstId')
               page_url = j.get('page_url') or prevue.get('page_url')
               
               # 尝试获取 channel_id，增加多字段备选
               channel_id = (prevue.get('channel_id') or prevue.get('channelId') or
                             j.get('channelId') or j.get('channel_id') or
                             item_channel_id)
               
               # 尝试获取 album_id，优先从 page_url 提取（最准确）
               album_id = None
               if page_url:
                   # 爱奇艺专辑页格式: /a_{album_id}.html
                   match = re.search(r'/a_(\w+)\.html', page_url)
                   if match:
                       album_id = match.group(1)
               
               if not album_id:
                   album_id = (j.get('albumId') or j.get('album_id') or
                               prevue.get('albumId') or prevue.get('album_id') or
                               prevue.get('entity_id') or prevue.get('entityId'))
               
               # 从 page_url 推断 channel_id（仅电影可确定）
               if not channel_id and page_url and '/v_' in page_url:
                   channel_id = 1
               
               # 获取图片
               pic = prevue.get('image_url') or j.get('image_url')
               
               # 构建 vod_id
               if album_id and first_id:
                   # 使用标准格式 channel_id$album_id$tvId，channel_id 可能为空（后面会补全）
                   vod_id = f"{channel_id or ''}${album_id}${first_id}"
               elif first_id and page_url:
                   # 回退到旧格式 tvId@base64(page_url)
                   pu = page_url.split('?')[0]
                   vod_id = f"{first_id}@{self.e64(pu)}"
               else:
                   continue
               
               # 构建描述（修复电视剧/动漫等集数显示问题）
               dq_status = j.get('dq_updatestatus', '')
               rank_prefix = j.get('rank_prefix', '')
               
               # 如果 dq_updatestatus 有值且不是"正片"，优先使用
               if dq_status and dq_status != '正片':
                   desc = dq_status
               else:
                   # 尝试从其他字段获取集数/状态信息
                   latest_order = j.get('latestOrder') or j.get('latest_order')
                   video_count = j.get('videoCount') or j.get('video_count')
                   period = j.get('period')
                   duration = j.get('duration')
                   
                   # 从 prevue 中也尝试获取
                   if not latest_order:
                       latest_order = prevue.get('latestOrder') or prevue.get('latest_order')
                   if not video_count:
                       video_count = prevue.get('videoCount') or prevue.get('video_count')
                   if not period:
                       period = prevue.get('period')
                   if not duration:
                       duration = prevue.get('duration')
                   
                   # 根据 channel_id 构建描述
                   cid = channel_id
                   if cid == 1:  # 电影
                       desc = duration if duration else (dq_status or rank_prefix or '正片')
                   elif cid == 6:  # 综艺
                       desc = f"{period}期" if period else (dq_status or rank_prefix or '正片')
                   elif cid in [2, 4, 15, 35, 37] or (not cid and (latest_order or video_count or period)):
                       # 剧集/动漫/儿童/微剧/漫剧
                       if latest_order and video_count:
                           if str(latest_order) == str(video_count):
                               desc = f"{latest_order}集全"
                           else:
                               desc = f"更新至{latest_order}集"
                       elif latest_order:
                           desc = f"更新至{latest_order}集"
                       elif video_count:
                           desc = f"{video_count}集全"
                       elif period:
                           desc = f"{period}期"
                       else:
                           desc = dq_status or rank_prefix or '正片'
                   else:
                       desc = dq_status or rank_prefix or '正片'
               
               vlist.append({
                   'vod_id': vod_id,
                   'vod_name': display_name,
                   'vod_pic': pic,
                   'vod_year': j.get('sns_score'),
                   'vod_remarks': desc
               })
       return {'list':vlist}

   def categoryContent(self, tid, pg, filter, extend):
       if tid == "1009":
           return self.homeVideoContent()
       
       # 构建筛选参数
       params = {
           'channel_id': tid,
           'data_type': 1,
           'page_id': pg,
           'ret_num': 24,
       }
       
       # 安全解码辅助函数
       def safe_decode(val):
           if not val:
               return val
           try:
               decoded = self.d64(val)
               if decoded:
                   return decoded
           except:
               pass
           return val
       
       # 排序模式
       mode = extend.get('mode', '')
       if mode:
           params['mode'] = safe_decode(mode)
       else:
           params['mode'] = 11  # 默认最热
       
       # 类型筛选
       three_category_id = extend.get('three_category_id', '')
       if three_category_id:
           params['three_category_id'] = safe_decode(three_category_id)
       
       # 地区筛选（原代码保留，API兼容性处理）
       region = extend.get('region', '')
       if region:
           params['region'] = safe_decode(region)
       
       # 年份筛选
       year = extend.get('year', '')
       if year:
           params['market_release_date_level'] = safe_decode(year)
       
       # 资费筛选
       is_purchase = extend.get('is_purchase', '')
       if is_purchase:
           params['is_purchase'] = safe_decode(is_purchase)
       
       url = f'{self.cate_api}?{urlencode(params)}'
       data = self.fetch(url, headers=self.headers).json()
       
       videos = []
       if data.get('data') and data['data'].get('list'):
           for item in data['data']['list']:
               channel_id = item.get('channelId')
               album_id = item.get('albumId')
               tv_id = item.get('tvId')
               if not album_id:
                   continue
               
               # 构建描述
               desc = ''
               if channel_id == 1:  # 电影
                   desc = f"{item.get('score', '')}分" if item.get('score') else ''
                   if item.get('duration'):
                       desc += f"\t{item.get('duration')}"
               elif channel_id in [2, 4, 35, 15, 37]:  # 剧集/动漫/微剧/儿童/漫剧
                   if item.get('latestOrder') == item.get('videoCount'):
                       desc = f"{item.get('score', '')}分\t" if item.get('score') else ''
                       desc += f"{item.get('latestOrder')}集全"
                   else:
                       if item.get('videoCount'):
                           desc = f"{item.get('score', '')}分\t" if item.get('score') else ''
                           desc += f"{item.get('latestOrder')}/{item.get('videoCount')}集"
                       elif item.get('latestOrder'):
                           desc = f"更新至 {item.get('latestOrder')}集"
                       else:
                           desc = item.get('focus', '')
               elif channel_id == 6:  # 综艺
                   desc = f"{item.get('period', '')}期"
               else:
                   if item.get('latestOrder'):
                       desc = f"更新至 第{item.get('latestOrder')}期"
                   elif item.get('period'):
                       desc = item.get('period')
                   else:
                       desc = item.get('focus', '')
               
               # 图片处理
               pic = item.get('imageUrl', '')
               if pic and '.jpg' in pic:
                   pic = pic.replace('.jpg', '_260_360.jpg')
               
               # 提取演员
               actors = []
               people = item.get('people', {})
               if people and people.get('main_charactor'):
                   for actor in people['main_charactor']:
                       if actor.get('name'):
                           actors.append(actor['name'])
               
               # 提取年份
               year_str = ''
               period = item.get('period', '')
               if period and len(period) >= 4:
                   year_str = period[:4]
               
               # 构建vod_id（包含tvId用于详情获取）
               vod_id = f"{channel_id}${album_id}"
               if tv_id:
                   vod_id += f"${tv_id}"
               
               videos.append({
                   'vod_id': vod_id,
                   'vod_name': item.get('name', ''),
                   'vod_pic': pic,
                   'vod_year': item.get('score', ''),
                   'vod_remarks': desc,
                   'type_name': self.CHANNEL_MAP.get(str(channel_id), ''),
                   'vod_actor': '|'.join(actors) if actors else '',
                   'vod_content': item.get('description', '')
               })
       
       has_next = data.get('data', {}).get('has_next', 0)
       result = {
           'list': videos,
           'page': pg,
           'pagecount': 9999 if has_next else pg,
           'limit': 24,
           'total': 999999
       }
       return result

   def _get_detail_from_cache(self, tv_id):
       """从缓存API获取视频详情"""
       try:
           url = f'https://cache.video.iqiyi.com/jp/vi/{tv_id}/'
           resp = self.fetch(url, headers=self.headers)
           # 兼容多种返回类型
           if hasattr(resp, 'text'):
               text = resp.text
           elif hasattr(resp, '_data'):
               text = resp._data.decode('utf-8') if hasattr(resp._data, 'decode') else str(resp._data)
           else:
               text = resp.decode('utf-8') if hasattr(resp, 'decode') else str(resp)
           
           # 解析JSONP: var tvInfoJs={...};
           start = text.find('var tvInfoJs=')
           if start != -1:
               start += len('var tvInfoJs=')
               # 找到匹配的闭合大括号（处理嵌套JSON）
               brace_count = 0
               end = start
               for i in range(start, len(text)):
                   if text[i] == '{':
                       brace_count += 1
                   elif text[i] == '}':
                       brace_count -= 1
                       if brace_count == 0:
                           end = i + 1
                           break
               import json
               info = json.loads(text[start:end])
               return {
                   'name': info.get('vn', ''),
                   'actors': info.get('ma', ''),
                   'director': info.get('d', ''),
                   'all_actors': info.get('a', ''),
                   'content': info.get('info', ''),
                   'area': info.get('ar', ''),
                   'year': str(info.get('ty', ''))[:4] if info.get('ty') else '',
                   'channel_id': str(info.get('c', '')),
                   'album_id': str(info.get('aid', '')),
                   'score': info.get('s', ''),
                   'tags': info.get('tg', ''),
               }
       except Exception:
           pass
       return {}

   def detailContent(self, ids):
       id_str = ids[0]
       
       # 解析 vod_id 格式
       # 格式1: channel_id$album_id$tvId
       # 格式2: channel_id$album_id
       # 格式3: tvId@base64_url
       
       tv_id = None
       channel_id = None
       album_id = None
       
       if '@' in id_str:
           # 旧格式: tvId@base64_url
           parts = id_str.split('@')
           tv_id = parts[0]
       elif '$' in id_str:
           parts = id_str.split('$')
           channel_id = parts[0]
           album_id = parts[1]
           if len(parts) >= 3:
               tv_id = parts[2]
       else:
           return {'list': []}
       
       # 如果 channel_id 为空，尝试通过 tv_id 获取缓存信息补全
       if not channel_id and tv_id:
           cache_info = self._get_detail_from_cache(tv_id)
           if cache_info:
               channel_id = cache_info.get('channel_id', '') or channel_id
               # channel_id 为空时，原始 album_id 可能来自 entity_id 不准确，用缓存的校准
               if cache_info.get('album_id'):
                   album_id = cache_info.get('album_id')
               elif not album_id:
                   album_id = cache_info.get('album_id', '') or album_id
       
       # 初始化vod对象
       vod = {
           'vod_id': id_str,
           'vod_name': '',
           'type_name': '',
           'vod_year': '',
           'vod_remarks': '',
           'vod_actor': '',
           'vod_director': '',
           'vod_content': '',
           'vod_play_from': '爱奇艺',
           'vod_play_url': ''
       }
       
       playlists = []
       first_tv_id = None  # 用于获取详情
       
       if channel_id == '1':  # 电影
           # 电影没有剧集列表
           vod['vod_play_url'] = f"正片${id_str}"
           if tv_id:
               first_tv_id = tv_id
       elif channel_id == '6':  # 综艺
           try:
               url = f'https://pcw-api.iqiyi.com/album/source/svlistinfo?cid=6&sourceid={album_id}&timelist='
               data = self.fetch(url, headers=self.headers).json()
               if data.get('data'):
                   for period_key, episodes in data['data'].items():
                       for ep in episodes:
                           if not first_tv_id and ep.get('tvId'):
                               first_tv_id = str(ep['tvId'])
                           playlists.append({
                               'title': ep.get('shortTitle', f"第{ep.get('order', '')}期"),
                               'url': ep.get('playUrl', '')
                           })
           except Exception:
               pass
       else:  # 剧集/动漫/儿童/微剧/纪录片
           try:
               url = f'https://pcw-api.iqiyi.com/albums/album/avlistinfo?aid={album_id}&size=200&page=1'
               data = self.fetch(url, headers=self.headers).json()
               if data.get('data'):
                   epsodelist = data['data'].get('epsodelist', [])
                   if epsodelist:
                       for ep in epsodelist:
                           if not first_tv_id and ep.get('tvId'):
                               first_tv_id = str(ep['tvId'])
                           playlists.append({
                               'title': ep.get('shortTitle', f"第{ep.get('order', '')}集"),
                               'url': ep.get('playUrl', '')
                           })
                       
                       # 分页处理
                       total = data['data'].get('total', 0)
                       if total > 200:
                           for page in range(2, int(total/200) + 2):
                               try:
                                   page_url = f'https://pcw-api.iqiyi.com/albums/album/avlistinfo?aid={album_id}&size=200&page={page}'
                                   page_data = self.fetch(page_url, headers=self.headers).json()
                                   if page_data.get('data') and page_data['data'].get('epsodelist'):
                                       for ep in page_data['data']['epsodelist']:
                                           playlists.append({
                                               'title': ep.get('shortTitle', f"第{ep.get('order', '')}集"),
                                               'url': ep.get('playUrl', '')
                                           })
                               except:
                                   break
                   elif data['data'].get('vlist'):
                       # 某些频道使用vlist格式
                       for ep in data['data']['vlist']:
                           if not first_tv_id and ep.get('id'):
                               first_tv_id = str(ep['id'])
                           playlists.append({
                               'title': ep.get('shortTitle', f"第{ep.get('pd', '')}集"),
                               'url': ep.get('vurl', '')
                           })
           except Exception:
               pass
       
       if playlists:
           vod['vod_play_url'] = '#'.join([f"{p['title']}${p['url']}" for p in playlists])
       else:
           vod['vod_play_url'] = f"正片${id_str}"
       
       # 获取详情信息
       # 优先使用已有的tv_id，否则使用从播放列表获取的first_tv_id
       detail_tv_id = tv_id or first_tv_id
       if detail_tv_id:
           cache_info = self._get_detail_from_cache(detail_tv_id)
           if cache_info:
               vod['vod_name'] = cache_info.get('name', '') or vod['vod_name']
               vod['vod_actor'] = cache_info.get('actors', '') or vod['vod_actor']
               vod['vod_director'] = cache_info.get('director', '') or vod['vod_director']
               vod['vod_content'] = cache_info.get('content', '') or vod['vod_content']
               vod['type_name'] = self.CHANNEL_MAP.get(cache_info.get('channel_id', ''), '') or vod['type_name']
               vod['vod_year'] = cache_info.get('year', '') or vod['vod_year']
       
       # 如果没有获取到名称，使用album_id兜底
       if not vod['vod_name'] and album_id:
           vod['vod_name'] = f'专辑{album_id}'
       
       return {'list': [vod]}

   def searchContent(self, key, quick, pg="1"):
       params = {
           'if': 'html5',
           'key': key,
           'pageNum': pg,
           'pos': 1,
           'pageSize': 24,
           'site': 'iqiyi',
       }
       url = f'https://search.video.iqiyi.com/o?{urlencode(params)}'
       data = self.fetch(url, headers=self.headers).json()
       
       videos = []
       if data.get('data') and data['data'].get('docinfos'):
           for item in data['data']['docinfos']:
               album = item.get('albumDocInfo', {})
               album_id = album.get('albumId')
               if not album_id:
                   continue
               
               # 获取channel
               channel = album.get('channel', '')
               channel_id = ''
               if channel:
                   # 映射channel名称到ID
                   channel_map = {
                       '电影': '1', '电视剧': '2', '动漫': '4', 
                       '综艺': '6', '纪录片': '3', '儿童': '15',
                       '微剧': '35'
                   }
                   channel_id = channel_map.get(channel, '2')
               
               videos.append({
                   'vod_id': f"{channel_id}${album_id}",
                   'vod_name': album.get('albumTitle', ''),
                   'vod_pic': album.get('albumVImage', ''),
                   'vod_year': album.get('score', ''),
                   'vod_remarks': album.get('tvFocus', '')
               })
       
       return {'list': videos, 'page': pg}

   def playerContent(self, flag, id, vipFlags):
       # id格式支持:
       #   channel_id$album_id$tvId
       #   channel_id$album_id
       #   tvId@base64(page_url)
       #   直接URL
       
       if '$' in id:
           parts = id.split('$')
           if len(parts) >= 2:
               channel_id = parts[0]
               album_id = parts[1]
               
               # 构造标准的爱奇艺页面URL，交由api.json中配置的外部解析器解析播放
               if channel_id == '1':  # 电影
                   url = f'https://www.iqiyi.com/v_{album_id}.html'
               else:  # 剧集/综艺/动漫/纪录片等
                   url = f'https://www.iqiyi.com/a_{album_id}.html'
               
               return {'parse': 1, 'url': url, 'header': self.headers}
       
       if '@' in id:
           # 旧格式: tvId@base64(page_url)
           parts = id.split('@')
           if len(parts) == 2:
               decoded_url = self.d64(parts[1])
               if decoded_url:
                   return {'parse': 1, 'url': decoded_url, 'header': self.headers}
       
       # id直接是URL（来自detailContent中的剧集playUrl）
       return {'parse': 1, 'url': id, 'header': self.headers}

   def localProxy(self, param):
       pass

   def getf(self,body):
       # 简化处理，不再从API获取筛选器
       # 可以扩展为返回硬编码筛选器
       return (body['type_id'], [])

   def e64(self, text):
       try:
           text_bytes = text.encode('utf-8')
           encoded_bytes = b64encode(text_bytes)
           return encoded_bytes.decode('utf-8')
       except Exception:
           return ""

   def d64(self,encoded_text: str):
       try:
           encoded_bytes = encoded_text.encode('utf-8')
           decoded_bytes = b64decode(encoded_bytes)
           return decoded_bytes.decode('utf-8')
       except Exception:
           return ""

   def random_str(self,length=16):
       hex_chars = '0123456789abcdef'
       return ''.join(random.choice(hex_chars) for _ in range(length))
