# -*- coding: utf-8 -*-
# by @嗷呜
import json
import random
import re
import sys
import time
from base64 import b64decode, b64encode
import concurrent.futures
import requests
from Crypto.Hash import MD5
from pyquery import PyQuery as pq
sys.path.append('..')
from base.spider import Spider

class Spider(Spider):

    def init(self, extend=""):
        self.host=self.gethost()
        self.headers.update({
            'referer': f'{self.host}/',
            'origin': self.host,
        })
        self.session = requests.Session()
        self.session.headers.update(self.headers)
        self.session.get(self.host)
        pass

    def getName(self):
        pass

    def isVideoFormat(self, url):
        pass

    def manualVideoCheck(self):
        pass

    def destroy(self):
        pass

    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',
        'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="134", "Google Chrome";v="134"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"macOS"',
        'sec-fetch-site': 'same-origin',
        'sec-fetch-mode': 'navigate',
        'sec-fetch-user': '?1',
        'sec-fetch-dest': 'document',
        'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
    }

    config={
        "1":[{"key":"class","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":"网络电影"}]},{"key":"area","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":"其他"}]},{"key":"year","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"},{"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":"by","name":"排序","value":[{"n":"时间","v":"time"},{"n":"人气","v":"hits"},{"n":"评分","v":"score"}]}],
        "2":[{"key":"class","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":"area","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":"其他"}]},{"key":"year","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"},{"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":"by","name":"排序","value":[{"n":"时间","v":"time"},{"n":"人气","v":"hits"},{"n":"评分","v":"score"}]}],
        "3":[{"key":"class","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":"求职"}]},{"key":"area","name":"地区","value":[{"n":"全部","v":""},{"n":"内地","v":"内地"},{"n":"港台","v":"港台"},{"n":"欧美","v":"欧美"},{"n":"日韩","v":"日韩"},{"n":"其他","v":"其他"}]},{"key":"year","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"},{"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":"by","name":"排序","value":[{"n":"时间","v":"time"},{"n":"人气","v":"hits"},{"n":"评分","v":"score"}]}],
        "4":[{"key":"class","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":"area","name":"地区","value":[{"n":"全部","v":""},{"n":"国产","v":"国产"},{"n":"欧美","v":"欧美"},{"n":"日本","v":"日本"},{"n":"其他","v":"其他"}]},{"key":"year","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"},{"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":"by","name":"排序","value":[{"n":"时间","v":"time"},{"n":"人气","v":"hits"},{"n":"评分","v":"score"}]}],
      }

    def homeContent(self, filter):
        data=self.getpq()
        result = {}
        classes = []
        for k in data('ul.swiper-wrapper').eq(0)('li').items():
            i=k('a').attr('href')
            if i and 'type' in i:
                classes.append({
                    'type_name': k.text(),
                    'type_id': re.findall(r'\d+', i)[0],
                })
        result['class'] = classes
        result['list'] = self.getlist(data('.tab-content.ewave-pannel_bd li'))
        result['filters'] = self.config
        return result

    def homeVideoContent(self):
        pass

    def categoryContent(self, tid, pg, filter, extend):
        path=f"/vodshow/{tid}-{extend.get('area','')}-{extend.get('by','')}-{extend.get('class','')}-----{pg}---{extend.get('year','')}.html"
        data=self.getpq(path)
        result = {}
        result['list'] = self.getlist(data('ul.ewave-vodlist.clearfix li'))
        result['page'] = pg
        result['pagecount'] = 9999
        result['limit'] = 90
        result['total'] = 999999
        return result

    def detailContent(self, ids):
        data=self.getpq(f"/voddetail/{ids[0]}.html")
        v=data('.ewave-content__detail')
        c=data('p')
        vod = {
            'type_name':c.eq(0)('a').text(),
            'vod_year': v('.data.hidden-sm').text(),
            'vod_remarks': v('h1').text(),
            'vod_actor': c.eq(1)('a').text(),
            'vod_director': c.eq(2)('a').text(),
            'vod_content': c.eq(-1).text(),
            'vod_play_from': '',
            'vod_play_url': ''
        }
        nd=list(data('ul.nav-tabs.swiper-wrapper li').items())
        pd=list(data('ul.ewave-content__playlist').items())
        n,p=[],[]
        for i,x in enumerate(nd):
            n.append(x.text())
            p.append('#'.join([f"{j.text()}${j('a').attr('href')}" for j in pd[i]('li').items()]))
        vod['vod_play_url']='$$$'.join(p)
        vod['vod_play_from']='$$$'.join(n)
        return {'list':[vod]}

    def searchContent(self, key, quick, pg="1"):
        if pg=="1":
            p=f"-------------.html?wd={key}"
        else:
            p=f"{key}----------{pg}---.html"
        data=self.getpq(f"/vodsearch/{p}")
        return {'list':self.getlist(data('ul.ewave-vodlist__media.clearfix li')),'page':pg}

    def playerContent(self, flag, id, vipFlags):
        try:
            data=self.getpq(id)
            jstr = json.loads(data('.ewave-player__video script').eq(0).text().split('=', 1)[-1])
            jxpath='/bbplayer/api.php'
            data=self.session.post(f"{self.host}{jxpath}",data={'vid':jstr['url']}).json()['data']
            if re.search(r'\.m3u8|\.mp4',data['url']):
                url=data['url']
            elif data['urlmode'] == 1:
                url=self.decode1(data['url'])
            elif data['urlmode'] == 2:
                url=self.decode2(data['url'])
            elif re.search(r'\.m3u8|\.mp4',jstr['url']):
                url=jstr['url']
            else:
                url=None
            if not url:raise Exception('未找到播放地址')
            p,c=0,''
        except Exception as e:
            self.log(f"解析失败: {e}")
            p,url,c=1,f"{self.host}{id}",'document.querySelector("#playleft iframe").contentWindow.document.querySelector("#start").click()'
        return  {'parse': p, 'url': url, 'header': {'User-Agent':'okhttp/3.12.1'},'click': c}

    def localProxy(self, param):
        wdict=json.loads(self.d64(param['wdict']))
        url=f"{wdict['jx']}{wdict['id']}"
        data=pq(self.fetch(url,headers=self.headers).text)
        html=data('script').eq(-1).text()
        url = re.search(r'src="(.*?)"', html).group(1)
        return [302,'text/html',None,{'Location':url}]

    def liveContent(self, url):
        pass

    def gethost(self):
        data=pq(self.fetch('https://13826.kstore.space/jubba.py/jbb1.html',headers=self.headers).text)
        hlist=list(data('.content-top ul li').items())[:2]
        hsots=[j('a').attr('href') for i in hlist for j in i('a').items()]
        return self.host_late(hsots)

    def host_late(self, urls):
        with concurrent.futures.ThreadPoolExecutor() as executor:
            future_to_url = {
                executor.submit(self.test_host, url): url
                for url in urls
            }
            results = {}
            for future in concurrent.futures.as_completed(future_to_url):
                url = future_to_url[future]
                try:
                    results[url] = future.result()
                except Exception as e:
                    results[url] = float('inf')
        min_url = min(results.items(), key=lambda x: x[1])[0] if results else None
        if all(delay == float('inf') for delay in results.values()) or not min_url:
            return urls[0]
        return min_url

    def test_host(self, url):
        try:
            start_time = time.monotonic()
            response = requests.head(
                url,
                timeout=1.0,
                allow_redirects=False,
                headers=self.headers
            )
            response.raise_for_status()
            return (time.monotonic() - start_time) * 1000
        except Exception as e:
            print(f"测试{url}失败: {str(e)}")
            return float('inf')

    def getpq(self, path='',min=0,max=3):
        data = self.session.get(f"{self.host}{path}")
        data=data.text
        try:
            if '人机验证' in data:
                print(f"第{min}次尝试人机验证")
                jstr=pq(data)('script').eq(-1).html()
                token,tpath,stt=self.extract(jstr)
                body={'value':self.encrypt(self.host,stt),'token':self.encrypt(token,stt)}
                cd=self.session.post(f"{self.host}{tpath}",data=body)
                if min>max:raise Exception('人机验证失败')
                return self.getpq(path,min+1,max)
            return pq(data)
        except:
            return pq(data.encode('utf-8'))

    def encrypt(self, input_str,staticchars):
        encodechars = ""
        for char in input_str:
            num0 = staticchars.find(char)
            if num0 == -1:
                code = char
            else:
                code = staticchars[(num0 + 3) % 62]
            num1 = random.randint(0, 61)
            num2 = random.randint(0, 61)
            encodechars += staticchars[num1] + code + staticchars[num2]
        return self.e64(encodechars)

    def extract(self, js_code):
        token_match = re.search(r'var token = encrypt\("([^"]+)"\);', js_code)
        token_value = token_match.group(1) if token_match else None
        url_match = re.search(r'var url = \'([^\']+)\';', js_code)
        url_value = url_match.group(1) if url_match else None
        staticchars_match = re.search(r'var\s+staticchars\s*=\s*["\']([^"\']+)["\'];', js_code)
        staticchars = staticchars_match.group(1) if staticchars_match else None
        return token_value, url_value,staticchars

    def decode1(self, val):
        url = self._custom_str_decode(val)
        parts = url.split("/")
        result = "/".join(parts[2:])
        key1 = json.loads(self.d64(parts[1]))
        key2 = json.loads(self.d64(parts[0]))
        decoded = self.d64(result)
        return self._de_string(key1, key2, decoded)

    def _custom_str_decode(self, val):
        decoded = self.d64(val)
        key = self.md5("test")
        result = ""
        for i in range(len(decoded)):
            result += chr(ord(decoded[i]) ^ ord(key[i % len(key)]))
        return self.d64(result)

    def _de_string(self, key_array, value_array, input_str):
        result = ""
        for char in input_str:
            if re.match(r'^[a-zA-Z]$', char):
                if char in key_array:
                    index = key_array.index(char)
                    result += value_array[index]
                    continue
            result += char
        return result

    def decode2(self, url):
        key = "PXhw7UT1B0a9kQDKZsjIASmOezxYG4CHo5Jyfg2b8FLpEvRr3WtVnlqMidu6cN"
        url=self.d64(url)
        result = ""
        i = 1
        while i < len(url):
            try:
                index = key.find(url[i])
                if index == -1:
                    char = url[i]
                else:
                    char = key[(index + 59) % 62]
                result += char
            except IndexError:
                break
            i += 3
        return result

    def getlist(self, data):
        videos = []
        for k in data.items():
            j = k('.ewave-vodlist__thumb')
            h=k('.text-overflow a')
            if not h.attr('href'):h=j
            videos.append({
                'vod_id': re.findall(r'\d+', h.attr('href'))[0],
                'vod_name': j.attr('title'),
                'vod_pic': j.attr('data-original'),
                'vod_remarks': k('.pic-text').text(),
            })
        return videos

    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 md5(self, text):
        h = MD5.new()
        h.update(text.encode('utf-8'))
        return h.hexdigest()