2019-07-06 23:00:00 -07:00
|
|
|
from flask import Flask
|
2020-05-06 14:34:38 -07:00
|
|
|
from flask import render_template, request, g, redirect, url_for, flash, current_app, Response
|
2019-07-15 22:51:10 -07:00
|
|
|
from flask_login import LoginManager, current_user, login_user, logout_user, login_required
|
2020-03-19 19:25:44 -07:00
|
|
|
|
|
|
|
from oauthlib.oauth2 import WebApplicationClient
|
2019-07-15 22:51:10 -07:00
|
|
|
|
2019-07-23 15:49:57 -07:00
|
|
|
import threading
|
|
|
|
import logging
|
|
|
|
import inotify.adapters, inotify.constants
|
2019-08-22 10:43:14 -07:00
|
|
|
import inspect
|
2020-03-19 19:25:44 -07:00
|
|
|
import datetime
|
|
|
|
import requests
|
|
|
|
import json
|
2020-04-02 19:35:32 -07:00
|
|
|
import os
|
2020-05-06 14:34:38 -07:00
|
|
|
import base64
|
2019-07-11 17:35:30 -07:00
|
|
|
|
2019-07-06 23:00:00 -07:00
|
|
|
import scripts.func as func
|
|
|
|
from scripts import database
|
2019-07-23 15:49:57 -07:00
|
|
|
from admin import admin
|
|
|
|
from comics import comics
|
2020-04-02 19:35:32 -07:00
|
|
|
from tv_movies import tv_movies
|
2020-05-06 14:34:38 -07:00
|
|
|
from games import games
|
2019-07-23 15:49:57 -07:00
|
|
|
|
|
|
|
|
|
|
|
class NullHandler(logging.Handler):
|
|
|
|
def emit(self, record=None):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def debug(self, *arg):
|
|
|
|
pass
|
|
|
|
nullLog = NullHandler()
|
|
|
|
inotify.adapters._LOGGER = nullLog
|
|
|
|
|
2019-07-06 23:00:00 -07:00
|
|
|
|
2020-03-19 19:25:44 -07:00
|
|
|
GOOGLE_CLIENT_ID = "***REMOVED***"
|
|
|
|
GOOGLE_CLIENT_SECRET = "***REMOVED***"
|
|
|
|
GOOGLE_DISCOVERY_URL = (
|
|
|
|
"https://accounts.google.com/.well-known/openid-configuration"
|
|
|
|
)
|
|
|
|
client = WebApplicationClient(GOOGLE_CLIENT_ID)
|
|
|
|
|
|
|
|
|
|
|
|
def get_google_provider_cfg():
|
|
|
|
return requests.get(GOOGLE_DISCOVERY_URL).json()
|
|
|
|
|
|
|
|
|
2019-07-06 23:00:00 -07:00
|
|
|
app = Flask(__name__)
|
2019-07-23 15:49:57 -07:00
|
|
|
app.register_blueprint(comics.Comics)
|
|
|
|
app.register_blueprint(admin.Admin)
|
2020-04-02 19:35:32 -07:00
|
|
|
app.register_blueprint(tv_movies.TV_Movies)
|
2020-05-06 14:34:38 -07:00
|
|
|
app.register_blueprint(games.Games)
|
2019-07-15 22:51:10 -07:00
|
|
|
app.config["SECRET_KEY"] = "***REMOVED***"
|
2020-03-19 19:25:44 -07:00
|
|
|
app.logger.setLevel("DEBUG")
|
2020-05-06 14:34:38 -07:00
|
|
|
# app.use_x_sendfile = True
|
2019-07-15 22:51:10 -07:00
|
|
|
|
|
|
|
login_manager = LoginManager(app)
|
|
|
|
login_manager.login_view = "login"
|
2020-05-06 14:34:38 -07:00
|
|
|
app.config["REMEMBER_COOKIE_DOMAIN"] = "narnian.us"
|
2019-07-06 23:00:00 -07:00
|
|
|
|
|
|
|
|
2019-07-16 11:15:35 -07:00
|
|
|
MOBILE_DEVICES = ["android", "blackberry", "ipad", "iphone"]
|
|
|
|
|
|
|
|
|
2019-07-06 23:00:00 -07:00
|
|
|
def get_comics():
|
|
|
|
with app.app_context():
|
2019-07-23 15:49:57 -07:00
|
|
|
i = inotify.adapters.InotifyTree(func.COMICS_DIRECTORY)
|
2020-04-02 19:35:32 -07:00
|
|
|
func.get_comics()
|
2019-07-23 15:49:57 -07:00
|
|
|
for event in i.event_gen(yield_nones=False):
|
|
|
|
(header, type_names, path, filename) = event
|
2020-04-02 19:35:32 -07:00
|
|
|
file_path = os.path.join(path, filename)
|
|
|
|
if "IN_CLOSE_WRITE" in type_names or "IN_MOVED_TO" in type_names:
|
2019-07-23 15:49:57 -07:00
|
|
|
func.get_comic(file_path)
|
2019-07-06 23:00:00 -07:00
|
|
|
|
|
|
|
|
2019-07-23 15:49:57 -07:00
|
|
|
def get_movies():
|
2019-07-06 23:00:00 -07:00
|
|
|
with app.app_context():
|
2019-07-23 15:49:57 -07:00
|
|
|
i = inotify.adapters.InotifyTree(func.MOVIES_DIRECTORY)
|
2020-04-02 19:35:32 -07:00
|
|
|
func.get_movies()
|
2019-07-23 15:49:57 -07:00
|
|
|
for event in i.event_gen(yield_nones=False):
|
|
|
|
(header, type_names, path, filename) = event
|
2020-04-02 19:35:32 -07:00
|
|
|
file_path = os.path.join(path, filename)
|
|
|
|
if "IN_CLOSE_WRITE" in type_names or "IN_MOVED_TO" in type_names:
|
|
|
|
func.get_movie(file_path)
|
2019-07-06 23:00:00 -07:00
|
|
|
|
|
|
|
|
2019-07-30 15:19:03 -07:00
|
|
|
def get_tv_shows():
|
|
|
|
with app.app_context():
|
2020-04-02 19:35:32 -07:00
|
|
|
i = inotify.adapters.InotifyTree(func.TV_SHOWS_DIRECTORY)
|
2019-07-30 15:19:03 -07:00
|
|
|
func.get_tv_shows()
|
|
|
|
func.get_tv_episodes()
|
2020-03-27 17:08:03 -07:00
|
|
|
for event in i.event_gen(yield_nones=False):
|
|
|
|
(header, type_names, path, filename) = event
|
2020-04-02 19:35:32 -07:00
|
|
|
file_path = os.path.join(path, filename)
|
|
|
|
if "IN_CLOSE_WRITE" in type_names or "IN_MOVED_TO" in type_names:
|
2020-03-27 17:08:03 -07:00
|
|
|
func.get_tv_shows()
|
2020-04-02 19:35:32 -07:00
|
|
|
func.get_tv_episode(file_path)
|
2019-07-30 15:19:03 -07:00
|
|
|
|
|
|
|
|
2020-05-06 14:34:38 -07:00
|
|
|
def get_games():
|
|
|
|
with app.app_context():
|
|
|
|
func.get_games()
|
|
|
|
|
|
|
|
|
2019-07-06 23:00:00 -07:00
|
|
|
with app.app_context():
|
2019-08-23 21:34:42 -07:00
|
|
|
current_app.logger.info("server start")
|
2019-07-06 23:00:00 -07:00
|
|
|
thread = threading.Thread(target=get_comics, args=())
|
|
|
|
thread.daemon = True
|
|
|
|
thread.start()
|
2019-07-23 15:49:57 -07:00
|
|
|
thread2 = threading.Thread(target=get_movies, args=())
|
2019-07-06 23:00:00 -07:00
|
|
|
thread2.daemon = True
|
|
|
|
thread2.start()
|
2019-07-30 15:19:03 -07:00
|
|
|
thread3 = threading.Thread(target=get_tv_shows, args=())
|
|
|
|
thread3.daemon = True
|
|
|
|
thread3.start()
|
2020-05-06 14:34:38 -07:00
|
|
|
thread4 = threading.Thread(target=get_games, args=())
|
|
|
|
thread4.daemon = True
|
|
|
|
thread4.start()
|
2019-07-06 23:00:00 -07:00
|
|
|
|
|
|
|
|
|
|
|
@app.teardown_appcontext
|
|
|
|
def close_connection(exception):
|
|
|
|
db = getattr(g, '_database', None)
|
|
|
|
if db is not None:
|
|
|
|
db.close()
|
|
|
|
|
|
|
|
|
|
|
|
def update_comic_db(sender, **kw):
|
|
|
|
try:
|
2019-07-11 17:35:30 -07:00
|
|
|
database.add_comics(kw["meta"], kw["thumbnails"])
|
2019-07-06 23:00:00 -07:00
|
|
|
except Exception as e:
|
2019-08-23 21:34:42 -07:00
|
|
|
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
2019-07-06 23:00:00 -07:00
|
|
|
|
|
|
|
|
2019-07-23 15:49:57 -07:00
|
|
|
def update_movie_db(sender, **kw):
|
|
|
|
try:
|
|
|
|
database.add_movies(kw["movies"])
|
|
|
|
except Exception as e:
|
2019-08-23 21:34:42 -07:00
|
|
|
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
2019-07-23 15:49:57 -07:00
|
|
|
|
|
|
|
|
2019-07-30 15:19:03 -07:00
|
|
|
def update_tv_show_db(sender, **kw):
|
|
|
|
try:
|
|
|
|
database.add_tv_shows(kw["tv_show"])
|
|
|
|
except Exception as e:
|
2019-08-23 21:34:42 -07:00
|
|
|
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
2019-07-30 15:19:03 -07:00
|
|
|
|
|
|
|
|
|
|
|
def update_tv_episodes_db(sender, **kw):
|
|
|
|
try:
|
|
|
|
database.add_tv_episodes(kw["tv_episodes"])
|
|
|
|
except Exception as e:
|
2019-08-23 21:34:42 -07:00
|
|
|
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
2019-07-30 15:19:03 -07:00
|
|
|
|
|
|
|
|
2020-05-06 14:34:38 -07:00
|
|
|
def update_games_db(sender, **kw):
|
|
|
|
try:
|
|
|
|
database.add_games(kw["games"])
|
|
|
|
except Exception as e:
|
|
|
|
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
|
|
|
|
|
|
|
|
2019-07-06 23:00:00 -07:00
|
|
|
func.comic_loaded.connect(update_comic_db)
|
2019-07-23 15:49:57 -07:00
|
|
|
func.movie_loaded.connect(update_movie_db)
|
2019-07-30 15:19:03 -07:00
|
|
|
func.tv_show_loaded.connect(update_tv_show_db)
|
|
|
|
func.tv_episodes_loaded.connect(update_tv_episodes_db)
|
2020-05-06 14:34:38 -07:00
|
|
|
func.games_loaded.connect(update_games_db)
|
2019-07-06 23:00:00 -07:00
|
|
|
|
|
|
|
|
2019-07-15 22:51:10 -07:00
|
|
|
@login_manager.user_loader
|
2020-03-19 19:25:44 -07:00
|
|
|
def load_user(email):
|
|
|
|
try:
|
|
|
|
return database.get_user(email)
|
|
|
|
except Exception as e:
|
|
|
|
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
|
|
|
return str(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
2019-07-15 22:51:10 -07:00
|
|
|
|
|
|
|
|
2020-05-06 14:34:38 -07:00
|
|
|
@login_manager.request_loader
|
|
|
|
def load_user_from_request(request):
|
|
|
|
try:
|
|
|
|
api_key = request.headers.get('Authorization')
|
|
|
|
if api_key:
|
|
|
|
api_key = api_key.replace('Basic ', '', 1)
|
|
|
|
try:
|
|
|
|
api_key = base64.b64decode(api_key).decode("utf-8")
|
|
|
|
except TypeError:
|
|
|
|
pass
|
|
|
|
email = api_key.split(":")[0]
|
|
|
|
password = api_key.split(":")[1]
|
|
|
|
user = load_user(email)
|
|
|
|
if user and user.check_password(password):
|
|
|
|
return user
|
|
|
|
return None
|
|
|
|
except Exception as e:
|
|
|
|
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
|
|
|
return str(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
|
|
|
|
|
|
|
|
2019-07-15 22:51:10 -07:00
|
|
|
@app.route("/login", methods=["GET", "POST"])
|
|
|
|
def login():
|
|
|
|
try:
|
2020-03-19 19:25:44 -07:00
|
|
|
google_provider_cfg = get_google_provider_cfg()
|
|
|
|
authorization_endpoint = google_provider_cfg["authorization_endpoint"]
|
|
|
|
|
|
|
|
request_uri = client.prepare_request_uri(
|
|
|
|
authorization_endpoint,
|
|
|
|
redirect_uri=request.base_url + "/callback",
|
|
|
|
scope=["openid", "email", "profile"],
|
|
|
|
)
|
|
|
|
|
2019-07-15 22:51:10 -07:00
|
|
|
if request.method == "POST":
|
2020-03-19 19:25:44 -07:00
|
|
|
email = request.form.get("email")
|
2019-07-15 22:51:10 -07:00
|
|
|
password = request.form.get("password")
|
2020-03-19 19:25:44 -07:00
|
|
|
user = database.get_user(email)
|
2019-07-15 22:51:10 -07:00
|
|
|
if user is None or not user.check_password(password):
|
2020-03-19 19:25:44 -07:00
|
|
|
flash("invalid email or password")
|
2019-07-15 22:51:10 -07:00
|
|
|
return redirect(url_for("login"))
|
2020-03-19 19:25:44 -07:00
|
|
|
login_user(user, remember=True, duration=datetime.timedelta(days=7))
|
2019-07-15 22:51:10 -07:00
|
|
|
next_page = request.args.get("next")
|
|
|
|
if not next_page:
|
|
|
|
next_page = url_for("home")
|
|
|
|
return redirect(next_page)
|
2020-03-19 19:25:44 -07:00
|
|
|
return render_template("login.html", title="login", auth_url=request_uri)
|
|
|
|
except Exception as e:
|
|
|
|
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
|
|
|
return str(e)
|
|
|
|
|
|
|
|
|
|
|
|
@app.route("/login/callback")
|
|
|
|
def callback():
|
|
|
|
try:
|
|
|
|
# Get authorization code Google sent back to you
|
|
|
|
code = request.args.get("code")
|
|
|
|
|
|
|
|
google_provider_cfg = get_google_provider_cfg()
|
|
|
|
token_endpoint = google_provider_cfg["token_endpoint"]
|
|
|
|
|
|
|
|
token_url, headers, body = client.prepare_token_request(
|
|
|
|
token_endpoint,
|
|
|
|
authorization_response=request.url,
|
|
|
|
redirect_url=request.base_url,
|
|
|
|
code=code
|
|
|
|
)
|
|
|
|
token_response = requests.post(
|
|
|
|
token_url,
|
|
|
|
headers=headers,
|
|
|
|
data=body,
|
|
|
|
auth=(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET)
|
|
|
|
)
|
|
|
|
|
|
|
|
client.parse_request_body_response(json.dumps(token_response.json()))
|
|
|
|
|
|
|
|
userinfo_endpoint = google_provider_cfg["userinfo_endpoint"]
|
|
|
|
uri, headers, body = client.add_token(userinfo_endpoint)
|
|
|
|
userinfo_response = requests.get(uri, headers=headers, data=body)
|
|
|
|
|
|
|
|
if userinfo_response.json().get("email_verified"):
|
|
|
|
unique_id = userinfo_response.json()["sub"]
|
|
|
|
users_email = userinfo_response.json()["email"]
|
|
|
|
users_name = userinfo_response.json()["given_name"]
|
|
|
|
else:
|
|
|
|
return "User email not available or not verified by Google.", 400
|
|
|
|
|
|
|
|
data = (unique_id, users_name, users_email, None, False)
|
|
|
|
|
|
|
|
current_app.logger.info("user data from google: " + str(data))
|
|
|
|
user = database.get_user(users_email)
|
|
|
|
|
|
|
|
if not user:
|
|
|
|
user = database.add_user(data)
|
|
|
|
current_app.logger.info("new user: {} created".format(users_email))
|
|
|
|
|
|
|
|
current_app.logger.info("email: "+str(user.email))
|
|
|
|
current_app.logger.info("username: "+str(user.username))
|
|
|
|
current_app.logger.info("authenticated: "+str(user.is_authenticated))
|
|
|
|
current_app.logger.info("active: "+str(user.is_active))
|
|
|
|
current_app.logger.info("id: "+str(user.get_id()))
|
|
|
|
login_user(user, remember=True, duration=datetime.timedelta(days=7), force=True)
|
|
|
|
|
|
|
|
return redirect(url_for("home"))
|
2019-07-15 22:51:10 -07:00
|
|
|
except Exception as e:
|
2019-08-23 21:34:42 -07:00
|
|
|
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
2019-07-15 22:51:10 -07:00
|
|
|
return str(e)
|
|
|
|
|
|
|
|
|
|
|
|
@app.route("/logout")
|
|
|
|
def logout():
|
|
|
|
try:
|
|
|
|
logout_user()
|
|
|
|
return redirect(url_for("login"))
|
|
|
|
except Exception as e:
|
2019-08-23 21:34:42 -07:00
|
|
|
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
2019-07-15 22:51:10 -07:00
|
|
|
return str(e)
|
|
|
|
|
|
|
|
|
|
|
|
@app.route("/")
|
|
|
|
def root():
|
|
|
|
return redirect(url_for("home"))
|
|
|
|
|
|
|
|
|
|
|
|
@app.route("/home")
|
|
|
|
@login_required
|
|
|
|
def home():
|
|
|
|
try:
|
2020-04-11 17:14:06 -07:00
|
|
|
return render_template("home.html", title="Home", current_user=current_user)
|
2019-07-15 22:51:10 -07:00
|
|
|
except Exception as e:
|
2019-08-23 21:34:42 -07:00
|
|
|
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
2019-07-15 22:51:10 -07:00
|
|
|
return str(e)
|
2019-07-06 23:00:00 -07:00
|
|
|
|
|
|
|
|
2020-05-06 14:34:38 -07:00
|
|
|
@app.after_request
|
|
|
|
def apply_headers(response: Response):
|
|
|
|
try:
|
|
|
|
user_name = "anonymous"
|
|
|
|
if current_user:
|
|
|
|
user_name = getattr(current_user, "email", "anonymous")
|
|
|
|
response.set_cookie("rpi_name", user_name)
|
|
|
|
return response
|
|
|
|
except Exception as e:
|
|
|
|
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
|
|
|
return str(e)
|
|
|
|
|
|
|
|
|
2019-07-06 23:00:00 -07:00
|
|
|
@app.route("/music")
|
2019-07-15 22:51:10 -07:00
|
|
|
@login_required
|
2019-07-06 23:00:00 -07:00
|
|
|
def music():
|
|
|
|
return "No music"
|
|
|
|
|
|
|
|
|
2020-05-06 14:34:38 -07:00
|
|
|
@app.errorhandler(404)
|
|
|
|
def resource_not_found(e):
|
|
|
|
try:
|
|
|
|
return render_template("404.html"), 404
|
|
|
|
except Exception as e:
|
|
|
|
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
|
|
|
return str(e)
|
|
|
|
|
|
|
|
|
|
|
|
@app.errorhandler(Exception)
|
|
|
|
def handle_exception(e):
|
|
|
|
return render_template("error.html", e=e), 500
|
|
|
|
|
|
|
|
|
|
|
|
games.Games.register_error_handler(404, resource_not_found)
|
|
|
|
tv_movies.TV_Movies.register_error_handler(404, resource_not_found)
|
|
|
|
comics.Comics.register_error_handler(404, resource_not_found)
|
|
|
|
admin.Admin.register_error_handler(404, resource_not_found)
|
|
|
|
games.Games.register_error_handler(Exception, handle_exception)
|
|
|
|
tv_movies.TV_Movies.register_error_handler(Exception, handle_exception)
|
|
|
|
comics.Comics.register_error_handler(Exception, handle_exception)
|
|
|
|
admin.Admin.register_error_handler(Exception, handle_exception)
|
2019-07-06 23:00:00 -07:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
app.run()
|