MediaDash/app.py

235 lines
6.9 KiB
Python

import sys # isort:skip
from gevent import monkey # isort:skip
if __name__ == "__main__" and "--debug" not in sys.argv[1:]:
monkey.patch_all()
import os
import requests as RQ
from flask import (
Flask,
abort,
flash,
redirect,
render_template,
request,
send_file,
send_from_directory,
session,
url_for,
)
from flask_bootstrap import Bootstrap
from flask_debugtoolbar import DebugToolbarExtension
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
from flask_login import LoginManager, current_user
from flask_login import login_user, logout_user
from flask_nav import Nav, register_renderer
from flask_nav.elements import Navbar, Text, View
from flask_session import Session
from flask_wtf.csrf import CSRFProtect
import stats_collect
from api.user import JellyfinUser
from forms import LoginForm
from models import RequestUser, db
from transcode import profiles
from utils import (
BootsrapRenderer,
handle_config,
is_safe_url,
login_required,
make_placeholder_image,
setup_template_filters,
with_application_context,
)
from views import register_blueprints
def left_nav():
requests_badge = None
if current_user.is_authenticated:
num_notifications = RequestUser.query.filter(
(RequestUser.user_id == current_user.id) & (
RequestUser.updated is True)).count()
if num_notifications > 0:
requests_badge = (num_notifications, "danger")
links = [
View("Home", "home.index"),
View("Requests", "requests.index", __badge=requests_badge),
View("Containers", "containers.index", container_id=None),
View("qBittorrent", "qbittorrent.index", infohash=None),
View("Sonarr", "sonarr.index"),
View("Radarr", "radarr.index"),
View("Jellyfin", "jellyfin.index"),
View("Search", "search.index"),
View("History", "history.index"),
View("Transcode", "transcode.index"),
View("Config", "config.index"),
View("Remote", "remote.index"),
View("Log", "log.index"),
]
if current_user.is_authenticated:
links.append(View("Logout", "logout"))
links[-1].classes = ["btn", "btn-danger", "my-2", "my-sm-0"]
else:
links.append(View("Login", "login"))
links[-1].classes = ["btn", "btn-success", "my-2", "my-sm-0"]
for n, link in enumerate(links):
adapter = app.url_map.bind("localhost")
name, args = adapter.match(link.get_url(), method="GET")
func = app.view_functions[name]
if getattr(func, "requires_login", False):
if not current_user.is_authenticated:
links[n] = None
if getattr(func, "requires_admin", False):
if not (current_user.is_authenticated and current_user.is_admin):
links[n] = None
links = list(filter(None, links))
return Navbar("PirateDash", *links)
def right_nav():
if current_user.is_authenticated:
return Text(current_user["Name"])
else:
return Text("")
def create_app():
templates = os.path.join(
os.path.dirname(
os.path.abspath(__file__)),
"templates")
app = Flask(__name__, template_folder=templates)
app.config.from_pyfile("config.cfg")
app.bootstrap = Bootstrap(app)
app.csrf = CSRFProtect(app)
app.nav = Nav(app)
app.toolbar = DebugToolbarExtension(app)
app.jinja_env.add_extension("jinja2.ext.debug")
app.jinja_env.add_extension("jinja2.ext.do")
app.jinja_env.trim_blocks = True
app.jinja_env.lstrip_blocks = True
register_renderer(app, "bootstrap4", BootsrapRenderer)
app.nav.register_element("left_nav", left_nav)
app.nav.register_element("right_nav", right_nav)
app.db = db
app.db.init_app(app)
app.login_manager = LoginManager(app)
app.login_manager.login_view = "/login"
app.config["SESSION_SQLALCHEMY"] = app.db
app.session = Session(app)
# app.limiter = Limiter(
# app, key_func=get_remote_address, default_limits=["120 per minute"]
# )
# for handler in app.logger.handlers:
# app.limiter.logger.addHandler(handler)
return app
app = create_app()
setup_template_filters(app)
register_blueprints(app)
@app.errorhandler(500)
def internal_error(error):
print(error)
return ""
@app.errorhandler(404)
def internal_error(error):
print(error)
return ""
@app.before_request
def before_request():
app.config["APP_CONFIG"] = handle_config()
# if request.cookies.get('magic')!="FOO":
# return ""
@app.route("/static/<path:path>")
def send_static(path):
return send_from_directory("static", path)
@app.route("/placeholder")
def placeholder():
return send_file(
make_placeholder_image(
**request.args),
mimetype="image/png")
@app.login_manager.user_loader
def load_user(user_id):
if "jf_user" in session:
if session["jf_user"].id == user_id:
return session["jf_user"]
@app.route("/logout")
@login_required
def logout():
del session["jf_user"]
logout_user()
return redirect("/login")
@app.route("/login", methods=["GET", "POST"])
def login():
next_url = request.args.get("next")
if current_user.is_authenticated:
if next_url and not is_safe_url(next_url):
next_url = None
return redirect(next_url or url_for("home.index"))
form = LoginForm()
if form.validate_on_submit():
try:
jf = JellyfinUser(form.username.data, form.password.data)
except RQ.exceptions.HTTPError as e:
if e.response.status_code != 401:
raise
flash("Invalid credentials", "error")
return render_template("login.html", form=form)
login_user(jf, remember=form.remember.data)
session["jf_user"] = jf
next_url = request.args.get("next")
if next_url and not is_safe_url(next_url):
return abort(400)
return redirect(next_url or url_for("home.index"))
return render_template("login.html", form=form)
@app.before_first_request
def before_first_request():
app.db.create_all()
# stats_collect.loop(60)
@with_application_context(app)
def init_app():
app.db.create_all()
if __name__ == "__main__":
port = 5000
if "--init" in sys.argv:
init_app()
if "--debug" in sys.argv:
os.environ["FLASK_ENV"] = "development"
app.debug = True
app.run(host="0.0.0.0", port=port, debug=True)
else:
from gevent.pywsgi import WSGIServer
server = WSGIServer(("0.0.0.0", port), app)
print("Running on {0}:{1}".format(*server.address))
server.serve_forever()