#!/usr/bin/python3 from flask import Flask, render_template from flask_sqlalchemy import SQLAlchemy from markupsafe import escape from argparse import ArgumentParser from ythdd_globals import colors import requests, json, toml, time import views, downloader, ythdd_api, ythdd_globals, ythdd_db import os from flask_apscheduler import APScheduler app = Flask(__name__) app_host = "None" app_port = "None" def setup(): # sanity check: make sure config is set # required to make `flask --app ythdd run --debug` work global config, app_host, app_port try: if not config['general']: ythdd_globals.setConfig(ythdd_globals.configfile) config = ythdd_globals.config except: ythdd_globals.setConfig(ythdd_globals.configfile) config = ythdd_globals.config # setting all the variables ythdd_globals.starttime = int(time.time()) ythdd_globals.realUptime = 0 ythdd_globals.apiRequests = 0 ythdd_globals.apiFailedRequests = 0 ythdd_globals.isProxied = config['general']['is_proxied'] ythdd_globals.outsideApiHits = 0 are_we_sure_of_host_and_port = True if app_host == "None": app_host = "127.0.0.1" are_we_sure_of_host_and_port = False if app_port == "None": app_port = "5000" are_we_sure_of_host_and_port = False public_facing_url = config['general']['public_facing_url'] rewrite_sanity_check = public_facing_url.replace(f"{app_host}:{app_port}", "") if not config['general']['is_proxied'] and public_facing_url == rewrite_sanity_check: sanity_string = f"{colors.WARNING}Heads up!{colors.ENDC} Public facing URL does not match the IP and port the server is running on.\n" sanity_string += f" Expected: {colors.OKCYAN}{config['general']['public_facing_url']}{colors.ENDC}, but" if not are_we_sure_of_host_and_port: sanity_string += " (assuming it's)" sanity_string += f" running on: {colors.OKCYAN}{app_host}:{app_port}{colors.ENDC}.\n" sanity_string += f" This is just a sanity check and may not neccessarily mean bad configuration.\n" 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) app.add_url_rule('/index.html', view_func=views.index) app.add_url_rule('/home', view_func=views.home) app.add_url_rule('/api/', view_func=ythdd_api.api_greeting) app.add_url_rule('/api/', view_func=ythdd_api.api_global_catchall) app.add_url_rule('/vi/', view_func=views.thumbnailProxy) app.add_url_rule('/ggpht/', view_func=views.ggphtProxy) app.add_url_rule('/guc/', view_func=views.gucProxy) app.add_url_rule('/img/', view_func=views.imgProxy) db = ythdd_db.initDB(app, config) with app.app_context(): db.create_all() # job scheduler for repetetive tasks scheduler = APScheduler() scheduler.add_job(func=every5seconds, trigger='interval', id='job', seconds=5) scheduler.start() # gets called every 5 seconds def every5seconds(): # update the "real" uptime counter ythdd_globals.realUptime += 5 @app.route('/', methods=['GET']) def blank(val): return f"{val}: not implemented in ythdd {ythdd_globals.version}" #users = db.session.query(LocalUsers).all() #return users def main(args): 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") try: host = args.ip port = args.port if not host or not port: raise Exception except: 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 host = host_port[0] port = host_port[1] global config, app_host, app_port try: # if specified, use custom config file ythdd_globals.configfile = args.config ythdd_globals.setConfig(ythdd_globals.configfile) except: # if not, try using the default "config.toml" if os.path.exists("config.toml"): ythdd_globals.configfile = "config.toml" else: # unless it's not there, if that's the case then use the dummy file ythdd_globals.configfile = "" # but try to set the API secret if provided by the user if args.secret: ythdd_globals.randomly_generated_passcode = args.secret ythdd_globals.setConfig(ythdd_globals.configfile) config = ythdd_globals.config app_host = host app_port = port setup() app.run(host=host, port=int(port)) if __name__ == "__main__": #app.run(host="127.0.0.1", port=5000) #app.run(host="0.0.0.0", port=5000) parser = ArgumentParser(description='A basic yt_dlp-based script for video download.') parser.add_argument("-i", "--ip", dest="ip", help="ip address/interface to bind to") parser.add_argument("-p", "--port", dest="port", help="port on which the flask web backend should be ran") parser.add_argument("-c", "--config", dest="config", help="path to TOML config file") parser.add_argument("-s", "--secret", dest="secret", help="admin's secret passcode for sensitive API access") args = parser.parse_args() main(args) else: app_host = os.getenv("FLASK_RUN_HOST", "None") app_port = os.getenv("FLASK_RUN_PORT", "None") setup()