Compare commits

..

8 Commits

Author SHA1 Message Date
gillux
b3e9e252aa
Merge 21c38e5cb4 into f2a4983df7 2024-11-14 06:00:59 +00:00
時流
21c38e5cb4 [ie/litv] remove unnecessary parameter
'm3u8_native' is already the default for entry_protocol parameter
2024-11-14 13:56:32 +08:00
時流
25b793b8cd [ie/litv] improve error handling
Returned error might not even be a dict, so we need traverse_obj() here.
On the other hand, no need to try/except around asset_url = ...
since the following request will fail anyway without it.
2024-11-14 13:56:32 +08:00
時流
2efc271b9b [ie/litv] clarify if/else order 2024-11-14 13:56:32 +08:00
時流
ddeb70eaed [ie/litv] inline variables 2024-11-14 13:56:32 +08:00
時流
c5315c16d7 [ie/litv] lint 2024-11-14 13:06:41 +08:00
時流
0c942a029e [ie/litv] Use _search_nextjs_data() 2024-11-14 13:06:39 +08:00
時流
652bf9c1f4 Merge branch 'master' into fix-litv 2024-11-14 12:32:17 +08:00

View File

@ -1,3 +1,4 @@
import functools
import json import json
import uuid import uuid
@ -5,10 +6,12 @@ from .common import InfoExtractor
from ..utils import ( from ..utils import (
ExtractorError, ExtractorError,
int_or_none, int_or_none,
join_nonempty,
smuggle_url, smuggle_url,
traverse_obj, traverse_obj,
try_call, try_call,
unsmuggle_url, unsmuggle_url,
urljoin,
) )
@ -70,71 +73,52 @@ class LiTVIE(InfoExtractor):
webpage = self._download_webpage(url, video_id) webpage = self._download_webpage(url, video_id)
vod_data = self._parse_json(self._search_regex( vod_data = self._search_nextjs_data(webpage, video_id, default={})
r'<script\s+id="__NEXT_DATA__"[^>]*>(.+)</script>', webpage, 'VOD data', default='{}'),
video_id)
program_info = traverse_obj( program_info = traverse_obj(vod_data, ('props', 'pageProps', 'programInformation', {dict})) or {}
vod_data,
('props', 'pageProps', 'programInformation'),
default={}, expected_type=dict)
series_id = program_info.get('series_id')
playlist_data = traverse_obj(vod_data, ('props', 'pageProps', 'seriesTree')) playlist_data = traverse_obj(vod_data, ('props', 'pageProps', 'seriesTree'))
if playlist_data is not None and self._yes_playlist(series_id, video_id, smuggled_data): if playlist_data is not None and self._yes_playlist(program_info.get('series_id'), video_id, smuggled_data):
content_type = program_info.get('content_type') return self._extract_playlist(playlist_data, program_info.get('content_type'))
return self._extract_playlist(playlist_data, content_type)
asset_id = traverse_obj(program_info, ('assets', 0, 'asset_id')) asset_id = traverse_obj(program_info, ('assets', 0, 'asset_id', {str}))
if asset_id is None: # live stream case if asset_id: # This is a live stream
asset_id = program_info.get('content_id')
media_type = program_info.get('content_type')
else: # vod case
media_type = 'vod' media_type = 'vod'
else: # This is a VOD
asset_id = program_info['content_id']
media_type = program_info['content_type']
puid = try_call(lambda: self._get_cookies('https://www.litv.tv/')['PUID'].value) puid = try_call(lambda: self._get_cookies('https://www.litv.tv/')['PUID'].value)
if puid is None: if puid:
endpoint = 'get-urls'
else:
puid = str(uuid.uuid4()) puid = str(uuid.uuid4())
endpoint = 'get-urls-no-auth' endpoint = 'get-urls-no-auth'
else:
endpoint = 'get-urls'
payload = {'AssetId': asset_id, 'MediaType': media_type, 'puid': puid}
video_data = self._download_json( video_data = self._download_json(
f'https://www.litv.tv/api/{endpoint}', video_id, f'https://www.litv.tv/api/{endpoint}', video_id,
data=json.dumps(payload).encode(), data=json.dumps({'AssetId': asset_id, 'MediaType': media_type, 'puid': puid}).encode(),
headers={'Content-Type': 'application/json'}) headers={'Content-Type': 'application/json'})
if video_data.get('error'): if error := traverse_obj(video_data, ('error', {dict})):
error_msg = traverse_obj(video_data, ('error', 'message')) error_msg = traverse_obj(error, ('message', {str}))
if error_msg == 'OutsideRegionError: ': if error_msg and 'OutsideRegionError' in error_msg:
self.raise_geo_restricted('This video is available in Taiwan only') self.raise_geo_restricted('This video is available in Taiwan only')
if error_msg: elif error_msg:
raise ExtractorError(f'{self.IE_NAME} said: {error_msg}', expected=True) raise ExtractorError(f'{self.IE_NAME} said: {error_msg}', expected=True)
raise ExtractorError(f'Unexpected error from {self.IE_NAME}') raise ExtractorError(f'Unexpected error from {self.IE_NAME}')
try:
asset_url = video_data['result']['AssetURLs'][0]
except KeyError:
raise ExtractorError(f'Unexpected result from {self.IE_NAME}')
formats = self._extract_m3u8_formats( formats = self._extract_m3u8_formats(
asset_url, video_id, ext='mp4', video_data['result']['AssetURLs'][0], video_id, ext='mp4', m3u8_id='hls')
entry_protocol='m3u8_native', m3u8_id='hls')
for a_format in formats: for a_format in formats:
# LiTV HLS segments doesn't like compressions # LiTV HLS segments doesn't like compressions
a_format.setdefault('http_headers', {})['Accept-Encoding'] = 'identity' a_format.setdefault('http_headers', {})['Accept-Encoding'] = 'identity'
title = program_info['title'] + program_info.get('secondary_mark', '')
description = program_info.get('description')
thumbnail = program_info.get('picture')
if thumbnail is not None:
thumbnail = 'https://p-cdnstatic.svc.litv.tv/' + thumbnail
categories = [item['name'] for item in program_info.get('genres', [])]
episode = int_or_none(program_info.get('episode'))
return { return {
'id': video_id, 'id': video_id,
'formats': formats, 'formats': formats,
'title': title, 'title': join_nonempty('title', 'secondary_mark', delim='', from_dict=program_info),
'description': description, **traverse_obj(program_info, {
'thumbnail': thumbnail, 'description': ('description', {str}),
'categories': categories, 'thumbnail': ('picture', {functools.partial(urljoin, 'https://p-cdnstatic.svc.litv.tv/')}),
'episode_number': episode, 'categories': ('genres', ..., 'name', {str}),
'episode_number': ('episode', {int_or_none}),
}),
} }