Replace requests with httpx, remove unused code

This commit is contained in:
Ivan Habunek 2022-08-15 07:12:10 +02:00
parent b03c19dac1
commit f40fd290f7
No known key found for this signature in database
GPG Key ID: CDBD63C43A30BB95
4 changed files with 16 additions and 82 deletions

View File

@ -34,7 +34,7 @@ setup(
python_requires='>=3.5', python_requires='>=3.5',
install_requires=[ install_requires=[
"m3u8>=1.0.0,<2.0.0", "m3u8>=1.0.0,<2.0.0",
"requests>=2.13,<3.0", "httpx>=0.17.0,<1.0.0",
], ],
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [

View File

@ -1,15 +1,15 @@
import asyncio import asyncio
from typing import OrderedDict import httpx
import m3u8 import m3u8
import os import os
import re import re
import requests
import shutil import shutil
import subprocess import subprocess
import tempfile import tempfile
from os import path from os import path
from pathlib import Path from pathlib import Path
from typing import OrderedDict
from urllib.parse import urlparse, urlencode from urllib.parse import urlparse, urlencode
from twitchdl import twitch, utils from twitchdl import twitch, utils
@ -287,7 +287,7 @@ def _download_video(video_id, args):
else _select_playlist_interactive(playlists)) else _select_playlist_interactive(playlists))
print_out("<dim>Fetching playlist...</dim>") print_out("<dim>Fetching playlist...</dim>")
response = requests.get(playlist_uri) response = httpx.get(playlist_uri)
response.raise_for_status() response.raise_for_status()
playlist = m3u8.loads(response.text) playlist = m3u8.loads(response.text)

View File

@ -1,14 +1,5 @@
import os import os
import requests import httpx
from collections import OrderedDict
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime
from functools import partial
from requests.exceptions import RequestException
from twitchdl.output import print_out
from twitchdl.utils import format_size, format_duration
CHUNK_SIZE = 1024 CHUNK_SIZE = 1024
CONNECT_TIMEOUT = 5 CONNECT_TIMEOUT = 5
@ -21,12 +12,12 @@ class DownloadFailed(Exception):
def _download(url, path): def _download(url, path):
tmp_path = path + ".tmp" tmp_path = path + ".tmp"
response = requests.get(url, stream=True, timeout=CONNECT_TIMEOUT)
size = 0 size = 0
with open(tmp_path, 'wb') as target: with httpx.stream("GET", url, timeout=CONNECT_TIMEOUT) as response:
for chunk in response.iter_content(chunk_size=CHUNK_SIZE): with open(tmp_path, "wb") as target:
target.write(chunk) for chunk in response.iter_bytes(chunk_size=CHUNK_SIZE):
size += len(chunk) target.write(chunk)
size += len(chunk)
os.rename(tmp_path, path) os.rename(tmp_path, path)
return size return size
@ -41,63 +32,7 @@ def download_file(url, path, retries=RETRY_COUNT):
for _ in range(retries): for _ in range(retries):
try: try:
return (_download(url, path), from_disk) return (_download(url, path), from_disk)
except RequestException: except httpx.RequestError:
pass pass
raise DownloadFailed(":(") raise DownloadFailed(":(")
def _print_progress(futures):
downloaded_count = 0
downloaded_size = 0
max_msg_size = 0
start_time = datetime.now()
total_count = len(futures)
current_download_size = 0
current_downloaded_count = 0
for future in as_completed(futures):
size, from_disk = future.result()
downloaded_count += 1
downloaded_size += size
# If we find something on disk, we don't want to take it in account in
# the speed calculation
if not from_disk:
current_download_size += size
current_downloaded_count += 1
percentage = 100 * downloaded_count // total_count
est_total_size = int(total_count * downloaded_size / downloaded_count)
duration = (datetime.now() - start_time).seconds
speed = current_download_size // duration if duration else 0
remaining = (total_count - downloaded_count) * duration / current_downloaded_count \
if current_downloaded_count else 0
msg = " ".join([
"Downloaded VOD {}/{}".format(downloaded_count, total_count),
"({}%)".format(percentage),
"<cyan>{}</cyan>".format(format_size(downloaded_size)),
"of <cyan>~{}</cyan>".format(format_size(est_total_size)),
"at <cyan>{}/s</cyan>".format(format_size(speed)) if speed > 0 else "",
"remaining <cyan>~{}</cyan>".format(format_duration(remaining)) if remaining > 0 else "",
])
max_msg_size = max(len(msg), max_msg_size)
print_out("\r" + msg.ljust(max_msg_size), end="")
def download_files(base_url, target_dir, vod_paths, max_workers):
"""
Downloads a list of VODs defined by a common `base_url` and a list of
`vod_paths`, returning a dict which maps the paths to the downloaded files.
"""
urls = [base_url + path for path in vod_paths]
targets = [os.path.join(target_dir, "{:05d}.ts".format(k)) for k, _ in enumerate(vod_paths)]
partials = (partial(download_file, url, path) for url, path in zip(urls, targets))
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = [executor.submit(fn) for fn in partials]
_print_progress(futures)
return OrderedDict(zip(vod_paths, targets))

View File

@ -2,9 +2,8 @@
Twitch API access. Twitch API access.
""" """
import requests import httpx
from requests.exceptions import HTTPError
from twitchdl import CLIENT_ID from twitchdl import CLIENT_ID
from twitchdl.exceptions import ConsoleError from twitchdl.exceptions import ConsoleError
@ -18,7 +17,7 @@ class GQLError(Exception):
def authenticated_get(url, params={}, headers={}): def authenticated_get(url, params={}, headers={}):
headers['Client-ID'] = CLIENT_ID headers['Client-ID'] = CLIENT_ID
response = requests.get(url, params, headers=headers) response = httpx.get(url, params=params, headers=headers)
if 400 <= response.status_code < 500: if 400 <= response.status_code < 500:
data = response.json() data = response.json()
# TODO: this does not look nice in the console since data["message"] # TODO: this does not look nice in the console since data["message"]
@ -33,7 +32,7 @@ def authenticated_get(url, params={}, headers={}):
def authenticated_post(url, data=None, json=None, headers={}): def authenticated_post(url, data=None, json=None, headers={}):
headers['Client-ID'] = CLIENT_ID headers['Client-ID'] = CLIENT_ID
response = requests.post(url, data=data, json=json, headers=headers) response = httpx.post(url, data=data, json=json, headers=headers)
if response.status_code == 400: if response.status_code == 400:
data = response.json() data = response.json()
raise ConsoleError(data["message"]) raise ConsoleError(data["message"])
@ -330,7 +329,7 @@ def get_access_token(video_id, auth_token=None):
try: try:
response = gql_query(query, headers=headers) response = gql_query(query, headers=headers)
return response["data"]["videoPlaybackAccessToken"] return response["data"]["videoPlaybackAccessToken"]
except HTTPError as error: except httpx.HTTPStatusError as error:
# Provide a more useful error message when server returns HTTP 401 # Provide a more useful error message when server returns HTTP 401
# Unauthorized while using a user-provided auth token. # Unauthorized while using a user-provided auth token.
if error.response.status_code == 401: if error.response.status_code == 401:
@ -351,7 +350,7 @@ def get_playlists(video_id, access_token):
""" """
url = "http://usher.twitch.tv/vod/{}".format(video_id) url = "http://usher.twitch.tv/vod/{}".format(video_id)
response = requests.get(url, params={ response = httpx.get(url, params={
"nauth": access_token['value'], "nauth": access_token['value'],
"nauthsig": access_token['signature'], "nauthsig": access_token['signature'],
"allow_audio_only": "true", "allow_audio_only": "true",