Skip to content

Commit

Permalink
Merge pull request #81 from offish/v1.6.6
Browse files Browse the repository at this point in the history
v1.6.6
  • Loading branch information
offish authored Sep 21, 2021
2 parents 22bc9a1 + 0101dd1 commit b68b486
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 162 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
venv
.idea
clips
*.pyc
5 changes: 3 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
moviepy==1.0.3
colorama
colorama~=0.4.4
selenium
opplast
opplast~=1.0.7
requests~=2.26.0
2 changes: 1 addition & 1 deletion twitchtube/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__title__ = "twitchtube"
__author__ = "offish"
__license__ = "MIT"
__version__ = "1.6.5"
__version__ = "1.6.6"
22 changes: 5 additions & 17 deletions twitchtube/api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import json

import requests

local = locals()
Expand All @@ -19,23 +17,13 @@ def data(slug: str, oauth_token: str, client_id: str) -> requests.Response:
)


def game(game_list: list, oauth_token: str, client_id: str) -> requests.Response:
# returns data about every specified name of the game (including it's id)
# e.g. [Minecraft] -> {'id': '27471', 'name': 'Minecraft',
# 'box_art_url': 'https://static-cdn.jtvnw.net/ttv-boxart/Minecraft-{width}x{height}.jpg'}
return request(
"helix/games",
{"Authorization": "Bearer " + oauth_token, "Client-Id": client_id},
{"name": game_list}
)


def user(user_list: list, oauth_token: str, client_id: str) -> requests.Response:
# just like game() but for users
def helix(
category: str, data: list, oauth_token: str, client_id: str
) -> requests.Response:
return request(
"helix/users",
"helix/" + category,
{"Authorization": "Bearer " + oauth_token, "Client-Id": client_id},
{"login": user_list}
{"login" if category == "users" else "name": data},
)


Expand Down
74 changes: 35 additions & 39 deletions twitchtube/clips.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import datetime
from math import ceil
from json import dump
import urllib.request
import re
import urllib.request

from .logging import Log
from .utils import format_blacklist, is_blacklisted
from .api import get

log = Log()
from .logging import Log as log
from .utils import format_blacklist, is_blacklisted


def get_data(slug: str, oauth_token: str, client_id: str) -> dict:
"""
Gets the data from a given slug,
returns a JSON respone from the Helix API endpoint
returns a JSON response from the Helix API endpoint
"""
response = get("data", slug=slug, oauth_token=oauth_token, client_id=client_id)

Expand Down Expand Up @@ -100,26 +96,24 @@ def get_clips(
Gets the top clips for given game, returns JSON response
from the Helix API endpoint.
"""
data = {}
new_ids = []
new_titles = []

headers = {"Accept": "application/vnd.twitchtv.v5+json", "Client-ID": client_id}

# params = {"period": period, "limit": limit}
params = {
"ended_at": datetime.datetime.now(datetime.timezone.utc).isoformat(),
"started_at": (
datetime.datetime.now(datetime.timezone.utc)
- datetime.timedelta(hours=period)
).isoformat(),
"first": limit,
}

if category == "channel":
params["broadcaster_id"] = id_
else:
params["game_id"] = id_
if period:
params = {
**params,
"ended_at": datetime.datetime.now(datetime.timezone.utc).isoformat(),
"started_at": (
datetime.datetime.now(datetime.timezone.utc)
- datetime.timedelta(hours=period)
).isoformat(),
}

params["broadcaster_id" if category == "channel" else "game_id"] = id_

log.info(f"Getting clips for {category} {name}")

Expand All @@ -129,17 +123,18 @@ def get_clips(
if response.get("error") == "Internal Server Error":
# the error is twitch's fault, we try again
get_clips(
blacklist,
category,
name,
path,
seconds,
ids,
client_id,
oauth_token,
period,
language,
limit,
blacklist=blacklist,
category=category,
id_=id_,
name=name,
path=path,
seconds=seconds,
ids=ids,
client_id=client_id,
oauth_token=oauth_token,
period=period,
language=language,
limit=limit,
)

else:
Expand All @@ -150,6 +145,10 @@ def get_clips(
formatted_blacklist = format_blacklist(blacklist, oauth_token, client_id)

if "data" in response:
data = {}
new_ids = []
new_titles = []

for clip in response["data"]:
clip_id = clip["id"]
duration = clip["duration"]
Expand Down Expand Up @@ -183,12 +182,9 @@ def download_clips(data: dict, path: str, oauth_token: str, client_id: str) -> l
"""
names = []

for clip in data:
download_clip(data[clip]["url"], path, oauth_token, client_id)

name = data[clip]["display_name"]

names.append(name)
for clip, value in data.items():
download_clip(value["url"], path, oauth_token, client_id)
names.append(data[clip]["display_name"])

log.info(f"Downloaded {len(data)} clips from this batch.\n")
log.info(f"Downloaded {len(data)} clips from this batch\n")
return names
6 changes: 3 additions & 3 deletions twitchtube/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
# twitch
CLIENT_ID = "" # Twitch Client ID
OAUTH_TOKEN = "" # Twitch OAuth Token
PERIOD = 24 # how many hours since the clip's creation should've passed e.g. 24, 48 etc
PERIOD = 24 # how many hours since the clip's creation should've passed e.g. 24, 48 etc 0 for all time
LANGUAGE = "en" # en, es, th etc.
LIMIT = 100 # 1-100

Expand All @@ -36,9 +36,9 @@
RESOLUTION = (
720,
1280,
) # Resoultion of the rendered video (height, width) for 1080p: ((1080, 1920))
) # Resolution of the rendered video (height, width) for 1080p: ((1080, 1920))
FRAMES = 30 # Frames per second (30/60)
VIDEO_LENGTH = 10.5 # Minumum video length in minutes (doesn't always work)
VIDEO_LENGTH = 10.5 # Minimum video length in minutes (doesn't always work)
RESIZE_CLIPS = True # Resize clips to fit RESOLUTION (True/False) If any RESIZE option is set to False the video might end up having a weird resolution
FILE_NAME = "rendered" # Name of the rendered video
ENABLE_INTRO = False # Enable (True/False)
Expand Down
16 changes: 10 additions & 6 deletions twitchtube/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
class InvalidCategory(Exception):
pass
class TwitchTubeError(Exception):
""" General error class for TwitchTube."""


class VideoPathAlreadyExists(Exception):
pass
class InvalidCategory(TwitchTubeError):
""" Error for when the specified category is invalid """


class NoClipsFound(Exception):
pass
class VideoPathAlreadyExists(TwitchTubeError):
""" Error for when a path already exists. """


class NoClipsFound(TwitchTubeError):
""" Error for when no clips are found. """
15 changes: 10 additions & 5 deletions twitchtube/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,22 @@ def log(color: int, sort: str, text: str) -> None:


class Log:
def info(self, text: str):
@staticmethod
def info(text: str):
log(f.GREEN, "info", text)

def error(self, text: str):
@staticmethod
def error(text: str):
log(f.RED, "error", text)

def warn(self, text: str):
@staticmethod
def warn(text: str):
log(f.YELLOW, "warn", text)

def clip(self, text: str):
@staticmethod
def clip(text: str):
log(f.CYAN, "clip", text)

def debug(self, text: str):
@staticmethod
def debug(text: str):
log(f.BLUE, "debug", text)
106 changes: 45 additions & 61 deletions twitchtube/utils.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from datetime import date
from string import ascii_lowercase, digits
from random import choice
from string import ascii_lowercase, digits

import requests

from .api import get
from .exceptions import InvalidCategory
from .config import CLIP_PATH

from requests import get as rget
from .exceptions import InvalidCategory


def get_date() -> str:
Expand All @@ -24,14 +24,12 @@ def get_path() -> str:


def get_description(description: str, names: list) -> str:
for name in names:
description += f"https://twitch.tv/{name}\n"
return description
return description + "".join([f"https://twitch.tv/{name}\n" for name in names])


def get_current_version(project: str) -> str:
txt = '__version__ = "'
response = rget(
response = requests.get(
f"https://raw.githubusercontent.com/offish/{project}/master/{project}/__init__.py"
).text
response = response[response.index(txt) :].replace(txt, "")
Expand All @@ -58,15 +56,12 @@ def create_video_config(


def get_category(category: str) -> str:
if category == "g" or category == "game":
return "game"
if category not in ["g", "game", "c", "channel"]:
raise InvalidCategory(
category + ' is not supported. Use "g", "game", "c" or "channel"'
)

if category == "c" or category == "channel":
return "channel"

raise InvalidCategory(
category + ' is not supported. Use "g", "game", "c" or "channel"'
)
return "game" if category in ["g", "game"] else "channel"


def get_category_and_name(entry: str) -> (str, str):
Expand All @@ -76,38 +71,36 @@ def get_category_and_name(entry: str) -> (str, str):
return category, name


def convert_name_to_ids(data: list, oauth_token: str, client_id: str) -> list:
# all data that is gets
new_data = []
users_to_check, games_to_check = [], []
user_info, game_info = [], []

for entry in data:
category, name = get_category_and_name(entry)
if category == "channel":
users_to_check.append(name)
elif category == "game":
games_to_check.append(name)

# if there are more than 100 entries in users_to_check or games_to_check, this *WILL NOT WORK*
if users_to_check:
user_info = get(
"user",
user_list=users_to_check,
oauth_token=oauth_token,
client_id=client_id,
)["data"]
if games_to_check:
game_info = get(
"game",
game_list=games_to_check,
oauth_token=oauth_token,
client_id=client_id,
)["data"]

return [("channel", i["id"], i["display_name"]) for i in user_info] + [
("game", i["id"], i["name"]) for i in game_info
]
def name_to_ids(data: list, oauth_token: str, client_id: str) -> list:
result = []

for category, helix_category, helix_name in [
(["channel", "c"], "users", "display_name"),
(["game", "g"], "games", "name"),
]:
current_list = []

for entry in data:
c, n = get_category_and_name(entry)

if c in category:
current_list.append(n)

if len(current_list) > 0:
info = (
get(
"helix",
category=helix_category,
data=current_list,
oauth_token=oauth_token,
client_id=client_id,
).get("data")
or []
)

result += [(category[0], i["id"], i[helix_name]) for i in info]

return result


def remove_blacklisted(data: list, blacklist: list) -> (bool, list):
Expand All @@ -130,19 +123,10 @@ def remove_blacklisted(data: list, blacklist: list) -> (bool, list):


def format_blacklist(blacklist: list, oauth_token: str, client_id: str) -> list:
formatted = convert_name_to_ids(blacklist, oauth_token, client_id)
return [f"{i[0]} {i[1]}" for i in formatted]
return [f"{i[0]} {i[1]}" for i in name_to_ids(blacklist, oauth_token, client_id)]


def is_blacklisted(clip: dict, blacklist: list) -> bool:
if "broadcaster_id" in clip:
if "channel " + clip["broadcaster_id"].lower() in [
i.lower() for i in blacklist
]:
return True

if clip.get("game_id"):
if "game " + clip["game_id"] in blacklist:
return True

return False
return (
"broadcaster_id" in clip and "channel " + clip["broadcaster_id"] in blacklist
) or ("game_id" in clip and "game " + clip["game_id"] in blacklist)
Loading

0 comments on commit b68b486

Please sign in to comment.