diff --git a/js/18/18.json b/js/18/18.json index 3c5bbf1..b250922 100644 --- a/js/18/18.json +++ b/js/18/18.json @@ -61,33 +61,10 @@ "proxy": {}, "plp": ""} }, - { - "key": "Pornhub", - "name": "Pornhub", - "type": 3, - "api": "./drpy_js/Pornhub.py", - "searchable": 1, - "quickSearch": 1, - "filterable": 0, - "changeable": 0, - "ext": { - "proxy": {}, - "plp": "" - } - }, - { - "key": "肉視頻", - "name": "肉視頻", - "type": 3, - "api": "./drpy_js/rou.py", - "searchable": 1, - "quickSearch": 0, - "filterable": 0, - "changeable": 0 - }, + { "key": "肉视频", - "name": "肉视频2", + "name": "肉视频", "type": 3, "api": "./drpy_js/rsp.py", "searchable": 1, @@ -156,6 +133,41 @@ "style": { "type": "rect", "ratio": 1.5} - } + }, + { + "key": "Pornhub", + "name": "Pornhub(需要翻墙)", + "type": 3, + "api": "./drpy_js/Pornhub.py", + "searchable": 1, + "quickSearch": 1, + "filterable": 0, + "changeable": 0, + "ext": { + "proxy": {}, + "plp": "" + } + }, + { + "key": "Xvideos", + "name": "Xvideos(需要翻墙)", + "type": 3, + "api": "./drpy_js/Xvideos.py", + "searchable": 1, + "quickSearch": 1, + "filterable": 0, + "changeable": 0 + }, + { + "key": "Xhamster", + "name": "Xhamster(需要翻墙)", + "type": 3, + "api": "./drpy_js/Xhamster.py", + "searchable": 1, + "quickSearch": 1, + "filterable": 0, + "changeable": 0, + "playerType": 2 + } ] } diff --git a/js/18/drpy_js/Pronhub.py b/js/18/drpy_js/Pronhub.py new file mode 100644 index 0000000..93f427b --- /dev/null +++ b/js/18/drpy_js/Pronhub.py @@ -0,0 +1,301 @@ +# -*- coding: utf-8 -*- +# by @嗷呜 +import json +import re +import sys +from base64 import b64decode, b64encode +from urllib.parse import urlparse + +import requests +from pyquery import PyQuery as pq +from requests import Session +sys.path.append('..') +from base.spider import Spider + +class Spider(Spider): + + def init(self, extend=""): + ''' + 内置代理配置:真心jar为例 + { + "key": "Phb", + "name": "Phb", + "type": 3, + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "api": "./py/Phb.py", + "ext": { + "http": "http://127.0.0.1:1072", + "https": "http://127.0.0.1:1072" + } + }, + 注:http(s)代理都是http + ''' + 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/109.0.5410.0 Safari/537.36', + 'pragma': 'no-cache', + 'cache-control': 'no-cache', + 'sec-ch-ua-platform': '"Windows"', + 'sec-ch-ua': '"Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"', + 'dnt': '1', + 'sec-ch-ua-mobile': '?0', + 'sec-fetch-site': 'cross-site', + 'sec-fetch-mode': 'cors', + 'sec-fetch-dest': 'empty', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'priority': 'u=1, i', + } + self.host = self.gethost() + self.headers.update({'referer': f'{self.host}/', 'origin': self.host}) + self.session = Session() + self.session.proxies.update(self.proxies) + self.session.headers.update(self.headers) + pass + + def getName(self): + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def destroy(self): + pass + + def homeContent(self, filter): + result = {} + cateManual = { + "视频": "/video", + "片单": "/playlists", + "频道": "/channels", + "分类": "/categories", + "明星": "/pornstars" + } + classes = [] + filters = {} + for k in cateManual: + classes.append({ + 'type_name': k, + 'type_id': cateManual[k] + }) + result['class'] = classes + result['filters'] = filters + return result + + def homeVideoContent(self): + data = self.getpq('/recommended') + vhtml = data("#recommendedListings .pcVideoListItem .phimage") + return {'list': self.getlist(vhtml)} + + def categoryContent(self, tid, pg, filter, extend): + vdata = [] + result = {} + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + if tid == '/video' or '_this_video' in tid: + pagestr = f'&' if '?' in tid else f'?' + tid = tid.split('_this_video')[0] + data = self.getpq(f'{tid}{pagestr}page={pg}') + vdata = self.getlist(data('#videoCategory .pcVideoListItem')) + elif tid == '/playlists': + data = self.getpq(f'{tid}?page={pg}') + vhtml = data('#playListSection li') + vdata = [] + for i in vhtml.items(): + vdata.append({ + 'vod_id': 'playlists_click_' + i('.thumbnail-info-wrapper .display-block a').attr('href'), + 'vod_name': i('.thumbnail-info-wrapper .display-block a').attr('title'), + 'vod_pic': self.proxy(i('.largeThumb').attr('src')), + 'vod_tag': 'folder', + 'vod_remarks': i('.playlist-videos .number').text(), + 'style': {"type": "rect", "ratio": 1.33} + }) + elif tid == '/channels': + data = self.getpq(f'{tid}?o=rk&page={pg}') + vhtml = data('#filterChannelsSection li .description') + vdata = [] + for i in vhtml.items(): + vdata.append({ + 'vod_id': 'director_click_' + i('.avatar a').attr('href'), + 'vod_name': i('.avatar img').attr('alt'), + 'vod_pic': self.proxy(i('.avatar img').attr('src')), + 'vod_tag': 'folder', + 'vod_remarks': i('.descriptionContainer ul li').eq(-1).text(), + 'style': {"type": "rect", "ratio": 1.33} + }) + elif tid == '/categories' and pg == '1': + result['pagecount'] = 1 + data = self.getpq(f'{tid}') + vhtml = data('.categoriesListSection li .relativeWrapper') + vdata = [] + for i in vhtml.items(): + vdata.append({ + 'vod_id': i('a').attr('href') + '_this_video', + 'vod_name': i('a').attr('alt'), + 'vod_pic': self.proxy(i('a img').attr('src')), + 'vod_tag': 'folder', + 'style': {"type": "rect", "ratio": 1.33} + }) + elif tid == '/pornstars': + data = self.getpq(f'{tid}?o=t&page={pg}') + vhtml = data('#popularPornstars .performerCard .wrap') + vdata = [] + for i in vhtml.items(): + vdata.append({ + 'vod_id': 'pornstars_click_' + i('a').attr('href'), + 'vod_name': i('.performerCardName').text(), + 'vod_pic': self.proxy(i('a img').attr('src')), + 'vod_tag': 'folder', + 'vod_year': i('.performerVideosViewsCount span').eq(0).text(), + 'vod_remarks': i('.performerVideosViewsCount span').eq(-1).text(), + 'style': {"type": "rect", "ratio": 1.33} + }) + elif 'playlists_click' in tid: + tid = tid.split('click_')[-1] + if pg == '1': + hdata = self.getpq(tid) + self.token = hdata('#searchInput').attr('data-token') + vdata = self.getlist(hdata('#videoPlaylist .pcVideoListItem .phimage')) + else: + tid = tid.split('playlist/')[-1] + data = self.getpq(f'/playlist/viewChunked?id={tid}&token={self.token}&page={pg}') + vdata = self.getlist(data('.pcVideoListItem .phimage')) + elif 'director_click' in tid: + tid = tid.split('click_')[-1] + data = self.getpq(f'{tid}/videos?page={pg}') + vdata = self.getlist(data('#showAllChanelVideos .pcVideoListItem .phimage')) + elif 'pornstars_click' in tid: + tid = tid.split('click_')[-1] + data = self.getpq(f'{tid}/videos?page={pg}') + vdata = self.getlist(data('#mostRecentVideosSection .pcVideoListItem .phimage')) + result['list'] = vdata + return result + + def detailContent(self, ids): + url = f"{self.host}{ids[0]}" + data = self.getpq(ids[0]) + vn = data('meta[property="og:title"]').attr('content') + dtext = data('.userInfo .usernameWrap a') + pdtitle = '[a=cr:' + json.dumps( + {'id': 'director_click_' + dtext.attr('href'), 'name': dtext.text()}) + '/]' + dtext.text() + '[/a]' + vod = { + 'vod_name': vn, + 'vod_director': pdtitle, + 'vod_remarks': (data('.userInfo').text() + ' / ' + data('.ratingInfo').text()).replace('\n', ' / '), + 'vod_play_from': '老僧酿酒', + 'vod_play_url': '' + } + js_content = data("#player script").eq(0).text() + plist = [f"{vn}${self.e64(f'{1}@@@@{url}')}"] + try: + pattern = r'"mediaDefinitions":\s*(\[.*?\]),\s*"isVertical"' + match = re.search(pattern, js_content, re.DOTALL) + if match: + json_str = match.group(1) + udata = json.loads(json_str) + plist = [ + f"{media['height']}${self.e64(f'{0}@@@@{url}')}" + for media in udata[:-1] + if (url := media.get('videoUrl')) + ] + except Exception as e: + print(f"提取mediaDefinitions失败: {str(e)}") + vod['vod_play_url'] = '#'.join(plist) + return {'list': [vod]} + + def searchContent(self, key, quick, pg="1"): + data = self.getpq(f'/video/search?search={key}&page={pg}') + return {'list': self.getlist(data('#videoSearchResult .pcVideoListItem .phimage'))} + + def playerContent(self, flag, id, vipFlags): + ids = self.d64(id).split('@@@@') + if '.m3u8' in ids[1]: ids[1] = self.proxy(ids[1], 'm3u8') + return {'parse': int(ids[0]), 'url': ids[1], 'header': self.headers} + + def localProxy(self, param): + url = self.d64(param.get('url')) + if param.get('type') == 'm3u8': + return self.m3Proxy(url) + else: + return self.tsProxy(url) + + def m3Proxy(self, 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 + for index, string in enumerate(lines): + 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): + data = requests.get(url, headers=self.headers, proxies=self.proxies, stream=True) + return [200, data.headers['Content-Type'], data.content] + + def gethost(self): + try: + response = requests.get('https://www.pornhub.com', headers=self.headers, proxies=self.proxies, + allow_redirects=False) + return response.headers['Location'][:-1] + except Exception as e: + print(f"获取主页失败: {str(e)}") + return "https://www.pornhub.com" + + 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 getlist(self, data): + vlist = [] + for i in data.items(): + vlist.append({ + 'vod_id': i('a').attr('href'), + 'vod_name': i('a').attr('title'), + 'vod_pic': self.proxy(i('img').attr('src')), + 'vod_remarks': i('.bgShadeEffect').text() or i('.duration').text(), + 'style': {'ratio': 1.33, 'type': 'rect'} + }) + return vlist + + def getpq(self, path): + try: + response = self.session.get(f'{self.host}{path}').text + return pq(response.encode('utf-8')) + except Exception as e: + print(f"请求失败: , {str(e)}") + return None + + def proxy(self, data, type='img'): + if data and len(self.proxies):return f"{self.getProxyUrl()}&url={self.e64(data)}&type={type}" + else:return data \ No newline at end of file diff --git a/js/18/drpy_js/Xhamster.py b/js/18/drpy_js/Xhamster.py new file mode 100644 index 0000000..52593b6 --- /dev/null +++ b/js/18/drpy_js/Xhamster.py @@ -0,0 +1,221 @@ +# -*- coding: utf-8 -*- +# by @嗷呜 +import json +import sys +from base64 import b64decode, b64encode +from pyquery import PyQuery as pq +from requests import Session +sys.path.append('..') +from base.spider import Spider + + +class Spider(Spider): + + def init(self, extend=""): + self.host = self.gethost() + self.headers['referer'] = f'{self.host}/' + self.session = Session() + self.session.headers.update(self.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/133.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="99", "Google Chrome";v="133", "Chromium";v="133"', + 'sec-ch-ua-full-version-list': '"Not(A:Brand";v="99.0.0.0", "Google Chrome";v="133.0.6943.98", "Chromium";v="133.0.6943.98"', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + } + + def homeContent(self, filter): + result = {} + cateManual = { + "4K": "/4k", + "国产": "two_click_/categories/chinese", + "最新": "/newest", + "最佳": "/best", + "频道": "/channels", + "类别": "/categories", + "明星": "/pornstars" + } + classes = [] + filters = {} + for k in cateManual: + classes.append({ + 'type_name': k, + 'type_id': cateManual[k] + }) + if k !='4K':filters[cateManual[k]]=[{'key':'type','name':'类型','value':[{'n':'4K','v':'/4k'}]}] + result['class'] = classes + result['filters'] = filters + return result + + def homeVideoContent(self): + data = self.getpq() + return {'list': self.getlist(data(".thumb-list--sidebar .thumb-list__item"))} + + def categoryContent(self, tid, pg, filter, extend): + vdata = [] + result = {} + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + if tid in ['/4k', '/newest', '/best'] or 'two_click_' in tid: + if 'two_click_' in tid: tid = tid.split('click_')[-1] + data = self.getpq(f'{tid}{extend.get("type","")}/{pg}') + vdata = self.getlist(data(".thumb-list--sidebar .thumb-list__item")) + elif tid == '/channels': + data = self.getpq(f'{tid}/{pg}') + jsdata = self.getjsdata(data) + for i in jsdata['channels']: + vdata.append({ + 'vod_id': f"two_click_" + i.get('channelURL'), + 'vod_name': i.get('channelName'), + 'vod_pic': i.get('siteLogoURL'), + 'vod_year': f'videos:{i.get("videoCount")}', + 'vod_tag': 'folder', + 'vod_remarks': f'subscribers:{i["subscriptionModel"].get("subscribers")}', + 'style': {'ratio': 1.33, 'type': 'rect'} + }) + elif tid == '/categories': + result['pagecount'] = pg + data = self.getpq(tid) + self.cdata = self.getjsdata(data) + for i in self.cdata['layoutPage']['store']['popular']['assignable']: + vdata.append({ + 'vod_id': "one_click_" + i.get('id'), + 'vod_name': i.get('name'), + 'vod_pic': '', + 'vod_tag': 'folder', + 'style': {'ratio': 1.33, 'type': 'rect'} + }) + elif tid == '/pornstars': + data = self.getpq(f'{tid}/{pg}') + pdata = self.getjsdata(data) + for i in pdata['pagesPornstarsComponent']['pornstarListProps']['pornstars']: + vdata.append({ + 'vod_id': f"two_click_" + i.get('pageURL'), + 'vod_name': i.get('name'), + 'vod_pic': i.get('imageThumbUrl'), + 'vod_remarks': i.get('translatedCountryName'), + 'vod_tag': 'folder', + 'style': {'ratio': 1.33, 'type': 'rect'} + }) + elif 'one_click' in tid: + result['pagecount'] = pg + tid = tid.split('click_')[-1] + for i in self.cdata['layoutPage']['store']['popular']['assignable']: + if i.get('id') == tid: + for j in i['items']: + vdata.append({ + 'vod_id': f"two_click_" + j.get('url'), + 'vod_name': j.get('name'), + 'vod_pic': j.get('thumb'), + 'vod_tag': 'folder', + 'style': {'ratio': 1.33, 'type': 'rect'} + }) + result['list'] = vdata + return result + + def detailContent(self, ids): + data = self.getpq(ids[0]) + link = data('link[rel="preload"][as="fetch"][crossorigin="true"]').attr('href') + if link: + ggggx = f"多音画$666_{link}" + else: + ggggx = f"嗅探${ids[0]}" + vn = data('meta[property="og:title"]').attr('content') + dtext = data('#video-tags-list-container') + href = dtext('a').attr('href') + title = dtext('span[class*="body-bold-"]').eq(0).text() + pdtitle = '' + if href: + pdtitle = '[a=cr:' + json.dumps({'id': 'two_click_' + href, 'name': title}) + '/]' + title + '[/a]' + vod = { + 'vod_name': vn, + 'vod_director': pdtitle, + 'vod_remarks': data('.rb-new__info').text(), + 'vod_play_from': '老僧酿酒', + 'vod_play_url': ggggx + } + return {'list': [vod]} + + def searchContent(self, key, quick, pg="1"): + data = self.getpq(f'/search/{key}?page={pg}') + return {'list': self.getlist(data(".thumb-list--sidebar .thumb-list__item")), 'page': pg} + + def playerContent(self, flag, id, vipFlags): + p,url=1,id + headers = { + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5410.0 Safari/537.36', + 'origin': self.host, + 'referer': f'{self.host}/', + } + if id.startswith("666_"): + p,url=0,id[4:] + return {'parse': p, 'url': url, 'header': headers} + + def localProxy(self, param): + pass + + def gethost(self): + try: + response = self.fetch('https://xhamster.com', headers=self.headers, allow_redirects=False) + return response.headers['Location'] + except Exception as e: + print(f"获取主页失败: {str(e)}") + return "https://zn.xhamster.com" + + 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 getlist(self, data): + vlist = [] + for i in data.items(): + vlist.append({ + 'vod_id': i('.role-pop').attr('href'), + 'vod_name': i('.video-thumb-info a').text(), + 'vod_pic': i('.role-pop img').attr('src'), + 'vod_year': i('.video-thumb-info .video-thumb-views').text().split(' ')[0], + 'vod_remarks': i('.role-pop div[data-role="video-duration"]').text(), + 'style': {'ratio': 1.33, 'type': 'rect'} + }) + return vlist + + def getpq(self, path=''): + h = '' if path.startswith('http') else self.host + response = self.session.get(f'{h}{path}') + return pq(response.content) + + + def getjsdata(self, data): + vhtml = data("script[id='initials-script']").text() + jst = json.loads(vhtml.split('initials=')[-1][:-1]) + return jst \ No newline at end of file diff --git a/js/18/drpy_js/Xvideos.py b/js/18/drpy_js/Xvideos.py new file mode 100644 index 0000000..563bd33 --- /dev/null +++ b/js/18/drpy_js/Xvideos.py @@ -0,0 +1,260 @@ +# -*- coding: utf-8 -*- +# by @嗷呜 +import json +import re +import sys +from pyquery import PyQuery as pq +from base64 import b64decode, b64encode +from requests import Session +sys.path.append('..') +from base.spider import Spider + + +class Spider(Spider): + def init(self, extend=""): + self.headers['referer']=f'{self.host}/' + self.session = Session() + self.session.headers.update(self.headers) + pass + + def getName(self): + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def destroy(self): + pass + + host = "https://www.xvideos.com" + + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.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="99", "Google Chrome";v="133", "Chromium";v="133"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-full-version': '"133.0.6943.98"', + 'sec-ch-ua-arch': '"x86"', + 'sec-ch-ua-platform': '"Windows"', + 'sec-ch-ua-platform-version': '"19.0.0"', + 'sec-ch-ua-model': '""', + 'sec-ch-ua-full-version-list': '"Not(A:Brand";v="99.0.0.0", "Google Chrome";v="133.0.6943.98", "Chromium";v="133.0.6943.98"', + 'dnt': '1', + 'upgrade-insecure-requests': '1', + 'sec-fetch-site': 'none', + 'sec-fetch-mode': 'navigate', + 'sec-fetch-user': '?1', + 'sec-fetch-dest': 'document', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'priority': 'u=0, i' + } + + def homeContent(self, filter): + result = {} + cateManual = { + "最新": "/new", + "最佳": "/best", + "频道": "/channels-index", + "标签": "/tags", + "明星": "/pornstars-index" + } + classes = [] + for k in cateManual: + classes.append({ + 'type_name': k, + 'type_id': cateManual[k] + }) + result['class'] = classes + return result + + def homeVideoContent(self): + data = self.getpq() + return {'list':self.getlist(data(".mozaique .frame-block"))} + + def categoryContent(self, tid, pg, filter, extend): + vdata = [] + result = {} + page = f"/{int(pg) - 1}" if pg != '1' else '' + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + if tid=='/new' or 'tags_click' in tid: + if 'tags_click' in tid:tid=tid.split('click_')[-1] + data=self.getpq(f'{tid}/{pg}') + vdata=self.getlist(data(".mozaique .frame-block")) + elif tid=='/best': + if pg=='1': + self.path=self.session.get(f'{self.host}{tid}',headers=self.headers,allow_redirects=False).headers['Location'] + data=self.getpq(f'{self.path}{page}') + vdata=self.getlist(data(".mozaique .frame-block")) + elif tid=='/channels-index' or tid=='/pornstars-index': + data = self.getpq(f'{tid}{page}') + vhtml=data(".mozaique .thumb-block") + for i in vhtml.items(): + a = i('.thumb-inside .thumb a') + match = re.search(r'src="([^"]+)"', a('script').text()) + img='' + if match: + img = match.group(1).strip() + vdata.append({ + 'vod_id': f"channels_click_{'/channels'if tid=='/channels-index' else ''}"+a.attr('href'), + 'vod_name': a('.profile-name').text() or i('.profile-name').text().replace('\xa0','/'), + 'vod_pic': img, + 'vod_tag': 'folder', + 'vod_remarks': i('.thumb-under .profile-counts').text(), + 'style': {'ratio': 1.33, 'type': 'rect'} + }) + elif tid=='/tags': + result['pagecount'] = pg + vhtml = self.getpq(tid) + vhtml = vhtml('.tags-list') + for d in vhtml.items(): + for i in d('li a').items(): + vdata.append({ + 'vod_id': "tags_click_"+i.attr('href'), + 'vod_name': i.attr('title') or i('b').text(), + 'vod_pic': '', + 'vod_tag': 'folder', + 'vod_remarks': i('.navbadge').text(), + 'style': {'ratio': 1.33, 'type': 'rect'} + }) + elif 'channels_click' in tid: + tid=tid.split('click_')[-1] + headers=self.session.headers.copy() + headers.update({'Accept': 'application/json, text/javascript, */*; q=0.01'}) + vhtml=self.post(f'{self.host}{tid}/videos/best/{int(pg)-1}',headers=headers).json() + for i in vhtml['videos']: + vdata.append({ + 'vod_id': i.get('u'), + 'vod_name': i.get('tf'), + 'vod_pic': i.get('il'), + 'vod_year': i.get('n'), + 'vod_remarks': i.get('d'), + 'style': {'ratio': 1.33, 'type': 'rect'} + }) + result['list'] = vdata + return result + + def detailContent(self, ids): + url = f"{self.host}{ids[0]}" + data = self.getpq(ids[0]) + vn=data('meta[property="og:title"]').attr('content') + dtext=data('.main-uploader a') + href=dtext.attr('href') + pdtitle='' + if href and href.count('/') < 2: + href=f'/channels{href}' + pdtitle = '[a=cr:' + json.dumps({'id': 'channels_click_'+href, 'name': dtext('.name').text()}) + '/]' + dtext('.name').text() + '[/a]' + vod = { + 'vod_name': vn, + 'vod_director':pdtitle, + 'vod_remarks': data('.page-title').text().replace(vn,''), + 'vod_play_from': '老僧酿酒', + 'vod_play_url': '' + } + js_content = data("#video-player-bg script") + jstr='' + for script in js_content.items(): + content = script.text() + if 'setVideoUrlLow' in content and 'html5player' in content: + jstr = content + break + plist = [f"{vn}${self.e64(f'{1}@@@@{url}')}"] + def extract_video_urls(js_content): + try: + low = re.search(r'setVideoUrlLow\([\'"]([^\'"]+)[\'"]\)', js_content) + high = re.search(r'setVideoUrlHigh\([\'"]([^\'"]+)[\'"]\)', js_content) + hls = re.search(r'setVideoHLS\([\'"]([^\'"]+)[\'"]\)', js_content) + + return { + 'hls': hls.group(1) if hls else None, + 'high': high.group(1) if high else None, + 'low': low.group(1) if low else None + } + except Exception as e: + print(f"提取视频URL失败: {str(e)}") + return {} + if jstr: + try: + urls = extract_video_urls(jstr) + plist = [ + f"{quality}${self.e64(f'{0}@@@@{url}')}" + for quality, url in urls.items() + if url + ] + except Exception as e: + print(f"提取url失败: {str(e)}") + vod['vod_play_url'] = '#'.join(plist) + return {'list':[vod]} + + def searchContent(self, key, quick, pg="1"): + data=self.getpq(f'/?k={key}&p={int(pg)-1}') + return {'list':self.getlist(data(".mozaique .frame-block")),'page':pg} + + def playerContent(self, flag, id, vipFlags): + headers = { + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5410.0 Safari/537.36', + 'pragma': 'no-cache', + 'cache-control': 'no-cache', + 'sec-ch-ua-platform': '"Windows"', + 'sec-ch-ua': '"Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"', + 'dnt': '1', + 'sec-ch-ua-mobile': '?0', + 'origin': self.host, + 'sec-fetch-site': 'cross-site', + 'sec-fetch-mode': 'cors', + 'sec-fetch-dest': 'empty', + 'referer': f'{self.host}/', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'priority': 'u=1, i', + } + ids=self.d64(id).split('@@@@') + return {'parse': int(ids[0]), 'url': ids[1], 'header': headers} + + 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 getlist(self, data): + vlist=[] + for i in data.items(): + a=i('.thumb-inside .thumb a') + b=i('.thumb-under .title a') + vlist.append({ + 'vod_id': a.attr('href'), + 'vod_name': b('a').attr('title'), + 'vod_pic': a('img').attr('data-src'), + 'vod_year': a('.video-hd-mark').text(), + 'vod_remarks': b('.duration').text(), + 'style': {'ratio': 1.33, 'type': 'rect'} + }) + return vlist + + def getpq(self, path=''): + response = self.session.get(f'{self.host}{path}').text + try: + return pq(response) + except Exception as e: + print(f"{str(e)}") + return pq(response.encode('utf-8')) \ No newline at end of file