fix: backport fixes from a sister project
This commit is contained in:
@@ -3,6 +3,7 @@ db_file_path = "/path/to/ythdd_db.sqlite" # Preferably stored on an SSD
|
||||
video_storage_directory_path = "/path/to/videos/" # Path to video vault.
|
||||
is_proxied = false # Set to true if running behind reverse proxy.
|
||||
public_facing_url = "http://localhost:5000/" # Used for URL rewriting. Note the trailing backslash /.
|
||||
debug = false # Whether to print verbose, debug info on API endpoints.
|
||||
|
||||
[api]
|
||||
api_key = "" # Leave empty API key for public access to non-sensitive backend
|
||||
|
||||
3
ythdd.py
3
ythdd.py
@@ -53,6 +53,9 @@ def setup():
|
||||
sanity_string += f" If you're running a reverse proxy, set {colors.OKCYAN}is_proxied{colors.ENDC} to true to silence this message.\n"
|
||||
print(sanity_string)
|
||||
|
||||
# Should work around disconnects: https://stackoverflow.com/a/61739721
|
||||
app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {"pool_pre_ping": True}
|
||||
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = f"sqlite:///{config['general']['db_file_path']}"
|
||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||
app.add_url_rule('/', view_func=views.index)
|
||||
|
||||
15
ythdd_api.py
15
ythdd_api.py
@@ -4,6 +4,7 @@ from markupsafe import escape
|
||||
import requests, time, json
|
||||
import ythdd_globals
|
||||
import ythdd_api_v1, ythdd_inv_tl
|
||||
import traceback
|
||||
|
||||
def api_greeting():
|
||||
string = {'status': 200, 'msg': f"ok (ythdd {ythdd_globals.version})", 'latest_api': f"v{ythdd_globals.apiVersion}"}
|
||||
@@ -25,10 +26,15 @@ def api_global_catchall(received_request):
|
||||
#return api_greeting()
|
||||
resp = api_greeting()
|
||||
try:
|
||||
status, received, data = ythdd_api_v1.lookup(request_list)
|
||||
status, received, data = ythdd_api_v1.lookup(request_list, request)
|
||||
except Exception as e:
|
||||
ythdd_globals.apiFailedRequests += 1
|
||||
stripped_filename = __file__[max(__file__.rfind("/"), __file__.rfind("\\")) + 1:]
|
||||
print(f"\n{c.FAIL}Error! /api/{received_request} -> {stripped_filename}:L{e.__traceback__.tb_lineno} -> {type(e).__name__}{c.ENDC}:"
|
||||
+ f"{traceback.format_exc()}")
|
||||
status, received, data = 500, f"internal server error: call ended in failure: {e}", []
|
||||
if ythdd_globals.config["general"]["debug"]:
|
||||
status, received, data = 500, f"internal server error: call ended in failure: {e} ({stripped_filename}:L{e.__traceback__.tb_lineno})", []
|
||||
resp = Response(json.dumps({'status': status, 'msg': received, 'data': data}), mimetype='application/json', status=status)
|
||||
elif request_list[0] == 'invidious':
|
||||
# drop 'invidious' from the list
|
||||
@@ -43,12 +49,17 @@ def api_global_catchall(received_request):
|
||||
# if a path has been supplied try to get appropriate data
|
||||
try:
|
||||
# lookup and construct a response
|
||||
resp = ythdd_inv_tl.lookup(request_list)
|
||||
resp = ythdd_inv_tl.lookup(request_list, request)
|
||||
#print(resp) # for debugging purposes
|
||||
# unless an error occurs
|
||||
except Exception as e:
|
||||
ythdd_globals.apiFailedRequests += 1
|
||||
stripped_filename = __file__[max(__file__.rfind("/"), __file__.rfind("\\")) + 1:]
|
||||
print(f"\n{c.FAIL}Error! /api/{received_request} -> {stripped_filename}:L{e.__traceback__.tb_lineno} -> {type(e).__name__}{c.ENDC}:"
|
||||
+ f"{traceback.format_exc()}")
|
||||
status, received, data = 500, f"internal server error: invidious translation call ended in failure: {e}", []
|
||||
if ythdd_globals.config["general"]["debug"]:
|
||||
status, received, data = 500, f"internal server error: invidious translation call ended in failure: {e} ({stripped_filename}:L{e.__traceback__.tb_lineno})", []
|
||||
resp = Response(json.dumps({'status': status, 'msg': received, 'data': data}), mimetype='application/json', status=status)
|
||||
else:
|
||||
ythdd_globals.apiFailedRequests += 1
|
||||
|
||||
@@ -8,6 +8,20 @@ import ythdd_globals, ythdd_extractor
|
||||
#from flask_sqlalchemy import SQLAlchemy
|
||||
#import ythdd_api_v1_stats, ythdd_api_v1_user, ythdd_api_v1_info, ythdd_api_v1_query, ythdd_api_v1_meta, ythdd_api_v1_admin
|
||||
|
||||
def requireAuthentication(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
token = kwargs["r"].args.get('token')
|
||||
if token == lewy_globals.config['api']['api_key']:
|
||||
try:
|
||||
status, received, data = func(*args, **kwargs)
|
||||
return status, received, data
|
||||
except:
|
||||
raise AssertionError(f"Function \"{func.__name__}\" does not return status, code, and data as it should!")
|
||||
else:
|
||||
return 401, "error", {'error_msg': "Unauthorized"}
|
||||
return wrapper
|
||||
|
||||
def incrementBadRequests():
|
||||
ythdd_globals.apiFailedRequests += 1
|
||||
|
||||
@@ -29,7 +43,7 @@ def stats():
|
||||
"outside_api_requests": ythdd_globals.outsideApiHits,
|
||||
"local_api_requests": ythdd_globals.apiRequests - ythdd_globals.outsideApiHits
|
||||
}
|
||||
return 200, "OK", data_to_send
|
||||
return 200, "ok", data_to_send
|
||||
|
||||
def videoIdSanityCheck(videoId: str):
|
||||
if len(videId) != 11:
|
||||
@@ -129,7 +143,7 @@ def hot(data):
|
||||
incrementBadRequests()
|
||||
return notImplemented([data[1]]) # workaround before notImplemented is reworked
|
||||
|
||||
def lookup(data):
|
||||
def lookup(data, request):
|
||||
match data[0]:
|
||||
case 'stats':
|
||||
return stats()
|
||||
|
||||
@@ -30,7 +30,7 @@ def getConfig(configfile):
|
||||
global randomly_generated_passcode
|
||||
|
||||
if not os.path.exists(configfile):
|
||||
dummy_config = {'general': {'db_file_path': 'ythdd_db.sqlite', 'video_storage_directory_path': 'videos/', 'is_proxied': False, 'public_facing_url': 'http://localhost:5000/'}, 'api': {'api_key': 'CHANGEME'}, 'extractor': {'user-agent': '', 'cookies_path': ''}, 'admin': {'admins': ['admin']}, 'yt_dlp': {}, 'postprocessing': {'presets': [{'name': 'recommended: [N][<=720p] best V+A', 'format': 'bv[height<=720]+ba', 'reencode': ''}, {'name': '[N][1080p] best V+A', 'format': 'bv[height=1080]+ba', 'reencode': ''}, {'name': '[R][1080p] webm', 'format': 'bv[height=1080]+ba', 'reencode': 'webm'}, {'name': '[N][720p] best V+A', 'format': 'bv[height=720]+ba', 'reencode': ''}, {'name': '[R][720p] webm', 'format': 'bv[height=720]+ba', 'reencode': 'webm'}, {'name': '[N][480p] best V+A', 'format': 'bv[height=480]+ba', 'reencode': ''}, {'name': '[480p] VP9 webm/reencode', 'format': 'bv*[height=480][ext=webm]+ba/bv[height=480]+ba', 'reencode': 'webm'}, {'name': '[N][1080p] best video only', 'format': 'bv[height=1080]', 'reencode': ''}, {'name': '[N][opus] best audio only', 'format': 'ba', 'reencode': 'opus'}]}}
|
||||
dummy_config = {'general': {'db_file_path': 'ythdd_db.sqlite', 'video_storage_directory_path': 'videos/', 'is_proxied': False, 'public_facing_url': 'http://localhost:5000/', 'debug': False}, 'api': {'api_key': 'CHANGEME'}, 'extractor': {'user-agent': '', 'cookies_path': ''}, 'admin': {'admins': ['admin']}, 'yt_dlp': {}, 'postprocessing': {'presets': [{'name': 'recommended: [N][<=720p] best V+A', 'format': 'bv[height<=720]+ba', 'reencode': ''}, {'name': '[N][1080p] best V+A', 'format': 'bv[height=1080]+ba', 'reencode': ''}, {'name': '[R][1080p] webm', 'format': 'bv[height=1080]+ba', 'reencode': 'webm'}, {'name': '[N][720p] best V+A', 'format': 'bv[height=720]+ba', 'reencode': ''}, {'name': '[R][720p] webm', 'format': 'bv[height=720]+ba', 'reencode': 'webm'}, {'name': '[N][480p] best V+A', 'format': 'bv[height=480]+ba', 'reencode': ''}, {'name': '[480p] VP9 webm/reencode', 'format': 'bv*[height=480][ext=webm]+ba/bv[height=480]+ba', 'reencode': 'webm'}, {'name': '[N][1080p] best video only', 'format': 'bv[height=1080]', 'reencode': ''}, {'name': '[N][opus] best audio only', 'format': 'ba', 'reencode': 'opus'}]}}
|
||||
# if a passcode has not been provided by the user (config file doesn't exist, and user didn't specify it using an argument)
|
||||
print(f"{colors.WARNING}WARNING{colors.ENDC}: Using default, baked in config data. {colors.ENDL}"
|
||||
f" Consider copying and editing the provided example file ({colors.OKCYAN}config.default.toml{colors.ENDC}).")
|
||||
@@ -99,8 +99,15 @@ def safeTraverse(obj: dict, path: list, default=None):
|
||||
for x in path:
|
||||
#print(f"traversing {result} with respect to {x}")
|
||||
result = result[x]
|
||||
except KeyError:
|
||||
except (KeyError, TypeError):
|
||||
result = default
|
||||
print(f"error reading: {' -> '.join(path)} - returning: {default}")
|
||||
finally:
|
||||
return result
|
||||
|
||||
def getCommit() -> str | None:
|
||||
try:
|
||||
return Repo(search_parent_directories=True).head.object.hexsha
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
|
||||
@@ -451,7 +451,7 @@ def videos(data):
|
||||
|
||||
return send(status_code, response)
|
||||
|
||||
def lookup(data):
|
||||
def lookup(data, request):
|
||||
# possibly TODO: rewrite this mess
|
||||
if len(data) > 2:
|
||||
if (data[0], data[1]) == ("api", "v1"):
|
||||
|
||||
Reference in New Issue
Block a user