mirror of
https://github.com/ihabunek/twitch-dl
synced 2024-08-30 18:32:25 +00:00
Add filtering videos by game
This commit is contained in:
parent
4241ab5d67
commit
d22fd74357
@ -8,6 +8,7 @@ Twitch Downloader change log
|
||||
* **Breaking**: `videos` command no longer takes the `--offset` parameter due to
|
||||
API changes
|
||||
* Add paging to `videos` command to replace offset
|
||||
* Add `--game` option to `videos` command to filter by game
|
||||
|
||||
1.7.0 (2020-04-25)
|
||||
------------------
|
||||
|
@ -30,16 +30,32 @@ def _continue():
|
||||
|
||||
return True
|
||||
|
||||
def videos(channel_name, limit, sort, type, **kwargs):
|
||||
print_out("Loading videos...")
|
||||
generator = twitch.channel_videos_generator(channel_name, limit, sort, type)
|
||||
|
||||
def _get_game_ids(names):
|
||||
if not names:
|
||||
return []
|
||||
|
||||
game_ids = []
|
||||
for name in names:
|
||||
print_out("<dim>Looking up game '{}'...</dim>".format(name))
|
||||
game_id = twitch.get_game_id(name)
|
||||
if not game_id:
|
||||
raise ConsoleError("Game '{}' not found".format(name))
|
||||
game_ids.append(int(game_id))
|
||||
|
||||
return game_ids
|
||||
|
||||
|
||||
def videos(channel_name, limit, sort, type, game, **kwargs):
|
||||
game_ids = _get_game_ids(game)
|
||||
|
||||
print_out("<dim>Loading videos...</dim>")
|
||||
generator = twitch.channel_videos_generator(
|
||||
channel_name, limit, sort, type, game_ids=game_ids)
|
||||
|
||||
first = 1
|
||||
|
||||
for videos, has_more in generator:
|
||||
if "edges" not in videos:
|
||||
break
|
||||
|
||||
count = len(videos["edges"]) if "edges" in videos else 0
|
||||
total = videos["totalCount"]
|
||||
last = first + count - 1
|
||||
@ -54,6 +70,8 @@ def videos(channel_name, limit, sort, type, **kwargs):
|
||||
break
|
||||
|
||||
first += count
|
||||
else:
|
||||
print_out("<yellow>No videos found</yellow>")
|
||||
|
||||
|
||||
def _select_quality(playlists):
|
||||
|
@ -7,6 +7,7 @@ from collections import namedtuple
|
||||
|
||||
from twitchdl.exceptions import ConsoleError
|
||||
from twitchdl.output import print_err
|
||||
from twitchdl.twitch import GQLError
|
||||
from . import commands, __version__
|
||||
|
||||
|
||||
@ -54,6 +55,11 @@ COMMANDS = [
|
||||
"help": "channel name",
|
||||
"type": str,
|
||||
}),
|
||||
(["-g", "--game"], {
|
||||
"help": "Show videos of given game (can be given multiple times)",
|
||||
"action": "append",
|
||||
"type": str,
|
||||
}),
|
||||
(["-l", "--limit"], {
|
||||
"help": "Number of videos to fetch (default 10, max 100)",
|
||||
"type": limit,
|
||||
@ -163,3 +169,8 @@ def main():
|
||||
except ConsoleError as e:
|
||||
print_err(e)
|
||||
sys.exit(1)
|
||||
except GQLError as e:
|
||||
print_err(e)
|
||||
for err in e.errors:
|
||||
print_err("*", err["message"])
|
||||
sys.exit(1)
|
||||
|
@ -8,6 +8,12 @@ from twitchdl import CLIENT_ID
|
||||
from twitchdl.exceptions import ConsoleError
|
||||
|
||||
|
||||
class GQLError(Exception):
|
||||
def __init__(self, errors):
|
||||
super().__init__("GraphQL query failed")
|
||||
self.errors = errors
|
||||
|
||||
|
||||
def authenticated_get(url, params={}, headers={}):
|
||||
headers['Client-ID'] = CLIENT_ID
|
||||
|
||||
@ -46,7 +52,12 @@ def kraken_get(url, params={}, headers={}):
|
||||
def gql_query(query):
|
||||
url = "https://gql.twitch.tv/gql"
|
||||
payload = {"query": query}
|
||||
return authenticated_post(url, json={"query": query}).json()
|
||||
response = authenticated_post(url, json={"query": query}).json()
|
||||
|
||||
if "errors" in response:
|
||||
raise GQLError(response["errors"])
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def get_video(video_id):
|
||||
@ -86,13 +97,15 @@ def get_clip(slug):
|
||||
return response["data"]["clip"]
|
||||
|
||||
|
||||
def get_channel_videos(channel_id, limit, sort, type="archive", after=None):
|
||||
def get_channel_videos(channel_id, limit, sort, type="archive", game_ids=[], after=None):
|
||||
url = "https://gql.twitch.tv/gql"
|
||||
|
||||
query = """
|
||||
{{
|
||||
user(login: "{channel_id}") {{
|
||||
videos(options: {{ }}, first: {limit}, type: {type}, sort: {sort}, after: "{after}") {{
|
||||
videos(options: {{
|
||||
gameIDs: {game_ids}
|
||||
}}, first: {limit}, type: {type}, sort: {sort}, after: "{after}") {{
|
||||
totalCount
|
||||
edges {{
|
||||
cursor
|
||||
@ -119,6 +132,7 @@ def get_channel_videos(channel_id, limit, sort, type="archive", after=None):
|
||||
|
||||
query = query.format(**{
|
||||
"channel_id": channel_id,
|
||||
"game_ids": game_ids,
|
||||
"after": after,
|
||||
"limit": limit,
|
||||
"sort": sort.upper(),
|
||||
@ -129,10 +143,15 @@ def get_channel_videos(channel_id, limit, sort, type="archive", after=None):
|
||||
return response["data"]["user"]["videos"]
|
||||
|
||||
|
||||
def channel_videos_generator(channel_id, limit, sort, type):
|
||||
def channel_videos_generator(channel_id, limit, sort, type, game_ids=None):
|
||||
cursor = None
|
||||
while True:
|
||||
videos = get_channel_videos(channel_id, limit, sort, type, after=cursor)
|
||||
videos = get_channel_videos(
|
||||
channel_id, limit, sort, type, game_ids=game_ids, after=cursor)
|
||||
|
||||
if not videos["edges"]:
|
||||
break
|
||||
|
||||
cursor = videos["edges"][-1]["cursor"]
|
||||
|
||||
yield videos, cursor is not None
|
||||
@ -161,3 +180,18 @@ def get_playlists(video_id, access_token):
|
||||
})
|
||||
response.raise_for_status()
|
||||
return response.content.decode('utf-8')
|
||||
|
||||
|
||||
def get_game_id(name):
|
||||
query = """
|
||||
{{
|
||||
game(name: "{}") {{
|
||||
id
|
||||
}}
|
||||
}}
|
||||
"""
|
||||
|
||||
response = gql_query(query.format(name.strip()))
|
||||
game = response["data"]["game"]
|
||||
if game:
|
||||
return game["id"]
|
||||
|
Loading…
Reference in New Issue
Block a user