Skip to content

Commit

Permalink
[cleanup, utils] Split into submodules (#7090)
Browse files Browse the repository at this point in the history
Closes #2173

Authored by: pukkandan, coletdjnz
Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
  • Loading branch information
coletdjnz committed May 20, 2023
1 parent 23c39a4 commit 69bec67
Show file tree
Hide file tree
Showing 8 changed files with 480 additions and 444 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ offlinetest: codetest
$(PYTHON) -m pytest -k "not download"

# XXX: This is hard to maintain
CODE_FOLDERS = yt_dlp yt_dlp/downloader yt_dlp/extractor yt_dlp/postprocessor yt_dlp/compat yt_dlp/dependencies
CODE_FOLDERS = yt_dlp yt_dlp/downloader yt_dlp/extractor yt_dlp/postprocessor yt_dlp/compat yt_dlp/utils yt_dlp/dependencies
yt-dlp: yt_dlp/*.py yt_dlp/*/*.py
mkdir -p zip
for d in $(CODE_FOLDERS) ; do \
Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ ignore = E402,E501,E731,E741,W503
max_line_length = 120
per_file_ignores =
devscripts/lazy_load_template.py: F401
yt_dlp/utils/__init__.py: F401, F403


[autoflake]
Expand Down
2 changes: 0 additions & 2 deletions yt_dlp/YoutubeDL.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@
parse_filesize,
preferredencoding,
prepend_extension,
register_socks_protocols,
remove_terminal_sequences,
render_table,
replace_extension,
Expand Down Expand Up @@ -739,7 +738,6 @@ def check_deprecated(param, option, suggestion):
when=when)

self._setup_opener()
register_socks_protocols()

def preload_download_archive(fn):
"""Preload the archive, if any is specified"""
Expand Down
14 changes: 14 additions & 0 deletions yt_dlp/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import warnings

from ..compat.compat_utils import passthrough_module

# XXX: Implement this the same way as other DeprecationWarnings without circular import
passthrough_module(__name__, '._legacy', callback=lambda attr: warnings.warn(
DeprecationWarning(f'{__name__}.{attr} is deprecated'), stacklevel=5))
del passthrough_module

# isort: off
from .traversal import *
from ._utils import *
from ._utils import _configuration_args, _get_exe_version_output
from ._deprecated import *
30 changes: 30 additions & 0 deletions yt_dlp/utils/_deprecated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Deprecated - New code should avoid these"""

from ._utils import preferredencoding


def encodeFilename(s, for_subprocess=False):
assert isinstance(s, str)
return s


def decodeFilename(b, for_subprocess=False):
return b


def decodeArgument(b):
return b


def decodeOption(optval):
if optval is None:
return optval
if isinstance(optval, bytes):
optval = optval.decode(preferredencoding())

assert isinstance(optval, str)
return optval


def error_to_compat_str(err):
return str(err)
163 changes: 163 additions & 0 deletions yt_dlp/utils/_legacy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
"""No longer used and new code should not use. Exists only for API compat."""

import platform
import struct
import sys
import urllib.parse
import zlib

from ._utils import decode_base_n, preferredencoding
from .traversal import traverse_obj
from ..dependencies import certifi, websockets

has_certifi = bool(certifi)
has_websockets = bool(websockets)


def load_plugins(name, suffix, namespace):
from ..plugins import load_plugins
ret = load_plugins(name, suffix)
namespace.update(ret)
return ret


def traverse_dict(dictn, keys, casesense=True):
return traverse_obj(dictn, keys, casesense=casesense, is_user_input=True, traverse_string=True)


def decode_base(value, digits):
return decode_base_n(value, table=digits)


def platform_name():
""" Returns the platform name as a str """
return platform.platform()


def get_subprocess_encoding():
if sys.platform == 'win32' and sys.getwindowsversion()[0] >= 5:
# For subprocess calls, encode with locale encoding
# Refer to http://stackoverflow.com/a/9951851/35070
encoding = preferredencoding()
else:
encoding = sys.getfilesystemencoding()
if encoding is None:
encoding = 'utf-8'
return encoding


# UNUSED
# Based on png2str() written by @gdkchan and improved by @yokrysty
# Originally posted at https://github.com/ytdl-org/youtube-dl/issues/9706
def decode_png(png_data):
# Reference: https://www.w3.org/TR/PNG/
header = png_data[8:]

if png_data[:8] != b'\x89PNG\x0d\x0a\x1a\x0a' or header[4:8] != b'IHDR':
raise OSError('Not a valid PNG file.')

int_map = {1: '>B', 2: '>H', 4: '>I'}
unpack_integer = lambda x: struct.unpack(int_map[len(x)], x)[0]

chunks = []

while header:
length = unpack_integer(header[:4])
header = header[4:]

chunk_type = header[:4]
header = header[4:]

chunk_data = header[:length]
header = header[length:]

header = header[4:] # Skip CRC

chunks.append({
'type': chunk_type,
'length': length,
'data': chunk_data
})

ihdr = chunks[0]['data']

width = unpack_integer(ihdr[:4])
height = unpack_integer(ihdr[4:8])

idat = b''

for chunk in chunks:
if chunk['type'] == b'IDAT':
idat += chunk['data']

if not idat:
raise OSError('Unable to read PNG data.')

decompressed_data = bytearray(zlib.decompress(idat))

stride = width * 3
pixels = []

def _get_pixel(idx):
x = idx % stride
y = idx // stride
return pixels[y][x]

for y in range(height):
basePos = y * (1 + stride)
filter_type = decompressed_data[basePos]

current_row = []

pixels.append(current_row)

for x in range(stride):
color = decompressed_data[1 + basePos + x]
basex = y * stride + x
left = 0
up = 0

if x > 2:
left = _get_pixel(basex - 3)
if y > 0:
up = _get_pixel(basex - stride)

if filter_type == 1: # Sub
color = (color + left) & 0xff
elif filter_type == 2: # Up
color = (color + up) & 0xff
elif filter_type == 3: # Average
color = (color + ((left + up) >> 1)) & 0xff
elif filter_type == 4: # Paeth
a = left
b = up
c = 0

if x > 2 and y > 0:
c = _get_pixel(basex - stride - 3)

p = a + b - c

pa = abs(p - a)
pb = abs(p - b)
pc = abs(p - c)

if pa <= pb and pa <= pc:
color = (color + a) & 0xff
elif pb <= pc:
color = (color + b) & 0xff
else:
color = (color + c) & 0xff

current_row.append(color)

return width, height, pixels


def register_socks_protocols():
# "Register" SOCKS protocols
# In Python < 2.6.5, urlsplit() suffers from bug https://bugs.python.org/issue7904
# URLs with protocols not in urlparse.uses_netloc are not handled correctly
for scheme in ('socks', 'socks4', 'socks4a', 'socks5'):
if scheme not in urllib.parse.uses_netloc:
urllib.parse.uses_netloc.append(scheme)
Loading

0 comments on commit 69bec67

Please sign in to comment.