introduced: requirements.txt, colored output (with ANSI escape codes), baked in failsafe when config file does not exist, slight improvements to ythdd.py

This commit is contained in:
2024-11-02 01:21:06 +01:00
parent 1fb14a5718
commit c60f7db698
3 changed files with 62 additions and 15 deletions

11
requirements.txt Normal file
View File

@@ -0,0 +1,11 @@
# For pacman-based distros: sudo pacman -S python-flask python-flask-sqlalchemy python-toml
blinker>=1.7.0
itsdangerous>=2.1.2
Jinja2>=3.1.4
MarkupSafe>=2.1.5
Werkzeug>=3.0.1
Flask>=2.3.3
greenlet>=3.1.0
SQLAlchemy>=2.0.36.dev0
Flask-SQLAlchemy>=3.1.1
toml>=0.10.2

View File

@@ -2,17 +2,19 @@
from flask import Flask, render_template from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from markupsafe import escape from markupsafe import escape
#from argparse import ArgumentParser
from ythdd_globals import config, colors
import requests, json, toml, time import requests, json, toml, time
import views, downloader, ythdd_api, ythdd_globals, ythdd_db import views, downloader, ythdd_api, ythdd_globals, ythdd_db
ythdd_globals.starttime = int(time.time()) ythdd_globals.starttime = int(time.time())
ythdd_globals.apiRequests = 0 ythdd_globals.apiRequests = 0
ythdd_globals.apiFailedRequests = 0 ythdd_globals.apiFailedRequests = 0
ythdd_globals.isProxied = ythdd_globals.config['general']['is_proxied'] ythdd_globals.isProxied = config['general']['is_proxied']
ythdd_globals.outsideApiHits = 0 ythdd_globals.outsideApiHits = 0
app = Flask(__name__) app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = f"sqlite:///{ythdd_globals.config["general"]["db_file_path"]}" app.config['SQLALCHEMY_DATABASE_URI'] = f"sqlite:///{config['general']['db_file_path']}"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.add_url_rule('/', view_func=views.index) app.add_url_rule('/', view_func=views.index)
app.add_url_rule('/index.html', view_func=views.index) app.add_url_rule('/index.html', view_func=views.index)
@@ -30,11 +32,23 @@ def blank(val):
#users = db.session.query(LocalUsers).all() #users = db.session.query(LocalUsers).all()
#return users #return users
if __name__ == "__main__": def main():
print("welcome to ythdd") print(f"{colors.BOLD + colors.HEADER}Welcome to ythdd ({ythdd_globals.version})!{colors.ENDC}")
print("to run locally, use ip 127.0.0.1. to run on all interfaces, use 0.0.0.0.") print(f"To run in development mode (to see changes updated live), use: {colors.OKCYAN}flask --app ythdd run --debug{colors.ENDC}.")
print("enter hostname:port to run flask app on:") print("To run locally, use IP 127.0.0.1. To run on all interfaces, use 0.0.0.0.\n")
print("Enter hostname:port to run Flask app on [127.0.0.1:5000]:")
try:
host_port = input('> ').split(':') host_port = input('> ').split(':')
if host_port == ['']:
host_port = ['127.0.0.1', '5000'] # defaults
except KeyboardInterrupt:
print(" ...exiting gracefully."), quit() # handle Ctrl+C
app.run(host=host_port[0], port=int(host_port[1]))
if __name__ == "__main__":
#app.run(host="127.0.0.1", port=5000) #app.run(host="127.0.0.1", port=5000)
#app.run(host="0.0.0.0", port=5000) #app.run(host="0.0.0.0", port=5000)
app.run(host=host_port[0], port=int(host_port[1])) # TODO: add argument parser to load config files, etc.
main()

View File

@@ -1,17 +1,39 @@
#!/usr/bin/python3 #!/usr/bin/python3
import time, toml import time, toml, os
global starttime, apiRequests, apiFailedRequests, outsideApiHits, config, version, apiVersion global starttime, apiRequests, apiFailedRequests, outsideApiHits, config, version, apiVersion, colors
#def init(): class colors:
# starttime = int(time.time()) HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKCYAN = '\033[96m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
ENDL = '\n'
#def notImplemented(data): def notImplemented(name):
# return 501, f"not recognised/implemented: {data[0]}", [] return 501, f"not recognised/implemented: {name}", []
config = toml.load("config.toml") configfile = "config.toml" # TODO: implement a way to specify alternative config file path
version = "0.0.1" version = "0.0.1"
apiVersion = "1" apiVersion = "1"
# TODO: turn this into function, to make setting configfile with argparser (and effectively using a custom config file) possible
if not os.path.exists(configfile):
# use dummy default config, TODO: update this in the near future
config = {'general': {'db_file_path': 'ythdd_db.sqlite', 'video_storage_directory_path': 'videos/', 'is_proxied': False}, 'api': {'api_key': 'CHANGEME', 'api_key_admin': str(int(time.time()*1337 % 899_999 + 100_000))}, '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'}]}}
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}).")
print(f"{colors.WARNING}WARNING{colors.ENDC}: Default config populated with one-time, insecure pseudorandom admin API key: {colors.OKCYAN}{config['api']['api_key_admin']}{colors.ENDC}."
f" {colors.ENDL}You need to provide a config file for persistence!{colors.ENDL}")
#with open(configfile, "w") as file:
# file.write(toml.dumps(config))
else:
config = toml.load(configfile)
def getUptime(): def getUptime():
return int(time.time()) - starttime return int(time.time()) - starttime