Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/yt-dlp/yt-dlp into ytdlp
Browse files Browse the repository at this point in the history
* 'master' of https://github.com/yt-dlp/yt-dlp:
  [crunchyroll:beta] Fix extractor after API change (#3801)
  Return an error code if update fails
  [utils] Fix bug in 0b9c08b
  [tiktok] Detect embeds
  • Loading branch information
Lesmiscore committed May 20, 2022
2 parents 67c60fc + 88d6220 commit 08afb42
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 42 deletions.
4 changes: 2 additions & 2 deletions yt_dlp/YoutubeDL.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
compat_str,
compat_urllib_error,
compat_urllib_request,
windows_enable_vt_mode,
)
from .cookies import load_cookies
from .downloader import LDM_EXCEPTIONS, FFmpegFD, get_suitable_downloader, shorten_protocol_name
Expand Down Expand Up @@ -146,6 +145,7 @@
url_basename,
variadic,
version_tuple,
windows_enable_vt_mode,
write_json_file,
write_string,
)
Expand Down Expand Up @@ -3875,7 +3875,7 @@ def print_debug_header(self):
def get_encoding(stream):
ret = str(getattr(stream, 'encoding', 'missing (%s)' % type(stream).__name__))
if not supports_terminal_sequences(stream):
from .compat import WINDOWS_VT_MODE # Must be imported locally
from .utils import WINDOWS_VT_MODE # Must be imported locally
ret += ' (No VT)' if WINDOWS_VT_MODE is False else ' (No ANSI)'
return ret

Expand Down
12 changes: 3 additions & 9 deletions yt_dlp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -874,22 +874,16 @@ def _real_main(argv=None):
with YoutubeDL(ydl_opts) as ydl:
actual_use = all_urls or opts.load_info_filename

# Remove cache dir
if opts.rm_cachedir:
ydl.cache.remove()

# Update version
if opts.update_self:
if opts.update_self and run_update(ydl) and actual_use:
# If updater returns True, exit. Required for windows
if run_update(ydl):
if actual_use:
return 100, 'ERROR: The program must exit for the update to complete'
return
return 100, 'ERROR: The program must exit for the update to complete'

# Maybe do nothing
if not actual_use:
if opts.update_self or opts.rm_cachedir:
return
return ydl._download_retcode

ydl.warn_if_short_id(sys.argv[1:] if argv is None else argv)
parser.error(
Expand Down
16 changes: 0 additions & 16 deletions yt_dlp/compat/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import contextlib
import os
import subprocess
import sys
import warnings
import xml.etree.ElementTree as etree
Expand Down Expand Up @@ -74,17 +72,3 @@ def compat_expanduser(path):
return userhome + path[i:]
else:
compat_expanduser = os.path.expanduser


WINDOWS_VT_MODE = False if compat_os_name == 'nt' else None


def windows_enable_vt_mode(): # TODO: Do this the proper way https://bugs.python.org/issue30075
if compat_os_name != 'nt':
return
global WINDOWS_VT_MODE
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
with contextlib.suppress(Exception):
subprocess.Popen('', shell=True, startupinfo=startupinfo).wait()
WINDOWS_VT_MODE = True
7 changes: 7 additions & 0 deletions yt_dlp/compat/_legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,10 @@ def compat_ctypes_WINFUNCTYPE(*args, **kwargs):
compat_xpath = lambda xpath: xpath
compat_zip = zip
workaround_optparse_bug9161 = lambda: None


def __getattr__(name):
if name in ('WINDOWS_VT_MODE', 'windows_enable_vt_mode'):
from .. import utils
return getattr(utils, name)
raise AttributeError(name)
9 changes: 5 additions & 4 deletions yt_dlp/extractor/crunchyroll.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,11 +728,12 @@ def _get_params(self, lang):
headers={
'Authorization': auth_response['token_type'] + ' ' + auth_response['access_token']
})
bucket = policy_response['cms']['bucket']
cms = traverse_obj(policy_response, 'cms_beta', 'cms')
bucket = cms['bucket']
params = {
'Policy': policy_response['cms']['policy'],
'Signature': policy_response['cms']['signature'],
'Key-Pair-Id': policy_response['cms']['key_pair_id']
'Policy': cms['policy'],
'Signature': cms['signature'],
'Key-Pair-Id': cms['key_pair_id']
}
locale = traverse_obj(initial_state, ('localization', 'locale'))
if locale:
Expand Down
6 changes: 6 additions & 0 deletions yt_dlp/extractor/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
from .ted import TedEmbedIE
from .theplatform import ThePlatformIE
from .threeqsdn import ThreeQSDNIE
from .tiktok import TikTokIE
from .tnaflix import TNAFlixNetworkEmbedIE
from .tube8 import Tube8IE
from .tunein import TuneInBaseIE
Expand Down Expand Up @@ -3862,6 +3863,11 @@ def _real_extract(self, url):
if ruutu_urls:
return self.playlist_from_matches(ruutu_urls, video_id, video_title)

# Look for Tiktok embeds
tiktok_urls = TikTokIE._extract_urls(webpage)
if tiktok_urls:
return self.playlist_from_matches(tiktok_urls, video_id, video_title)

# Look for HTML5 media
entries = self._parse_html5_media_entries(url, webpage, video_id, m3u8_id='hls')
if entries:
Expand Down
28 changes: 18 additions & 10 deletions yt_dlp/extractor/tiktok.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
import itertools
import json
import random
import re
import string
import time
import json

from .common import InfoExtractor
from ..compat import (
compat_urllib_parse_unquote,
compat_urllib_parse_urlparse
)
from ..compat import compat_urllib_parse_unquote, compat_urllib_parse_urlparse
from ..utils import (
ExtractorError,
HEADRequest,
LazyList,
UnsupportedError,
get_first,
int_or_none,
join_nonempty,
LazyList,
qualities,
srt_subtitles_timecode,
str_or_none,
traverse_obj,
try_get,
url_or_none,
qualities,
)


Expand All @@ -36,6 +34,10 @@ class TikTokBaseIE(InfoExtractor):
_WEBPAGE_HOST = 'https://www.tiktok.com/'
QUALITIES = ('360p', '540p', '720p', '1080p')

@staticmethod
def _create_url(user_id, video_id):
return f'https://www.tiktok.com/@{user_id or "_"}/video/{video_id}'

def _call_api_impl(self, ep, query, manifest_app_version, video_id, fatal=True,
note='Downloading API JSON', errnote='Unable to download API page'):
self._set_cookie(self._API_HOSTNAME, 'odin_tt', ''.join(random.choice('0123456789abcdef') for _ in range(160)))
Expand Down Expand Up @@ -361,7 +363,7 @@ def _parse_aweme_video_web(self, aweme_detail, webpage_url):


class TikTokIE(TikTokBaseIE):
_VALID_URL = r'https?://www\.tiktok\.com/@[\w\.-]+/video/(?P<id>\d+)'
_VALID_URL = r'https?://www\.tiktok\.com/(?:embed|@(?P<user_id>[\w\.-]+)/video)/(?P<id>\d+)'

_TESTS = [{
'url': 'https://www.tiktok.com/@leenabhushan/video/6748451240264420610',
Expand Down Expand Up @@ -466,7 +468,7 @@ class TikTokIE(TikTokBaseIE):
'info_dict': {
'id': '7059698374567611694',
'ext': 'mp4',
'title': 'tiktok video #7059698374567611694',
'title': 'TikTok video #7059698374567611694',
'description': '',
'uploader': 'pokemonlife22',
'creator': 'Pokemon',
Expand All @@ -490,6 +492,11 @@ class TikTokIE(TikTokBaseIE):
'only_matching': True
}]

@classmethod
def _extract_urls(cls, webpage):
return [mobj.group('url') for mobj in re.finditer(
rf'<(?:script|iframe)[^>]+\bsrc=(["\'])(?P<url>{cls._VALID_URL})', webpage)]

def _extract_aweme_app(self, aweme_id):
try:
aweme_detail = self._call_api('aweme/detail', {'aweme_id': aweme_id}, aweme_id,
Expand All @@ -506,7 +513,8 @@ def _extract_aweme_app(self, aweme_id):
return self._parse_aweme_video_app(aweme_detail)

def _real_extract(self, url):
video_id = self._match_id(url)
video_id, user_id = self._match_valid_url(url).group('id', 'user_id')
url = self._create_url(user_id, video_id)

try:
return self._extract_aweme_app(video_id)
Expand Down
19 changes: 18 additions & 1 deletion yt_dlp/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5218,10 +5218,12 @@ def jwt_decode_hs256(jwt):
return payload_data


WINDOWS_VT_MODE = False if compat_os_name == 'nt' else None


@functools.cache
def supports_terminal_sequences(stream):
if compat_os_name == 'nt':
from .compat import WINDOWS_VT_MODE # Must be imported locally
if not WINDOWS_VT_MODE or get_windows_version() < (10, 0, 10586):
return False
elif not os.getenv('TERM'):
Expand All @@ -5232,6 +5234,21 @@ def supports_terminal_sequences(stream):
return False


def windows_enable_vt_mode(): # TODO: Do this the proper way https://bugs.python.org/issue30075
if compat_os_name != 'nt':
return
global WINDOWS_VT_MODE
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
try:
subprocess.Popen('', shell=True, startupinfo=startupinfo).wait()
except Exception:
return

WINDOWS_VT_MODE = True
supports_terminal_sequences.cache_clear()


_terminal_sequences_re = re.compile('\033\\[[^m]+m')


Expand Down

0 comments on commit 08afb42

Please sign in to comment.