push latest changes
This commit is contained in:
		
							parent
							
								
									7523a19d1f
								
							
						
					
					
						commit
						cb2b5c2c2b
					
				
					 63 changed files with 3158 additions and 1552 deletions
				
			
		
							
								
								
									
										24
									
								
								views/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								views/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| import sys | ||||
| 
 | ||||
| from flask import Blueprint | ||||
| 
 | ||||
| from .api import api  # noqa | ||||
| from .config import config_page  # noqa | ||||
| from .containers import containers_page  # noqa | ||||
| from .history import history_page  # noqa | ||||
| from .home import home_page  # noqa | ||||
| from .jellyfin import jellyfin_page  # noqa | ||||
| from .logs import logs_page  # noqa | ||||
| from .qbittorrent import qbittorrent_page  # noqa | ||||
| from .radarr import radarr_page  # noqa | ||||
| from .remote import remote_page  # noqa | ||||
| from .requests import requests_page  # noqa | ||||
| from .search import search_page  # noqa | ||||
| from .sonarr import sonarr_page  # noqa | ||||
| from .transcode import transcode_page  # noqa | ||||
| 
 | ||||
| 
 | ||||
| def register_blueprints(app): | ||||
|     for k, v in vars(sys.modules[__name__]).items(): | ||||
|         if isinstance(v, Blueprint): | ||||
|             app.register_blueprint(v) | ||||
							
								
								
									
										32
									
								
								views/api/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								views/api/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| from flask import Blueprint, request, flash, session, redirect, url_for | ||||
| 
 | ||||
| import time | ||||
| from api import Client | ||||
| from utils import admin_required | ||||
| 
 | ||||
| api = Blueprint("api", __name__, url_prefix="/api") | ||||
| 
 | ||||
| 
 | ||||
| @api.route("/add_torrent", methods=["POST"]) | ||||
| @admin_required | ||||
| def add_torrent(): | ||||
|     category = request.form.get("category") | ||||
|     c = Client() | ||||
|     hashes_1 = set(c.qbittorent.status().get("torrents", {})) | ||||
|     links = "" | ||||
|     count = 0 | ||||
|     for link in request.form.getlist("torrent[]"): | ||||
|         links += link + "\n" | ||||
|         count += 1 | ||||
|     c.qbittorent.add(urls=links, category=category) | ||||
|     for _ in range(10): | ||||
|         status = c.qbittorent.status().get("torrents", {}) | ||||
|         hashes_2 = set(status) | ||||
|         if len(hashes_2 - hashes_1) == count: | ||||
|             break | ||||
|         time.sleep(0.5) | ||||
|     else: | ||||
|         flash("Some torrents failed to get added to QBittorrent", "waring") | ||||
|     new_torrents = sorted(hashes_2 - hashes_1) | ||||
|     session["new_torrents"] = {h: status[h] for h in new_torrents} | ||||
|     return redirect(url_for("search")) | ||||
							
								
								
									
										45
									
								
								views/config/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								views/config/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | |||
| from flask import Blueprint, json, render_template, request | ||||
| from api import Client | ||||
| from forms import ConfigForm | ||||
| from utils import admin_required, handle_config, populate_form, validate_transcoding_profiles | ||||
| 
 | ||||
| config_page = Blueprint("config", __name__, url_prefix="/config") | ||||
| 
 | ||||
| 
 | ||||
| @config_page.route("/", methods=["GET", "POST"]) | ||||
| @admin_required | ||||
| def index(): | ||||
|     form = ConfigForm() | ||||
|     cfg = {} | ||||
|     populate_form(form) | ||||
|     if form.validate_on_submit(): | ||||
|         skip = ["save", "test", "csrf_token"] | ||||
|         transcode_profiles = request.files.get("transcode_profiles") | ||||
|         if transcode_profiles: | ||||
|             try: | ||||
|                 form.transcode_profiles.data = json.load(transcode_profiles) | ||||
|                 validate_transcoding_profiles(form.transcode_profiles.data) | ||||
|             except ValueError as e: | ||||
|                 form.transcode_profiles.data = None | ||||
|                 form.transcode_profiles.errors = [ | ||||
|                     "Invalid json data in file {}: {}".format( | ||||
|                         transcode_profiles.filename, e | ||||
|                     ) | ||||
|                 ] | ||||
|         else: | ||||
|             form.transcode_profiles.data = handle_config().get("transcode_profiles", {}) | ||||
|         if form.errors: | ||||
|             return render_template("config.html", form=form) | ||||
|         for name, field in form._fields.items(): | ||||
|             if name in skip: | ||||
|                 continue | ||||
|             cfg[name] = field.data | ||||
|         if form.test.data: | ||||
|             test_res = Client.test(cfg) | ||||
|             populate_form(form, cfg) | ||||
|             return render_template("config.html", form=form, test=test_res) | ||||
|         handle_config(cfg) | ||||
|         populate_form(form) | ||||
|         return render_template("config.html", form=form) | ||||
|     form.process() | ||||
|     return render_template("config.html", form=form) | ||||
							
								
								
									
										22
									
								
								views/containers/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								views/containers/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| from flask import Blueprint, render_template | ||||
| 
 | ||||
| from api import Client | ||||
| from utils import admin_required | ||||
| 
 | ||||
| containers_page = Blueprint("containers", __name__, url_prefix="/containers") | ||||
| 
 | ||||
| 
 | ||||
| @containers_page.route("/") | ||||
| @admin_required | ||||
| def index(): | ||||
|     c = Client() | ||||
|     containers = c.portainer.containers() | ||||
|     return render_template("containers/index.html", containers=containers) | ||||
| 
 | ||||
| 
 | ||||
| @containers_page.route("/<container_id>") | ||||
| @admin_required | ||||
| def details(container_id): | ||||
|     c = Client() | ||||
|     container = c.portainer.containers(container_id) | ||||
|     return render_template("containers/details.html", container=container) | ||||
							
								
								
									
										15
									
								
								views/history/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								views/history/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | |||
| from flask import Blueprint, render_template | ||||
| 
 | ||||
| from api import Client | ||||
| from utils import admin_required | ||||
| 
 | ||||
| history_page = Blueprint("history", __name__, url_prefix="/history") | ||||
| 
 | ||||
| 
 | ||||
| @history_page.route("/") | ||||
| @admin_required | ||||
| def index(): | ||||
|     c = Client() | ||||
|     sonarr = c.sonarr.history() | ||||
|     radarr = c.radarr.history() | ||||
|     return render_template("history.html", sonarr=sonarr, radarr=radarr) | ||||
							
								
								
									
										16
									
								
								views/home/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								views/home/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| from flask import Blueprint, render_template | ||||
| from flask_login import current_user | ||||
| 
 | ||||
| import stats_collect | ||||
| 
 | ||||
| home_page = Blueprint("home", __name__) | ||||
| 
 | ||||
| 
 | ||||
| @home_page.route("/") | ||||
| def index(): | ||||
|     stats = stats_collect.Stats() | ||||
|     if not (current_user.is_authenticated and current_user.is_admin): | ||||
|         stats["images"] = [ | ||||
|             img for img in stats["images"] if img[0] != "Torrents"] | ||||
| 
 | ||||
|     return render_template("index.html", fluid=True, data=stats) | ||||
							
								
								
									
										43
									
								
								views/jellyfin/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								views/jellyfin/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,43 @@ | |||
| from flask import Blueprint, render_template | ||||
| from flask_login import current_user | ||||
| 
 | ||||
| import stats_collect | ||||
| from api import Client | ||||
| from utils import login_required | ||||
| 
 | ||||
| jellyfin_page = Blueprint("jellyfin", __name__, url_prefix="/jellyfin") | ||||
| 
 | ||||
| 
 | ||||
| @jellyfin_page.route("/") | ||||
| @login_required | ||||
| def index(): | ||||
|     c = Client() | ||||
|     stats = stats_collect.Stats() | ||||
|     jellyfin = { | ||||
|         "info": c.jellyfin.system_info(), | ||||
|         "status": c.jellyfin.status(), | ||||
|         "counts": c.jellyfin.get_counts(), | ||||
|         "library": stats["library"], | ||||
|     } | ||||
|     if not (current_user.is_authenticated and current_user.is_admin): | ||||
|         jellyfin["library"] = {} | ||||
|         jellyfin["status"]["HasUpdateAvailable"] = False | ||||
|         jellyfin["status"]["HasPendingRestart"] = False | ||||
| 
 | ||||
|     return render_template("jellyfin/index.html", **jellyfin) | ||||
| 
 | ||||
| 
 | ||||
| @jellyfin_page.route("/<item_id>") | ||||
| @login_required | ||||
| def details(item_id): | ||||
|     c = Client() | ||||
|     jellyfin = { | ||||
|         "info": c.jellyfin.system_info(), | ||||
|         "status": c.jellyfin.status(), | ||||
|         "item": c.jellyfin.media_info(item_id), | ||||
|     } | ||||
|     if jellyfin["item"].get("Type") == "Movie": | ||||
|         return render_template("jellyfin/movie.html", **jellyfin) | ||||
|     if jellyfin["item"].get("Type") == "Series": | ||||
|         return render_template("jellyfin/series.html", **jellyfin) | ||||
|     return render_template("jellyfin/details.html", **jellyfin) | ||||
							
								
								
									
										19
									
								
								views/logs/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								views/logs/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | |||
| from flask import Blueprint, render_template | ||||
| 
 | ||||
| from api import Client | ||||
| from utils import admin_required | ||||
| 
 | ||||
| logs_page = Blueprint("log", __name__, url_prefix="/log") | ||||
| 
 | ||||
| 
 | ||||
| @logs_page.route("/") | ||||
| @admin_required | ||||
| def index(): | ||||
|     c = Client() | ||||
|     logs = { | ||||
|         "radarr": c.radarr.log(), | ||||
|         "sonarr": c.sonarr.log(), | ||||
|         "qbt": c.qbittorent.log(), | ||||
|         "peers": c.qbittorent.peer_log(), | ||||
|     } | ||||
|     return render_template("logs.html", logs=logs) | ||||
							
								
								
									
										48
									
								
								views/qbittorrent/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								views/qbittorrent/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | |||
| from flask import Blueprint, render_template, request, redirect | ||||
| 
 | ||||
| from api import Client | ||||
| from utils import admin_required | ||||
| 
 | ||||
| qbittorrent_page = Blueprint( | ||||
|     "qbittorrent", | ||||
|     __name__, | ||||
|     url_prefix="/qbittorrent") | ||||
| 
 | ||||
| 
 | ||||
| @qbittorrent_page.route("/") | ||||
| @admin_required | ||||
| def index(): | ||||
|     c = Client() | ||||
|     qbt = c.qbittorent.status() | ||||
|     sort_by_choices = { | ||||
|         "speed": "Transfer Speed", | ||||
|         "eta": "Time remaining", | ||||
|         "state": "State", | ||||
|         "category": "Category", | ||||
|     } | ||||
|     return render_template( | ||||
|         "qbittorrent/index.html", | ||||
|         qbt=qbt, | ||||
|         status_map=c.qbittorent.status_map, | ||||
|         state_filter=request.args.get("state"), | ||||
|         sort_by=request.args.get("sort", "speed"), | ||||
|         sort_by_choices=sort_by_choices, | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| @qbittorrent_page.route("/add_trackers/<infohash>") | ||||
| @admin_required | ||||
| def add_trackers(infohash): | ||||
|     c = Client() | ||||
|     c.qbittorent.add_trackers(infohash) | ||||
|     return redirect(url_for("qbittorrent_details", infohash=infohash)) | ||||
| 
 | ||||
| 
 | ||||
| @qbittorrent_page.route("/<infohash>") | ||||
| @admin_required | ||||
| def details(infohash): | ||||
|     c = Client() | ||||
|     qbt = c.qbittorent.status(infohash) | ||||
|     return render_template( | ||||
|         "qbittorrent/details.html", qbt=qbt, status_map=c.qbittorent.status_map | ||||
|     ) | ||||
							
								
								
									
										24
									
								
								views/radarr/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								views/radarr/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| from flask import Blueprint, render_template | ||||
| 
 | ||||
| from api import Client | ||||
| from utils import admin_required | ||||
| 
 | ||||
| radarr_page = Blueprint("radarr", __name__, url_prefix="/radarr") | ||||
| 
 | ||||
| 
 | ||||
| @radarr_page.route("/") | ||||
| @admin_required | ||||
| def index(): | ||||
|     c = Client() | ||||
|     movies = c.radarr.movies() | ||||
|     status = c.radarr.status() | ||||
|     history = c.radarr.history() | ||||
|     return render_template( | ||||
|         "radarr/index.html", movies=movies, status=status, history=history | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| @radarr_page.route("/<movie_id>") | ||||
| @admin_required | ||||
| def details(movie_id): | ||||
|     return render_template("radarr/details.html") | ||||
							
								
								
									
										98
									
								
								views/remote/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								views/remote/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,98 @@ | |||
| import base64 | ||||
| import hashlib | ||||
| import io | ||||
| 
 | ||||
| from cryptography.hazmat.primitives import serialization | ||||
| from cryptography.hazmat.primitives.serialization import load_ssh_public_key | ||||
| from flask import Blueprint, redirect, render_template, request, url_for, Markup, flash | ||||
| 
 | ||||
| from forms import AddSSHUser | ||||
| from api import Client | ||||
| from utils import admin_required | ||||
| 
 | ||||
| remote_page = Blueprint("remote", __name__, url_prefix="/remote") | ||||
| 
 | ||||
| 
 | ||||
| def ssh_fingerprint(key): | ||||
|     fp = hashlib.md5(base64.b64decode(key)).hexdigest() | ||||
|     return ":".join(a + b for a, b in zip(fp[::2], fp[1::2])) | ||||
| 
 | ||||
| 
 | ||||
| @remote_page.route("/stop") | ||||
| @admin_required | ||||
| def stop(): | ||||
|     c = Client() | ||||
|     session_id = request.args.get("session") | ||||
|     c.jellyfin.stop_session(session_id) | ||||
|     return redirect(url_for("remote.index")) | ||||
| 
 | ||||
| 
 | ||||
| @remote_page.route("/") | ||||
| @admin_required | ||||
| def index(): | ||||
|     c = Client() | ||||
|     res = c.ssh.get("/data/.ssh/authorized_keys", io.BytesIO()) | ||||
|     res.local.seek(0) | ||||
|     ssh_keys = [] | ||||
|     for key in str(res.local.read(), "utf8").splitlines(): | ||||
|         disabled = False | ||||
|         if key.startswith("#"): | ||||
|             key = key.lstrip("#").lstrip() | ||||
|             disabled = True | ||||
|         load_ssh_public_key(bytes(key, "utf8")) | ||||
|         key_type, key, name = key.split(None, 2) | ||||
|         ssh_keys.append( | ||||
|             { | ||||
|                 "disabled": disabled, | ||||
|                 "type": key_type, | ||||
|                 "key": key, | ||||
|                 "fingerprint": ssh_fingerprint(key), | ||||
|                 "name": name, | ||||
|             } | ||||
|         ) | ||||
|     key = request.args.get("key") | ||||
|     enabled = request.args.get("enabled") | ||||
|     if not (key is None or enabled is None): | ||||
|         key_file = [] | ||||
|         for ssh_key in ssh_keys: | ||||
|             if ssh_key["key"] == key: | ||||
|                 ssh_key["disabled"] = enabled == "False" | ||||
|             if ssh_key["disabled"]: | ||||
|                 key_file.append("#{type} {key} {name}".format(**ssh_key)) | ||||
|             else: | ||||
|                 key_file.append("{type} {key} {name}".format(**ssh_key)) | ||||
|         buf = io.BytesIO(bytes("\n".join(key_file), "utf8")) | ||||
|         c.ssh.put(buf, "/data/.ssh/authorized_keys", preserve_mode=False) | ||||
|         return redirect(url_for("remote")) | ||||
|     jellyfin = { | ||||
|         "users": c.jellyfin.get_users(), | ||||
|         "sessions": c.jellyfin.sessions(), | ||||
|         "info": c.jellyfin.system_info(), | ||||
|     } | ||||
|     return render_template( | ||||
|         "remote/index.html", | ||||
|         ssh=ssh_keys, | ||||
|         jellyfin=jellyfin) | ||||
| 
 | ||||
| 
 | ||||
| @remote_page.route("/add", methods=["GET", "POST"]) | ||||
| @admin_required | ||||
| def add(): | ||||
|     form = AddSSHUser() | ||||
|     c = Client() | ||||
|     if form.validate_on_submit(): | ||||
|         key = load_ssh_public_key(bytes(form.data["ssh_key"], "utf8")) | ||||
|         rawKeyData = key.public_bytes( | ||||
|             encoding=serialization.Encoding.OpenSSH, | ||||
|             format=serialization.PublicFormat.OpenSSH, | ||||
|         ) | ||||
|         passwd = c.add_user(form.data["name"], str(rawKeyData, "utf8")) | ||||
|         flash( | ||||
|             Markup( | ||||
|                 "".join( | ||||
|                     [ | ||||
|                         f"<p>Name: <b>{form.data['name']}</b></p>", | ||||
|                         f"<p>PW: <b>{passwd}</b></p>", | ||||
|                         f"<p>FP: <b>{ssh_fingerprint(rawKeyData.split()[1])}</b></p>", | ||||
|                     ]))) | ||||
|     return render_template("remote/add.html", form=form) | ||||
							
								
								
									
										217
									
								
								views/requests/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								views/requests/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,217 @@ | |||
| import base64 | ||||
| import json | ||||
| from datetime import datetime | ||||
| 
 | ||||
| from flask import ( | ||||
|     Blueprint, | ||||
|     current_app, | ||||
|     flash, | ||||
|     redirect, | ||||
|     render_template, | ||||
|     request, | ||||
|     session, | ||||
|     url_for, | ||||
| ) | ||||
| from flask_login import current_user | ||||
| from collections import defaultdict | ||||
| from api import Client | ||||
| from forms import RequestForm | ||||
| from models import RequestItem, RequestUser | ||||
| from utils import login_required, handle_config | ||||
| 
 | ||||
| requests_page = Blueprint("requests", __name__, url_prefix="/requests") | ||||
| 
 | ||||
| 
 | ||||
| @requests_page.route("/<request_id>/<download_id>", methods=["GET"]) | ||||
| @login_required | ||||
| def download_details(request_id, download_id): | ||||
|     c = Client() | ||||
|     request = RequestItem.query.filter(RequestItem.id == request_id).one_or_none() | ||||
|     if request is None: | ||||
|         flash("Unknown request ID", "danger") | ||||
|         return redirect(url_for("requests.details", request_id=request_id)) | ||||
|     try: | ||||
|         qbt = c.qbittorent.poll(download_id) | ||||
|     except Exception: | ||||
|         flash("Unknown download ID", "danger") | ||||
|         return redirect(url_for("requests.details", request_id=request_id)) | ||||
|     return render_template("qbittorrent/details.html", qbt=qbt) | ||||
| 
 | ||||
| 
 | ||||
| @requests_page.route("/<request_id>", methods=["GET"]) | ||||
| @login_required | ||||
| def details(request_id): | ||||
|     c = Client() | ||||
|     if current_user.is_admin: | ||||
|         requests = RequestItem.query | ||||
|     else: | ||||
|         user_id = current_user.get_id() | ||||
|         requests = RequestItem.query.filter( | ||||
|             RequestItem.users.any(RequestUser.user_id == user_id) | ||||
|         ) | ||||
|     request = requests.filter(RequestItem.id == request_id).one_or_none() | ||||
|     if request is None: | ||||
|         flash("Unknown request ID", "danger") | ||||
|         return redirect(url_for("requests.index")) | ||||
|     RequestUser.query.filter( | ||||
|         (RequestUser.user_id == current_user.id) | ||||
|         & (RequestUser.item_id == request.item_id) | ||||
|     ).update({RequestUser.updated: False}) | ||||
|     current_app.db.session.commit() | ||||
|     jf_item = None | ||||
|     arr = request.arr_item | ||||
|     id_map = c.jellyfin.id_map() | ||||
|     for key_id in ["tmdbId", "imdbId", "tvdbId"]: | ||||
|         if key_id in arr: | ||||
|             key = (key_id.lower()[:-2], str(arr[key_id])) | ||||
|             jf_item = id_map.get(key, None) | ||||
|             if jf_item: | ||||
|                 break | ||||
|     return render_template( | ||||
|         "requests/details.html", request=request, jellyfin_id=jf_item | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| @requests_page.route("/", methods=["GET", "POST"]) | ||||
| @login_required | ||||
| def index(): | ||||
|     c = Client() | ||||
|     form = RequestForm() | ||||
|     user_id = current_user.get_id() | ||||
|     cfg = handle_config() | ||||
|     used_requests = defaultdict(int) | ||||
|     if current_user.is_admin: | ||||
|         requests = RequestItem.query | ||||
|     else: | ||||
|         requests = RequestItem.query.filter( | ||||
|             RequestItem.users.any(RequestUser.user_id == user_id) | ||||
|         ) | ||||
|     for item in requests: | ||||
|         if item.approved is None: | ||||
|             used_requests[item.request_type] += 1 | ||||
|     remaining = {} | ||||
|     remaining["movies"] = ( | ||||
|         cfg["num_requests_per_user"]["movies"] - used_requests["radarr"] | ||||
|     ) | ||||
|     remaining["shows"] = cfg["num_requests_per_user"]["shows"] - used_requests["sonarr"] | ||||
|     print("RQs:", used_requests, remaining) | ||||
|     if ( | ||||
|         request.method == "POST" | ||||
|         and ("approve" in request.form) | ||||
|         or ("decline" in request.form) | ||||
|     ): | ||||
|         approved = "approve" in request.form | ||||
|         declined = "decline" in request.form | ||||
|         if approved and declined: | ||||
|             flash("What the fuck?") | ||||
|             approved = False | ||||
|             declined = False | ||||
|         if approved or declined: | ||||
|             new_state = approved | ||||
|             print("Approved:", approved) | ||||
|         for item_id in request.form.getlist("selected[]"): | ||||
|             item = RequestItem.query.get(item_id) | ||||
|             if item.approved != new_state: | ||||
|                 RequestUser.query.filter(RequestUser.item_id == item_id).update( | ||||
|                     {RequestUser.updated: True} | ||||
|                 ) | ||||
|             item.approved = new_state | ||||
|             if new_state is True: | ||||
|                 search_type = item.request_type | ||||
|                 if hasattr(c, search_type): | ||||
|                     api = getattr(c, search_type) | ||||
|                     if hasattr(api, "add"): | ||||
|                         result = api.add(json.loads(item.data)) | ||||
|                         print(result) | ||||
|                         if item.request_type == "sonarr": | ||||
|                             item.arr_id = result["seriesId"] | ||||
|                         if item.request_type == "radarr": | ||||
|                             item.arr_id = result["id"] | ||||
|                     else: | ||||
|                         flash("Invalid search type: {}".format(search_type), "danger") | ||||
|             current_app.db.session.merge(item) | ||||
|         current_app.db.session.commit() | ||||
|         return render_template( | ||||
|             "requests/index.html", | ||||
|             results=[], | ||||
|             form=form, | ||||
|             search_type=None, | ||||
|             requests=requests, | ||||
|         ) | ||||
|         return redirect(url_for("requests.index")) | ||||
|     if request.method == "POST" and form.search.data is False: | ||||
|         request_type = request.form["search_type"] | ||||
|         for item in request.form.getlist("selected[]"): | ||||
|             data = str(base64.b64decode(item), "utf8") | ||||
|             item = json.loads(data) | ||||
|             item_id = "{type}/{titleSlug}/{year}".format(type=request_type, **item) | ||||
|             user_id = session["jf_user"].get_id() | ||||
|             request_entry = RequestItem.query.get(item_id) | ||||
|             if request_entry is None: | ||||
|                 request_entry = RequestItem( | ||||
|                     added_date=datetime.now(), | ||||
|                     item_id=item_id, | ||||
|                     users=[], | ||||
|                     data=data, | ||||
|                     request_type=request_type, | ||||
|                 ) | ||||
|                 current_app.db.session.add(request_entry) | ||||
|             request_entry.users.append( | ||||
|                 RequestUser( | ||||
|                     user_id=user_id, item_id=item_id, user_name=current_user["Name"] | ||||
|                 ) | ||||
|             ) | ||||
|             current_app.db.session.merge(request_entry) | ||||
|         current_app.db.session.commit() | ||||
|         return render_template( | ||||
|             "requests/index.html", results=[], form=form, requests=requests | ||||
|         ) | ||||
|     if form and form.validate_on_submit(): | ||||
|         c = Client() | ||||
|         query = form.query.data | ||||
|         search_type = form.search_type.data | ||||
|         if hasattr(c, search_type): | ||||
|             api = getattr(c, search_type) | ||||
|             if hasattr(api, "search"): | ||||
|                 results = api.search(query) | ||||
|                 return render_template( | ||||
|                     "requests/index.html", | ||||
|                     results=results, | ||||
|                     form=form, | ||||
|                     search_type=search_type, | ||||
|                 ) | ||||
|         flash("Invalid search type: {}".format(search_type), "danger") | ||||
|     return render_template( | ||||
|         "requests/index.html", | ||||
|         results=[], | ||||
|         form=form, | ||||
|         search_type=None, | ||||
|         requests=requests, | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| """ | ||||
|     if form.validate_on_submit(): | ||||
|         query = form.query.data | ||||
|         if not (form.torrents.data or form.movies.data or form.tv_shows.data): | ||||
|             form.torrents.data = True | ||||
|             form.movies.data = True | ||||
|             form.tv_shows.data = True | ||||
| 
 | ||||
|         if form.torrents.data: | ||||
|             results["torrents"] = c.jackett.search( | ||||
|                 query, form.indexer.data or form.indexer.choices | ||||
|             ) | ||||
|         if form.movies.data: | ||||
|             results["movies"] = c.radarr.search(query) | ||||
|         if form.tv_shows.data: | ||||
|             results["tv_shows"] = c.sonarr.search(query) | ||||
|         return render_template( | ||||
|             "search/index.html", | ||||
|             # form=form, | ||||
|             search_term=query, | ||||
|             results=results, | ||||
|             client=c, | ||||
|             group_by_tracker=form.group_by_tracker.data, | ||||
|         ) | ||||
| """ | ||||
							
								
								
									
										62
									
								
								views/search/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								views/search/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,62 @@ | |||
| from urllib.parse import unquote_plus | ||||
| 
 | ||||
| from flask import Blueprint, json, render_template, request | ||||
| 
 | ||||
| from api import Client | ||||
| from forms import SearchForm | ||||
| from utils import admin_required | ||||
| 
 | ||||
| search_page = Blueprint("search", __name__, url_prefix="/search") | ||||
| 
 | ||||
| 
 | ||||
| @search_page.route("/details", methods=["GET", "POST"]) | ||||
| @admin_required | ||||
| def details(): | ||||
|     data = { | ||||
|         "info": json.loads(unquote_plus(request.form["data"])), | ||||
|         "type": request.form["type"], | ||||
|     } | ||||
|     return render_template("search/details.html", **data) | ||||
| 
 | ||||
| 
 | ||||
| @search_page.route("/", methods=["GET", "POST"]) | ||||
| @admin_required | ||||
| def index(): | ||||
|     c = Client() | ||||
|     results = {} | ||||
|     params = request.args | ||||
|     form = SearchForm() | ||||
|     form.indexer.choices = c.jackett.indexers() | ||||
|     if form.validate_on_submit(): | ||||
|         query = form.query.data | ||||
|         if not (form.torrents.data or form.movies.data or form.tv_shows.data): | ||||
|             form.torrents.data = True | ||||
|             form.movies.data = True | ||||
|             form.tv_shows.data = True | ||||
| 
 | ||||
|         if form.torrents.data: | ||||
|             results["torrents"] = c.jackett.search( | ||||
|                 query, form.indexer.data or form.indexer.choices | ||||
|             ) | ||||
|         if form.movies.data: | ||||
|             results["movies"] = c.radarr.search(query) | ||||
|         if form.tv_shows.data: | ||||
|             results["tv_shows"] = c.sonarr.search(query) | ||||
|         return render_template( | ||||
|             "search/index.html", | ||||
|             # form=form, | ||||
|             search_term=query, | ||||
|             results=results, | ||||
|             client=c, | ||||
|             group_by_tracker=form.group_by_tracker.data, | ||||
|         ) | ||||
|     for name, field in form._fields.items(): | ||||
|         field.default = params.get(name) | ||||
|     form.process() | ||||
|     return render_template( | ||||
|         "search/index.html", | ||||
|         form=form, | ||||
|         results={}, | ||||
|         group_by_tracker=False, | ||||
|         sort_by="Gain", | ||||
|     ) | ||||
							
								
								
									
										24
									
								
								views/sonarr/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								views/sonarr/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| from flask import Blueprint, render_template | ||||
| 
 | ||||
| from api import Client | ||||
| from utils import admin_required | ||||
| 
 | ||||
| sonarr_page = Blueprint("sonarr", __name__, url_prefix="/sonarr") | ||||
| 
 | ||||
| 
 | ||||
| @sonarr_page.route("/") | ||||
| @admin_required | ||||
| def index(): | ||||
|     c = Client() | ||||
|     series = c.sonarr.series() | ||||
|     status = c.sonarr.status() | ||||
|     history = c.sonarr.history() | ||||
|     return render_template( | ||||
|         "sonarr/index.html", series=series, status=status, history=history | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| @sonarr_page.route("/<show_id>") | ||||
| @admin_required | ||||
| def details(show_id): | ||||
|     return render_template("sonarr/details.html") | ||||
							
								
								
									
										10
									
								
								views/transcode/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								views/transcode/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| from flask import Blueprint, render_template | ||||
| 
 | ||||
| from utils import admin_required | ||||
| transcode_page = Blueprint("transcode", __name__, url_prefix="/transcode") | ||||
| 
 | ||||
| 
 | ||||
| @transcode_page.route("/", methods=["GET", "POST"]) | ||||
| @admin_required | ||||
| def index(): | ||||
|     return render_template("transcode/profiles.html") | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue