2021-12-13 18:11:43 +00:00
|
|
|
import sys # isort:skip
|
|
|
|
from gevent import monkey # isort:skip
|
|
|
|
|
|
|
|
if __name__ == "__main__" and "--debug" not in sys.argv[1:]:
|
2021-08-29 13:03:28 +00:00
|
|
|
monkey.patch_all()
|
2021-12-13 18:11:43 +00:00
|
|
|
|
2021-08-29 13:03:28 +00:00
|
|
|
import os
|
2021-12-13 18:11:43 +00:00
|
|
|
|
2021-08-29 13:03:28 +00:00
|
|
|
import requests as RQ
|
|
|
|
from flask import (
|
|
|
|
Flask,
|
2021-12-13 18:11:43 +00:00
|
|
|
abort,
|
|
|
|
flash,
|
|
|
|
redirect,
|
2021-08-29 13:03:28 +00:00
|
|
|
render_template,
|
|
|
|
request,
|
|
|
|
send_file,
|
2021-12-13 18:11:43 +00:00
|
|
|
send_from_directory,
|
2021-08-29 13:03:28 +00:00
|
|
|
session,
|
2021-12-13 18:11:43 +00:00
|
|
|
url_for,
|
2021-08-29 13:03:28 +00:00
|
|
|
)
|
|
|
|
from flask_bootstrap import Bootstrap
|
|
|
|
from flask_debugtoolbar import DebugToolbarExtension
|
2021-12-13 18:11:43 +00:00
|
|
|
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
|
2021-08-29 13:03:28 +00:00
|
|
|
|
|
|
|
import stats_collect
|
2021-12-13 18:11:43 +00:00
|
|
|
from api.user import JellyfinUser
|
|
|
|
|
|
|
|
from forms import LoginForm
|
|
|
|
from models import RequestUser, db
|
2021-08-29 13:03:28 +00:00
|
|
|
from transcode import profiles
|
|
|
|
from utils import (
|
|
|
|
BootsrapRenderer,
|
2021-12-13 18:11:43 +00:00
|
|
|
handle_config,
|
|
|
|
is_safe_url,
|
|
|
|
login_required,
|
2021-08-29 13:03:28 +00:00
|
|
|
make_placeholder_image,
|
2021-12-13 18:11:43 +00:00
|
|
|
setup_template_filters,
|
2021-08-29 13:03:28 +00:00
|
|
|
with_application_context,
|
|
|
|
)
|
2021-12-13 18:11:43 +00:00
|
|
|
from views import register_blueprints
|
2021-08-29 13:03:28 +00:00
|
|
|
|
|
|
|
def left_nav():
|
2021-12-13 18:11:43 +00:00
|
|
|
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")
|
2021-08-29 13:03:28 +00:00
|
|
|
links = [
|
2021-12-13 18:11:43 +00:00
|
|
|
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"),
|
2021-08-29 13:03:28 +00:00
|
|
|
]
|
2021-12-13 18:11:43 +00:00
|
|
|
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))
|
2021-08-29 13:03:28 +00:00
|
|
|
return Navbar("PirateDash", *links)
|
|
|
|
|
|
|
|
|
2021-12-13 18:11:43 +00:00
|
|
|
def right_nav():
|
|
|
|
if current_user.is_authenticated:
|
|
|
|
return Text(current_user["Name"])
|
|
|
|
else:
|
|
|
|
return Text("")
|
|
|
|
|
|
|
|
|
2021-08-29 13:03:28 +00:00
|
|
|
def create_app():
|
2021-12-13 18:11:43 +00:00
|
|
|
templates = os.path.join(
|
|
|
|
os.path.dirname(
|
|
|
|
os.path.abspath(__file__)),
|
|
|
|
"templates")
|
2021-08-29 13:03:28 +00:00
|
|
|
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)
|
2021-12-13 18:11:43 +00:00
|
|
|
app.nav.register_element("right_nav", right_nav)
|
2021-08-29 13:03:28 +00:00
|
|
|
app.db = db
|
2021-12-13 18:11:43 +00:00
|
|
|
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)
|
2021-08-29 13:03:28 +00:00
|
|
|
return app
|
|
|
|
|
|
|
|
|
|
|
|
app = create_app()
|
2021-12-13 18:11:43 +00:00
|
|
|
setup_template_filters(app)
|
|
|
|
register_blueprints(app)
|
2021-08-29 13:03:28 +00:00
|
|
|
|
|
|
|
|
2021-12-13 18:11:43 +00:00
|
|
|
@app.errorhandler(500)
|
|
|
|
def internal_error(error):
|
|
|
|
print(error)
|
|
|
|
return ""
|
2021-08-29 13:03:28 +00:00
|
|
|
|
|
|
|
|
2021-12-13 18:11:43 +00:00
|
|
|
@app.errorhandler(404)
|
|
|
|
def internal_error(error):
|
|
|
|
print(error)
|
|
|
|
return ""
|
2021-08-29 13:03:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
@app.before_request
|
|
|
|
def before_request():
|
|
|
|
app.config["APP_CONFIG"] = handle_config()
|
2021-12-13 18:11:43 +00:00
|
|
|
# if request.cookies.get('magic')!="FOO":
|
|
|
|
# return ""
|
2021-08-29 13:03:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
@app.route("/static/<path:path>")
|
|
|
|
def send_static(path):
|
|
|
|
return send_from_directory("static", path)
|
|
|
|
|
|
|
|
|
|
|
|
@app.route("/placeholder")
|
|
|
|
def placeholder():
|
2021-12-13 18:11:43 +00:00
|
|
|
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()
|
2021-08-29 13:03:28 +00:00
|
|
|
if form.validate_on_submit():
|
2021-12-13 18:11:43 +00:00
|
|
|
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)
|
2021-08-29 13:03:28 +00:00
|
|
|
|
|
|
|
|
2021-12-13 18:11:43 +00:00
|
|
|
@with_application_context(app)
|
|
|
|
def init_app():
|
|
|
|
app.db.create_all()
|
2021-08-29 13:03:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
port = 5000
|
2021-12-13 18:11:43 +00:00
|
|
|
if "--init" in sys.argv:
|
|
|
|
init_app()
|
2021-08-29 13:03:28 +00:00
|
|
|
if "--debug" in sys.argv:
|
2021-12-13 18:11:43 +00:00
|
|
|
os.environ["FLASK_ENV"] = "development"
|
|
|
|
app.debug = True
|
|
|
|
app.run(host="0.0.0.0", port=port, debug=True)
|
2021-08-29 13:03:28 +00:00
|
|
|
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()
|