diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..13861a6 --- /dev/null +++ b/requirements.txt @@ -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 diff --git a/ythdd.py b/ythdd.py index 4d41621..c041c8d 100644 --- a/ythdd.py +++ b/ythdd.py @@ -2,17 +2,19 @@ from flask import Flask, render_template from flask_sqlalchemy import SQLAlchemy from markupsafe import escape +#from argparse import ArgumentParser +from ythdd_globals import config, colors import requests, json, toml, time import views, downloader, ythdd_api, ythdd_globals, ythdd_db ythdd_globals.starttime = int(time.time()) ythdd_globals.apiRequests = 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 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.add_url_rule('/', 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() #return users +def main(): + print(f"{colors.BOLD + colors.HEADER}Welcome to ythdd ({ythdd_globals.version})!{colors.ENDC}") + print(f"To run in development mode (to see changes updated live), use: {colors.OKCYAN}flask --app ythdd run --debug{colors.ENDC}.") + 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(':') + 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__": - print("welcome to ythdd") - print("to run locally, use ip 127.0.0.1. to run on all interfaces, use 0.0.0.0.") - print("enter hostname:port to run flask app on:") - host_port = input('> ').split(':') #app.run(host="127.0.0.1", port=5000) #app.run(host="0.0.0.0", port=5000) - app.run(host=host_port[0], port=int(host_port[1])) \ No newline at end of file + # TODO: add argument parser to load config files, etc. + main() diff --git a/ythdd_globals.py b/ythdd_globals.py index d88c4c1..96b3520 100644 --- a/ythdd_globals.py +++ b/ythdd_globals.py @@ -1,17 +1,39 @@ #!/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(): -# starttime = int(time.time()) +class colors: + 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): -# return 501, f"not recognised/implemented: {data[0]}", [] +def notImplemented(name): + 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" 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(): - return int(time.time()) - starttime \ No newline at end of file + return int(time.time()) - starttime