mirror of
https://github.com/ihabunek/twitch-dl
synced 2024-08-30 18:32:25 +00:00
parent
0dd04a7e2d
commit
a49dcab419
@ -3,6 +3,7 @@ import re
|
||||
from os import path
|
||||
|
||||
from twitchdl import twitch, utils
|
||||
from twitchdl.commands.download import get_clip_authenticated_url
|
||||
from twitchdl.download import download_file
|
||||
from twitchdl.exceptions import ConsoleError
|
||||
from twitchdl.output import print_out, print_clip, print_json
|
||||
@ -79,7 +80,7 @@ def _clips_download(args):
|
||||
for clips, _ in generator:
|
||||
for clip in clips["edges"]:
|
||||
clip = clip["node"]
|
||||
url = clip["videoQualities"][0]["sourceURL"]
|
||||
url = get_clip_authenticated_url(clip["slug"], "source")
|
||||
target = _clip_target_filename(clip)
|
||||
|
||||
if path.exists(target):
|
||||
|
@ -7,7 +7,7 @@ import tempfile
|
||||
|
||||
from os import path
|
||||
from pathlib import Path
|
||||
from urllib.parse import urlparse
|
||||
from urllib.parse import urlparse, urlencode
|
||||
|
||||
from twitchdl import twitch, utils
|
||||
from twitchdl.download import download_file, download_files
|
||||
@ -139,21 +139,21 @@ def download(args):
|
||||
raise ConsoleError("Invalid input: {}".format(args.video))
|
||||
|
||||
|
||||
def _get_clip_url(clip, args):
|
||||
def _get_clip_url(clip, quality):
|
||||
qualities = clip["videoQualities"]
|
||||
|
||||
# Quality given as an argument
|
||||
if args.quality:
|
||||
if args.quality == "source":
|
||||
if quality:
|
||||
if quality == "source":
|
||||
return qualities[0]["sourceURL"]
|
||||
|
||||
selected_quality = args.quality.rstrip("p") # allow 720p as well as 720
|
||||
selected_quality = quality.rstrip("p") # allow 720p as well as 720
|
||||
for q in qualities:
|
||||
if q["quality"] == selected_quality:
|
||||
return q["sourceURL"]
|
||||
|
||||
available = ", ".join([str(q["quality"]) for q in qualities])
|
||||
msg = "Quality '{}' not found. Available qualities are: {}".format(args.quality, available)
|
||||
msg = "Quality '{}' not found. Available qualities are: {}".format(quality, available)
|
||||
raise ConsoleError(msg)
|
||||
|
||||
# Ask user to select quality
|
||||
@ -167,6 +167,23 @@ def _get_clip_url(clip, args):
|
||||
return selected_quality["sourceURL"]
|
||||
|
||||
|
||||
def get_clip_authenticated_url(slug, quality):
|
||||
print_out("<dim>Fetching access token...</dim>")
|
||||
access_token = twitch.get_clip_access_token(slug)
|
||||
|
||||
if not access_token:
|
||||
raise ConsoleError("Access token not found for slug '{}'".format(slug))
|
||||
|
||||
url = _get_clip_url(access_token, quality)
|
||||
|
||||
query = urlencode({
|
||||
"sig": access_token["playbackAccessToken"]["signature"],
|
||||
"token": access_token["playbackAccessToken"]["value"],
|
||||
})
|
||||
|
||||
return "{}?{}".format(url, query)
|
||||
|
||||
|
||||
def _download_clip(slug, args):
|
||||
print_out("<dim>Looking up clip...</dim>")
|
||||
clip = twitch.get_clip(slug)
|
||||
@ -174,6 +191,12 @@ def _download_clip(slug, args):
|
||||
if not clip:
|
||||
raise ConsoleError("Clip '{}' not found".format(slug))
|
||||
|
||||
print_out("<dim>Fetching access token...</dim>")
|
||||
access_token = twitch.get_clip_access_token(slug)
|
||||
|
||||
if not access_token:
|
||||
raise ConsoleError("Access token not found for slug '{}'".format(slug))
|
||||
|
||||
print_out("Found: <green>{}</green> by <yellow>{}</yellow>, playing <blue>{}</blue> ({})".format(
|
||||
clip["title"],
|
||||
clip["broadcaster"]["displayName"],
|
||||
@ -181,7 +204,7 @@ def _download_clip(slug, args):
|
||||
utils.format_duration(clip["durationSeconds"])
|
||||
))
|
||||
|
||||
url = _get_clip_url(clip, args)
|
||||
url = get_clip_authenticated_url(slug, args.quality)
|
||||
print_out("<dim>Selected URL: {}</dim>".format(url))
|
||||
|
||||
target = _clip_target_filename(clip)
|
||||
|
@ -51,6 +51,16 @@ def kraken_get(url, params={}, headers={}):
|
||||
return authenticated_get(url, params, headers)
|
||||
|
||||
|
||||
def gql_post(query):
|
||||
url = "https://gql.twitch.tv/gql"
|
||||
response = authenticated_post(url, data=query).json()
|
||||
|
||||
if "errors" in response:
|
||||
raise GQLError(response["errors"])
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def gql_query(query):
|
||||
url = "https://gql.twitch.tv/gql"
|
||||
response = authenticated_post(url, json={"query": query}).json()
|
||||
@ -133,6 +143,26 @@ def get_clip(slug):
|
||||
return response["data"]["clip"]
|
||||
|
||||
|
||||
def get_clip_access_token(slug):
|
||||
query = """
|
||||
{{
|
||||
"operationName": "VideoAccessToken_Clip",
|
||||
"variables": {{
|
||||
"slug": "{slug}"
|
||||
}},
|
||||
"extensions": {{
|
||||
"persistedQuery": {{
|
||||
"version": 1,
|
||||
"sha256Hash": "36b89d2507fce29e5ca551df756d27c1cfe079e2609642b4390aa4c35796eb11"
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
"""
|
||||
|
||||
response = gql_post(query.format(slug=slug).strip())
|
||||
return response["data"]["clip"]
|
||||
|
||||
|
||||
def get_channel_clips(channel_id, period, limit, after=None):
|
||||
"""
|
||||
List channel clips.
|
||||
|
Loading…
Reference in New Issue
Block a user