mirror of
https://github.com/ihabunek/twitch-dl
synced 2024-08-30 18:32:25 +00:00
Use graphql to fetch channel videos
The old helix endpoint returns HTTP 401 fixes #18
This commit is contained in:
parent
6c28dd2f5e
commit
2118cd8825
@ -1,6 +1,13 @@
|
||||
Twitch Downloader change log
|
||||
============================
|
||||
|
||||
1.8.0 (2020-05-17)
|
||||
------------------
|
||||
|
||||
* Fix videos command (#18)
|
||||
* **Breaking**: `videos` command no longer takes the `--offset` parameter due to
|
||||
API changes
|
||||
|
||||
1.7.0 (2020-04-25)
|
||||
------------------
|
||||
|
||||
|
@ -16,26 +16,23 @@ from twitchdl.exceptions import ConsoleError
|
||||
from twitchdl.output import print_out, print_video
|
||||
|
||||
|
||||
def videos(channel_name, limit, offset, sort, type, **kwargs):
|
||||
print_out("Looking up user...")
|
||||
user = twitch.get_user(channel_name)
|
||||
if not user:
|
||||
raise ConsoleError("User {} not found.".format(channel_name))
|
||||
|
||||
def videos(channel_name, limit, sort, type, **kwargs):
|
||||
print_out("Loading videos...")
|
||||
videos = twitch.get_channel_videos(user["id"], limit, offset, sort, type)
|
||||
count = len(videos['videos'])
|
||||
videos = twitch.get_channel_videos(channel_name, limit, sort, type)
|
||||
count = len(videos["edges"])
|
||||
total = videos["totalCount"]
|
||||
|
||||
if not count:
|
||||
print_out("No videos found")
|
||||
return
|
||||
|
||||
first = offset + 1
|
||||
last = offset + len(videos['videos'])
|
||||
total = videos["_total"]
|
||||
# TODO: paging
|
||||
first = 1
|
||||
last = count
|
||||
print_out("<yellow>Showing videos {}-{} of {}</yellow>".format(first, last, total))
|
||||
|
||||
for video in videos['videos']:
|
||||
print_video(video)
|
||||
for video in videos["edges"]:
|
||||
print_video(video["node"])
|
||||
|
||||
|
||||
def _select_quality(playlists):
|
||||
|
@ -32,6 +32,19 @@ def time(value):
|
||||
return hours * 3600 + minutes * 60 + seconds
|
||||
|
||||
|
||||
def limit(value):
|
||||
"""Validates the number of videos to fetch."""
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
raise ArgumentTypeError("must be an integer")
|
||||
|
||||
if not 1 <= int(value) <= 100:
|
||||
raise ArgumentTypeError("must be between 1 and 100")
|
||||
|
||||
return value
|
||||
|
||||
|
||||
COMMANDS = [
|
||||
Command(
|
||||
name="videos",
|
||||
@ -43,14 +56,9 @@ COMMANDS = [
|
||||
}),
|
||||
(["-l", "--limit"], {
|
||||
"help": "Number of videos to fetch (default 10, max 100)",
|
||||
"type": int,
|
||||
"type": limit,
|
||||
"default": 10,
|
||||
}),
|
||||
(["-o", "--offset"], {
|
||||
"help": "Offset for pagination of results. (default 0)",
|
||||
"type": int,
|
||||
"default": 0,
|
||||
}),
|
||||
(["-s", "--sort"], {
|
||||
"help": "Sorting order of videos. (default: time)",
|
||||
"type": str,
|
||||
|
@ -57,12 +57,16 @@ def print_err(*args, **kwargs):
|
||||
|
||||
|
||||
def print_video(video):
|
||||
published_at = video['published_at'].replace('T', ' @ ').replace('Z', '')
|
||||
length = utils.format_duration(video['length'])
|
||||
name = video['channel']['display_name']
|
||||
published_at = video["publishedAt"].replace("T", " @ ").replace("Z", "")
|
||||
length = utils.format_duration(video["lengthSeconds"])
|
||||
channel = video["creator"]["channel"]["displayName"]
|
||||
game = video["game"]["name"]
|
||||
|
||||
print_out("\n<bold>{}</bold>".format(video['_id'][1:]))
|
||||
# Can't find URL in video object, strange
|
||||
url = "https://twitch.tv/{}".format(video["id"])
|
||||
|
||||
print_out("\n<bold>{}</bold>".format(video["id"]))
|
||||
print_out("<green>{}</green>".format(video["title"]))
|
||||
print_out("<cyan>{}</cyan> playing <cyan>{}</cyan>".format(name, video['game']))
|
||||
print_out("<cyan>{}</cyan> playing <cyan>{}</cyan>".format(channel, game))
|
||||
print_out("Published <cyan>{}</cyan> Length: <cyan>{}</cyan> ".format(published_at, length))
|
||||
print_out("<i>{}</i>".format(video["url"]))
|
||||
print_out("<i>{}</i>".format(url))
|
||||
|
@ -43,18 +43,6 @@ def kraken_get(url, params={}, headers={}):
|
||||
return authenticated_get(url, params, headers)
|
||||
|
||||
|
||||
def get_user(login):
|
||||
"""
|
||||
https://dev.twitch.tv/docs/api/reference/#get-users
|
||||
"""
|
||||
response = authenticated_get("https://api.twitch.tv/helix/users", {
|
||||
"login": login
|
||||
})
|
||||
|
||||
users = response.json()["data"]
|
||||
return users[0] if users else None
|
||||
|
||||
|
||||
def get_video(video_id):
|
||||
"""
|
||||
https://dev.twitch.tv/docs/v5/reference/videos#get-video
|
||||
@ -93,18 +81,46 @@ def get_clip(slug):
|
||||
return data["data"]["clip"]
|
||||
|
||||
|
||||
def get_channel_videos(channel_id, limit, offset, sort, type="archive"):
|
||||
"""
|
||||
https://dev.twitch.tv/docs/v5/reference/channels#get-channel-videos
|
||||
"""
|
||||
url = "https://api.twitch.tv/kraken/channels/{}/videos".format(channel_id)
|
||||
def get_channel_videos(channel_id, limit, sort, type="archive"):
|
||||
url = "https://gql.twitch.tv/gql"
|
||||
|
||||
return kraken_get(url, {
|
||||
"broadcast_type": type,
|
||||
query = """
|
||||
{{
|
||||
user(login: "{channel_id}") {{
|
||||
videos(options: {{ }}, first: {limit}, type: {type}, sort: {sort}, after: "opaqueCursor") {{
|
||||
totalCount
|
||||
edges {{
|
||||
cursor
|
||||
node {{
|
||||
id
|
||||
title
|
||||
publishedAt
|
||||
broadcastType
|
||||
lengthSeconds
|
||||
game {{
|
||||
name
|
||||
}}
|
||||
creator {{
|
||||
channel {{
|
||||
displayName
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
"""
|
||||
|
||||
query = query.format(**{
|
||||
"channel_id": channel_id,
|
||||
"limit": limit,
|
||||
"offset": offset,
|
||||
"sort": sort,
|
||||
}).json()
|
||||
"type": type.upper(),
|
||||
"sort": sort.upper(),
|
||||
})
|
||||
|
||||
response = authenticated_post(url, json={"query": query}).json()
|
||||
return response["data"]["user"]["videos"]
|
||||
|
||||
|
||||
def get_access_token(video_id):
|
||||
|
Loading…
Reference in New Issue
Block a user