From 44e04a89d5ee64ffabad067ef5adba9b4a541120 Mon Sep 17 00:00:00 2001 From: flaskfarm Date: Fri, 21 Oct 2022 01:42:51 +0900 Subject: [PATCH] update --- .gitignore | 2 +- lib/support/site/tving.py | 508 -------------------------------------- 2 files changed, 1 insertion(+), 509 deletions(-) delete mode 100644 lib/support/site/tving.py diff --git a/.gitignore b/.gitignore index 10a95a6..afd4798 100644 --- a/.gitignore +++ b/.gitignore @@ -143,5 +143,5 @@ false *copy.py *.sh data/ -lib/support/site/tving.py +lib/support/site/1tving.py lib/support/site/wavve.py diff --git a/lib/support/site/tving.py b/lib/support/site/tving.py deleted file mode 100644 index a2f9912..0000000 --- a/lib/support/site/tving.py +++ /dev/null @@ -1,508 +0,0 @@ -import base64 -import json -import os -import platform -import re -import sys -import time -import traceback -import urllib.parse - -import requests - -if __name__ == '__main__': - if platform.system() == 'Windows': - sys.path += ["C:\SJVA3\lib2", "C:\SJVA3\data\custom", "C:\SJVA3_DEV"] - else: - sys.path += ["/root/SJVA3/lib2", "/root/SJVA3/data/custom"] - -from support import d, logger - -apikey = '1e7952d0917d6aab1f0293a063697610' -#apikey = '95a64ebcd8e154aeb96928bf34848826' - -class SupportTving: - default_param = f'&screenCode=CSSD0100&networkCode=CSND0900&osCode=CSOD0900&teleCode=CSCD0900&apiKey={apikey}' - - headers = { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36', - 'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', - 'Accept-Language' : 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7', - 'Referer' : '', - } - - # 같은 코드가 여러군에 있는게 불편하여 그냥 sjva안에서는 ins를 가져와서 사용하는 것으로 한다. - # sjva외에서는 생성해서 사용. - # ins를 만드는 것은 system plugin - ins = None - - - def __init__(self, token=None, proxy=None, user=None, password=None, deviceid=None, uuid=None): - self.token = token - if self.token and '_tving_token=' in self.token: - self.token = self.token.split('=')[1] - self.proxies = None - self.proxy = proxy - if self.proxy != None: - self.proxies = {"https": proxy, 'http':proxy} - self.user = user - self.password = password - self.deviceid = deviceid - self.uuid = uuid - - - def do_login(self, user_id, user_pw, login_type): - try: - url = 'https://user.tving.com/user/doLogin.tving' - if login_type == '0': - login_type_value = '10' - else: - login_type_value = '20' - params = { - 'userId' : user_id, - 'password' : user_pw, - 'loginType' : login_type_value - } - res = requests.post(url, data=params) - cookie = res.headers['Set-Cookie'] - for c in cookie.split(','): - c = c.strip() - if c.startswith('_tving_token'): - ret = c.split(';')[0] - return ret - except Exception as exception: - logger.error('Exception:%s', exception) - logger.error(traceback.format_exc()) - - - def get_device_list(self): - url = f"http://api.tving.com/v1/user/device/list?{self.default_param[1:]}" - return self.api_get(url) - - def get_info(self, mediacode, streamcode): - ts = str(int(time.time())) - try: - tmp_param = self.default_param - if streamcode == 'stream70': - tmp_param = self.default_param.replace('CSSD0100', 'CSSD1200') - url = f"http://api.tving.com/v2/media/stream/info?info=y{tmp_param}&noCache={ts}&mediaCode={mediacode}&streamCode={streamcode}&deviceId={self.deviceid}" - #logger.warning(url) - if self.token != None: - self.headers['Cookie'] = f"_tving_token={self.token}" - info = self.api_get(url) - if streamcode == 'stream70': - for stream in info['content']['info']['stream']: - if stream['code'] == 'stream70': - break - else: - #logger.debug("stream70이 없어서 50으로 재요청") - return self.get_info(mediacode, 'stream50') - #logger.debug(d(self.headers)) - #logger.debug(d(info)) - #logger.error(mediacode) - - if info['result']['code'] == "000": - info['avaliable'] = True - else: - info['avaliable'] = False - return info - - #logger.error(info['stream']['drm_yn']) - if 'drm_yn' in info['stream'] and info['stream']['drm_yn'] == 'Y' and '4k_nondrm_url' not in info['stream']['broadcast']: - info['drm'] = True - info['play_info'] = { - 'uri' : self.__decrypt2(mediacode, ts, info['stream']['broadcast']['widevine']['broad_url']), - 'drm_scheme' : 'widevine', - 'drm_license_uri' : 'http://cj.drmkeyserver.com/widevine_license', - 'drm_key_request_properties': { - 'origin' : 'https://www.tving.com', - 'sec-fetch-site' : 'cross-site', - 'sec-fetch-mode' : 'cors', - 'user-agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36', - 'Host' : 'cj.drmkeyserver.com', - 'referer' : 'https://www.tving.com/', - 'AcquireLicenseAssertion' : info['stream']['drm_license_assertion'], - } - } - info['url'] = info['play_info']['uri'] - #info['play_info']['url'] = info['play_info']['uri'] - else: - if '4k_nondrm_url' in info['stream']['broadcast']: - url = info['stream']['broadcast']['4k_nondrm_url'] - else: - url = info['stream']['broadcast']['broad_url'] - decrypted_url = self.__decrypt2(mediacode, ts, url) - #logger.error(decrypted_url) - #if decrypted_url.find('m3u8') == -1: - # decrypted_url = decrypted_url.replace('rtmp', 'http') - # decrypted_url = decrypted_url.replace('?', '/playlist.m3u8?') - #2020-06-12 - # 2022-05-26 - # smil/playlist.m3u8 이거 영화만 탐?? - #logger.error(decrypted_url) - if decrypted_url.find('smil/playlist.m3u8') != -1 and decrypted_url.find('content_type=VOD') != -1 : - tmps = decrypted_url.split('playlist.m3u8') - r = requests.get(decrypted_url, headers=self.headers, proxies=self.proxies) - lines = r.text.split('\n') - #logger.debug(d(lines)) - # 2022-05-26 이전까지는 고화질이 마지막에 나왔을텐데 영화에서 맨 처음에 나온다고 함. 당연히 확인했을테니 마지막이었겠지? - #i = -1 - #last = '' - #while len(last) == 0: - # last = lines[i].strip() - # i -= 1 - max_bandwidth = 0 - max_url = None - while len(lines) > 0: #for line in lines: - line = lines.pop(0) - match = re.search('BANDWIDTH=(?P\d+)', line) - if match: - bw = int(match.group('bw')) - if bw > max_bandwidth: - max_bandwidth = bw - max_url = lines.pop(0) - decrypted_url = '%s%s' % (tmps[0], max_url) - #logger.debug(f"VOD : {decrypted_url}") - if 'manifest.m3u8' in decrypted_url: #QVOD - r = requests.get(decrypted_url, headers=self.headers, proxies=self.proxies) - lines = r.text.split('\n') - i = -1 - last = '' - while len(last) == 0: - last = lines[i].strip() - i -= 1 - tmps = decrypted_url.split('//') - tmps2 = tmps[1].split('/', 1) - tmps3 = tmps2[1].rsplit('/', 1) - tmps3[1] = re.sub(r'manifest\.m3u8\?start=(\d|-|:)+&end=(\d|-|:)+', '', tmps3[1]) - decrypted_url = f"{tmps[0]}//{tmps2[0]}{last}{tmps3[1]}" - info['broad_url'] = decrypted_url - info['drm'] = False - info['url'] = decrypted_url - info['play_info'] = { - 'hls': decrypted_url, - } - if mediacode[0] in ['E', 'M']: - info['filename'] = self.get_filename(info) - #logger.warning(d(info)) - return info - except Exception as e: - logger.error(f"Exception:{str(e)}") - logger.error(traceback.format_exc()) - - - - - - # list_type : all, live, vod - def get_live_list(self, list_type='live', order='rating', include_drm=False): - - def func(param, page, order='rating', include_drm=True): - has_more = 'N' - try: - result = [] - url = f'https://api.tving.com/v2/media/lives?cacheType=main&pageNo={page}&pageSize=20&order={order}&adult=all&free=all&guest=all&scope=all{param}{self.default_param}' - data = self.api_get(url) - - #logger.debug(url) - for item in data["result"]: - try: - # 2020-11-10 현재 /v1 에서는 drm채널인지 알려주지않고, 방송이 drm 적용인지 알려줌. 그냥 fix로.. - info = {'is_drm':self.is_drm_channel(item['live_code'])} - if include_drm == False and info['is_drm']: - continue - - info['id'] = item["live_code"] - info['title'] = item['schedule']['channel']['name']['ko'] - info['episode_title'] = ' ' - info['img'] = 'http://image.tving.com/upload/cms/caic/CAIC1900/%s.png' % item["live_code"] - if item['schedule']['episode'] is not None: - info['episode_title'] = item['schedule']['episode']['name']['ko'] - if info['title'].startswith('CH.') and len(item['schedule']['episode']['image']) > 0: - info['img'] = 'http://image.tving.com' + item['schedule']['episode']['image'][0]['url'] - #info['free'] = (item['schedule']['broadcast_url'][0]['broad_url1'].find('drm') == -1) - info['summary'] = info['episode_title'] - result.append(info) - except Exception as exception: - logger.error('Exception:%s', exception) - logger.error(traceback.format_exc()) - has_more = data["has_more"] - except Exception as exception: - logger.error('Exception:%s', exception) - logger.error(traceback.format_exc()) - return has_more, result - - ret = [] - if list_type == 'live': - params = ['&channelType=CPCS0100,CPCS0400'] - elif list_type == 'vod': - params = ['&channelType=CPCS0300'] - elif list_type == 'all': - params = ['&channelType=CPCS0100,CPCS0400', '&channelType=CPCS0300'] - else: - params = ['&channelType=CPCS0100,CPCS0400'] - - for param in params: - page = 1 - while True: - hasMore, data = func(param, page, order=order, include_drm=include_drm) - ret += data - if hasMore == 'N': - break - page += 1 - return ret - - - - - def get_vod_list(self, program_code=None, page=1): - url = f'http://api.tving.com/v2/media/episodes?pageNo={page}&pageSize=18&adult=all&guest=all&scope=all&personal=N{self.default_param}' - if program_code is not None: - url += f'&free=all&order=frequencyDesc&programCode={program_code}' - else: - url += "&free=all&lastFrequency=n&order=broadDate" - return self.api_get(url) - - - def get_vod_list_genre(self, genre, page=1): - url = f'http://api.tving.com/v2/media/episodes?pageNo={page}&pageSize=18&adult=all&guest=all&scope=all&personal=N{self.default_param}' - if genre != None and genre != 'all': - url += f"&free=all&lastFrequency=y&order=broadDate&categoryCode={genre}" - else: - url += "&free=all&lastFrequency=y&order=broadDate" - return self.api_get(url) - - - def get_movie_list(self, page=1, category='all'): - url = f'https://api.tving.com/v2/media/movies?pageNo={page}&pageSize=24&order=viewDay&free=all&adult=all&guest=all&scope=all&productPackageCode=338723&personal=N&diversityYn=N{self.default_param}' - if category != 'all': - url += f'&multiCategoryCode={category}' - return self.api_get(url) - - - def get_frequency_programid(self, programid, page=1): - url = f'https://api.tving.com/v2/media/frequency/program/{programid}?pageNo={page}&pageSize=10&order=new&free=all&adult=all&scope=all{self.default_param}' - return self.api_get(url) - - - def get_schedules(self, code, date, start_time, end_time): - url = f"https://api.tving.com/v2/media/schedules?pageNo=1&pageSize=20&order=chno&scope=all&adult=n&free=all&broadDate={date}&broadcastDate={date}&startBroadTime={start_time}&endBroadTime={end_time}&channelCode={','.join(code)}{self.default_param}" - return self.api_get(url) - - - def get_program_programid(self, programid): - url = f'https://api.tving.com/v2/media/program/{programid}?pageNo=1&pageSize=10&order=name{self.default_param}' - return self.api_get(url) - - - def search(self, keyword): - # gubun VODBC, VODMV - try: - import urllib.parse - url = 'https://search.tving.com/search/common/module/getAkc.jsp?kwd=' + urllib.parse.quote(str(keyword)) - data = requests.get(url, headers=self.headers).json() - #logger.debug(d(data)) - if 'dataList' in data['akcRsb']: - return data['akcRsb']['dataList'] - except Exception as exception: - logger.error('Exception:%s', exception) - logger.error(traceback.format_exc()) - - - def api_get(self, url): - try: - if self.token != None: - self.headers['Cookie'] = f"_tving_token={self.token}" - data = requests.get(url, headers=self.headers, proxies=self.proxies).json() - try: - if type(data['body']['result']) == type({}) and data['body']['result']['message'] != None: - logger.debug(f"tving api message : {data['body']['result']['message']}") - except: - pass - if data['header']['status'] == 200: - return data['body'] - except Exception as e: - logger.error(f'url: {url}') - logger.error(f"Exception:{str(e)}") - logger.error(traceback.format_exc()) - - - - def is_drm_channel(self, code): - # C07381:ocn C05661:디즈니채널 C44441:koon C04601:ocn movie C07382:ocn thrill - return (code in ['C07381', 'C05661', 'C44441', 'C04601', 'C07382']) - - - - def get_filename(self, episode_data): - try: - title = episode_data["content"]["program_name"] - title = title.replace("<", "").replace(">", "").replace("\\", "").replace("/", "").replace(":", "").replace("*", "").replace("\"", "").replace("|", "").replace("?", "").replace(" ", " ").strip() - currentQuality = None - if episode_data["stream"]["quality"] is None: - currentQuality = "stream40" - else: - qualityCount = len(episode_data["stream"]["quality"]) - for i in range(qualityCount): - if episode_data["stream"]["quality"][i]["selected"] == "Y": - currentQuality = episode_data["stream"]["quality"][i]["code"] - break - if currentQuality is None: - return - qualityRes = self.__get_quality_to_res(currentQuality) - - if 'frequency' in episode_data["content"]: - episodeno = episode_data["content"]["frequency"] - airdate = str(episode_data["content"]["info"]["episode"]["broadcast_date"])[2:] - if episodeno > 0: - ret = f"{title}.E{str(episodeno).zfill(2)}.{airdate}.{qualityRes}-ST.mp4" - else: - ret = f"{title}.{airdate}.{qualityRes}-ST.mp4" - else: - ret = f"{title}.{qualityRes}-ST.mp4" - #if episode_data['drm']: - # ret = ret.replace('.mp4', '.mkv') - from support import SupportFile - return SupportFile.text_for_filename(ret) - except Exception as e: - logger.error(f"Exception:{str(e)}") - logger.error(traceback.format_exc()) - - - def __get_quality_to_res(self, quality): - if quality == 'stream50': - return '1080p' - elif quality == 'stream40': - return '720p' - elif quality == 'stream30': - return '480p' - elif quality == 'stream70': - return '2160p' - elif quality == 'stream25': - return '270p' - return '1080p' - - - def get_quality_to_tving(self, quality): - if quality == 'FHD': - return 'stream50' - elif quality == 'HD': - return 'stream40' - elif quality == 'SD': - return 'stream30' - elif quality == 'UHD': - return 'stream70' - return 'stream50' - - - - def __decrypt2(self, mediacode, ts, url): - try: - #raise Exception('test') - import sc - ret = sc.td1(mediacode, str(ts), url).strip() - #data = sc.td1(code, ts, url) - ret = re.sub('[^ -~]+', '', ret) - #logger.error(f"[{ret}]") - return ret - except Exception as e: - logger.error(f"Exception:{str(e)}") - #logger.error(traceback.format_exc()) - data = {'url':url, 'code':mediacode, 'ts':ts} - ret = requests.post('https://sjva.me/sjva/tving.php', data=data).json() - return ret['url'] - - - - - - - - -if __name__ == '__main__': - import argparse - - #from support.base import d, get_logger - from lib_wvtool import WVDownloader - - parser = argparse.ArgumentParser() - parser.add_argument('--code', required=True, help='컨텐츠 코드') - parser.add_argument('--quality', required=False, default='stream50', help='화질') - parser.add_argument('--token', required=True,) - parser.add_argument('--proxy', default=None) - parser.add_argument('--deviceid', default=None) - parser.add_argument('--folder_tmp', default=None) - parser.add_argument('--folder_output', default=None) - - args = parser.parse_args() - info = SupportTving(token=args.token, proxy=args.proxy, deviceid=args.deviceid).get_info(args.code, args.quality) - logger.debug(d(info['play_info'])) - if info['drm']: - SupportTving.headers['Cookie'] = f"_tving_token={args.token}" - downloader = WVDownloader({ - 'logger' : logger, - 'mpd_url' : info['play_info']['uri'], - 'code' : args.code, - 'output_filename' : info['filename'], - 'license_headers' : info['play_info']['drm_key_request_properties'], - 'license_url' : info['play_info']['drm_license_uri'], - 'clean' : True, - 'folder_output': args.folder_output, - 'folder_tmp': args.folder_tmp, - 'mpd_headers' : SupportTving.headers - - }) - downloader.download() - else: - logger.error("DRM 영상이 아닙니다.") - #print(args) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -