added the Games tab as well as Basic access authentication
This commit is contained in:
parent
2a5f7ae67f
commit
51c6b5e572
@ -142,6 +142,7 @@ def get_comic_page(comic_id, page_number):
|
||||
response.headers["cache-control"] = "public"
|
||||
date = pytz.utc.localize(datetime.datetime.utcfromtimestamp(os.path.getmtime(meta.path)))
|
||||
response.headers["last-modified"] = date.strftime('%a, %d %b %Y %H:%M:%S %Z')
|
||||
response.headers["Content-Disposition"] = "attachment; filename=\"{} {}_{}{}\"".format(str(meta.series), meta.issuetext, str(page_number), filetype.guess(byte_image).extension)
|
||||
return response
|
||||
|
||||
|
||||
@ -155,4 +156,5 @@ def get_comic_thumbnail(comic_id, page_number):
|
||||
date = pytz.utc.localize(datetime.datetime.utcfromtimestamp(os.path.getmtime(meta.path)))
|
||||
response.headers["last-modified"] = date.strftime('%a, %d %b %Y %H:%M:%S %Z')
|
||||
response.headers["content-type"] = thumb.type
|
||||
response.headers["Content-Disposition"] = "attachment; filename=\"{} {}_{}_thumbnail\"".format(str(meta.series), meta.issuetext, str(page_number))
|
||||
return response
|
||||
|
91
games/games.py
Normal file
91
games/games.py
Normal file
@ -0,0 +1,91 @@
|
||||
from flask import Blueprint, render_template, request, send_file, current_app, jsonify, abort
|
||||
from flask_login import login_required
|
||||
|
||||
from pathvalidate import sanitize_filename
|
||||
import os
|
||||
import inspect
|
||||
import re
|
||||
|
||||
from scripts import database, func
|
||||
|
||||
Games = Blueprint("games", __name__, template_folder="templates")
|
||||
|
||||
|
||||
@Games.route("/games")
|
||||
@login_required
|
||||
def index():
|
||||
try:
|
||||
page = request.args.get("page", 1, type=int)
|
||||
max_items = request.args.get("max_items", 30, type=int)
|
||||
games = database.get_all_games()
|
||||
start = (max_items*(page-1))
|
||||
end = len(games) if len(games) < max_items*page else max_items*page
|
||||
return render_template("games/index.html", title="Games", games=games)
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
return str(type(e)) + " " + str(e)
|
||||
|
||||
|
||||
@Games.route('/games/get_games')
|
||||
@login_required
|
||||
def get_games():
|
||||
try:
|
||||
games = database.get_all_games()
|
||||
games_json = {}
|
||||
for game in games:
|
||||
games_json[game.game_id] = {
|
||||
"id": game.game_id,
|
||||
"title": game.title,
|
||||
"windows": game.windows,
|
||||
"mac": game.mac,
|
||||
"linux": game.linux,
|
||||
"description": game.description,
|
||||
"poster_path": game.poster_path
|
||||
}
|
||||
return jsonify(games_json)
|
||||
# return jsonify({game["id"]: game for game in games})
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
return str(type(e)) + " " + str(e)
|
||||
|
||||
|
||||
@Games.route('/games/get_game/<int:game_id>')
|
||||
@login_required
|
||||
def get_game(game_id):
|
||||
try:
|
||||
game = database.get_game(game_id)
|
||||
if game:
|
||||
game_json = {
|
||||
"title": game.title,
|
||||
"game_id": game.game_id,
|
||||
"description": game.description,
|
||||
"poster_path": game.poster_path,
|
||||
"windows": game.windows,
|
||||
"mac": game.mac,
|
||||
"linux": game.linux
|
||||
}
|
||||
return jsonify(game_json)
|
||||
abort(404)
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
return str(type(e)) + " " + str(e)
|
||||
|
||||
|
||||
@Games.route("/games/download/<int:game_id>")
|
||||
@login_required
|
||||
def download_game(game_id):
|
||||
try:
|
||||
game = database.get_game(game_id)
|
||||
if game:
|
||||
files = game.windows["files"]
|
||||
filename = sanitize_filename(files[0])
|
||||
folder = re.match(r"(.+)_setup_win.(exe|msi)", filename).group(1)
|
||||
if len(files) > 1:
|
||||
filename = sanitize_filename(game.title+".zip")
|
||||
path = os.path.join(func.GAMES_DIRECTORY, folder, filename)
|
||||
return send_file(path, as_attachment=True, attachment_filename=filename)
|
||||
else:
|
||||
abort(404)
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
return str(type(e)) + " " + str(e)
|
8
games/templates/games/index.html
Normal file
8
games/templates/games/index.html
Normal file
@ -0,0 +1,8 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
{% for game in games %}
|
||||
<a class="btn btn-primary" href="{{ url_for("games.index") }}/download/{{ game.game_id }}">Download</a>
|
||||
<p>{{ game.title }} - {{ game.game_id }}</p>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
84
rpiWebApp.py
84
rpiWebApp.py
@ -1,5 +1,5 @@
|
||||
from flask import Flask
|
||||
from flask import render_template, request, g, redirect, url_for, flash, current_app
|
||||
from flask import render_template, request, g, redirect, url_for, flash, current_app, Response
|
||||
from flask_login import LoginManager, current_user, login_user, logout_user, login_required
|
||||
|
||||
from oauthlib.oauth2 import WebApplicationClient
|
||||
@ -12,12 +12,14 @@ import datetime
|
||||
import requests
|
||||
import json
|
||||
import os
|
||||
import base64
|
||||
|
||||
import scripts.func as func
|
||||
from scripts import database
|
||||
from admin import admin
|
||||
from comics import comics
|
||||
from tv_movies import tv_movies
|
||||
from games import games
|
||||
|
||||
|
||||
class NullHandler(logging.Handler):
|
||||
@ -46,11 +48,14 @@ app = Flask(__name__)
|
||||
app.register_blueprint(comics.Comics)
|
||||
app.register_blueprint(admin.Admin)
|
||||
app.register_blueprint(tv_movies.TV_Movies)
|
||||
app.register_blueprint(games.Games)
|
||||
app.config["SECRET_KEY"] = "***REMOVED***"
|
||||
app.logger.setLevel("DEBUG")
|
||||
# app.use_x_sendfile = True
|
||||
|
||||
login_manager = LoginManager(app)
|
||||
login_manager.login_view = "login"
|
||||
app.config["REMEMBER_COOKIE_DOMAIN"] = "narnian.us"
|
||||
|
||||
|
||||
MOBILE_DEVICES = ["android", "blackberry", "ipad", "iphone"]
|
||||
@ -91,9 +96,13 @@ def get_tv_shows():
|
||||
func.get_tv_episode(file_path)
|
||||
|
||||
|
||||
def get_games():
|
||||
with app.app_context():
|
||||
func.get_games()
|
||||
|
||||
|
||||
with app.app_context():
|
||||
current_app.logger.info("server start")
|
||||
#database.initialize_db()
|
||||
thread = threading.Thread(target=get_comics, args=())
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
@ -103,6 +112,9 @@ with app.app_context():
|
||||
thread3 = threading.Thread(target=get_tv_shows, args=())
|
||||
thread3.daemon = True
|
||||
thread3.start()
|
||||
thread4 = threading.Thread(target=get_games, args=())
|
||||
thread4.daemon = True
|
||||
thread4.start()
|
||||
|
||||
|
||||
@app.teardown_appcontext
|
||||
@ -140,10 +152,18 @@ def update_tv_episodes_db(sender, **kw):
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
|
||||
|
||||
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))
|
||||
|
||||
|
||||
func.comic_loaded.connect(update_comic_db)
|
||||
func.movie_loaded.connect(update_movie_db)
|
||||
func.tv_show_loaded.connect(update_tv_show_db)
|
||||
func.tv_episodes_loaded.connect(update_tv_episodes_db)
|
||||
func.games_loaded.connect(update_games_db)
|
||||
|
||||
|
||||
@login_manager.user_loader
|
||||
@ -155,6 +175,27 @@ def load_user(email):
|
||||
return str(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
|
||||
|
||||
@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))
|
||||
|
||||
|
||||
@app.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
try:
|
||||
@ -267,16 +308,47 @@ def home():
|
||||
return str(e)
|
||||
|
||||
|
||||
@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)
|
||||
|
||||
|
||||
@app.route("/music")
|
||||
@login_required
|
||||
def music():
|
||||
return "No music"
|
||||
|
||||
|
||||
@app.route("/games")
|
||||
@login_required
|
||||
def games():
|
||||
return "No Games"
|
||||
@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)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -7,13 +7,12 @@ from wand.image import Image
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy import Column, Integer, String, BLOB, Boolean, DateTime, Numeric, func, over, ARRAY, TIMESTAMP
|
||||
from sqlalchemy import Column, Integer, String, BLOB, Boolean, DateTime, Numeric, func, over, ARRAY, TIMESTAMP, JSON
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
from sqlalchemy.pool import NullPool
|
||||
from sqlalchemy.sql.expression import cast
|
||||
import sqlalchemy
|
||||
import sqlite3
|
||||
import psycopg2
|
||||
import os
|
||||
import inspect
|
||||
import logging
|
||||
@ -240,6 +239,27 @@ class DupComic(Base):
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
|
||||
|
||||
class Game(Base):
|
||||
__tablename__ = "games"
|
||||
|
||||
title = Column(String)
|
||||
game_id = Column(Integer, primary_key=True)
|
||||
description = Column(String)
|
||||
poster_path = Column(String)
|
||||
windows = Column(JSON)
|
||||
mac = Column(JSON)
|
||||
linux = Column(JSON)
|
||||
|
||||
def __init__(self, data):
|
||||
i = 0
|
||||
try:
|
||||
for column in self.__table__.columns:
|
||||
setattr(self, column.name, data[i])
|
||||
i += 1
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
|
||||
|
||||
class User(Base, UserMixin):
|
||||
__tablename__ = "users"
|
||||
|
||||
@ -335,13 +355,13 @@ class TvMovieKeywords(Base):
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))"""
|
||||
|
||||
|
||||
def get_db():
|
||||
db = getattr(g, '_database', None)
|
||||
if db is None:
|
||||
db = g._database = psycopg2.connect(host="bombur", database="rpiwebapp", user="rpiwebapp", password="hello").cursor()
|
||||
|
||||
#db.row_factory = sqlite3.Row
|
||||
return db
|
||||
# def get_db():
|
||||
# db = getattr(g, '_database', None)
|
||||
# if db is None:
|
||||
# db = g._database = psycopg2.connect(host="bombur", database="rpiwebapp", user="rpiwebapp", password="hello").cursor()
|
||||
#
|
||||
# #db.row_factory = sqlite3.Row
|
||||
# return db
|
||||
|
||||
|
||||
def get_imdb():
|
||||
@ -454,6 +474,14 @@ def add_comics(meta, thumbnails):
|
||||
current_app.logger.info("{} comic{} added".format(len(meta), "s" if len(meta)>1 or len(meta)<1 else ""))
|
||||
|
||||
|
||||
def add_games(games):
|
||||
session = Session()
|
||||
for game_data in games:
|
||||
game = Game(game_data)
|
||||
session.add(game)
|
||||
session.commit()
|
||||
|
||||
|
||||
def db_get_all_comics():
|
||||
session = Session()
|
||||
result = session.query(Comic).all()
|
||||
@ -549,6 +577,17 @@ def tv_episode_path_in_db(path):
|
||||
return False
|
||||
|
||||
|
||||
def game_in_db(game_id):
|
||||
try:
|
||||
session = Session()
|
||||
result = session.query(Game).filter(Game.game_id == game_id).one_or_none()
|
||||
if result:
|
||||
return True
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
return False
|
||||
|
||||
|
||||
def imdb_get_movie(title, year):
|
||||
row = get_imdb().execute("SELECT tconst, runtimeMinutes FROM title_basics WHERE (originalTitle LIKE ? OR primaryTitle LIKE ?) AND (titleType LIKE '%movie' OR titleType='video') AND startYear=?", (title, title, year)).fetchone()
|
||||
return row
|
||||
@ -718,6 +757,18 @@ def db_get_current_tv_show_episode_and_data(parent_imdb_id, episodes):
|
||||
return most_recent_episode, most_recent_data
|
||||
|
||||
|
||||
def get_all_games():
|
||||
session = Session()
|
||||
result = session.query(Game).order_by(Game.title).all()
|
||||
return result
|
||||
|
||||
|
||||
def get_game(game_id):
|
||||
session = Session()
|
||||
result = session.query(Game).filter(Game.game_id == game_id).one_or_none()
|
||||
return result
|
||||
|
||||
|
||||
def db_search_table_columns_by_query(query, table, columns, group=[], order=[]):
|
||||
session = Session()
|
||||
results = {}
|
||||
@ -811,21 +862,21 @@ def resize_image(image, new_width=256, new_height=256):
|
||||
return new_image
|
||||
|
||||
|
||||
def fix_thumbnails():
|
||||
new_height = 256
|
||||
new_width = 256
|
||||
print("Start fix thumbnail size")
|
||||
rows = get_db().execute("SELECT * FROM rpiwebapp.comic_thumbnails")
|
||||
print("got list of all thumbnails\n")
|
||||
|
||||
for row in rows:
|
||||
image = Image(file=BytesIO(row["image"]))
|
||||
if image.width > new_width or image.height > new_height:
|
||||
print("id:", row["id"], "pageNumber:", row["pageNumber"])
|
||||
get_db().execute("UPDATE rpiwebapp.comic_thumbnails SET image=? WHERE comic_id=? AND pageNumber=?",
|
||||
[resize_image(image, new_width, new_height).make_blob(), row["id"], row["pageNumber"]])
|
||||
get_db().commit()
|
||||
print("Finished fix thumbnail size")
|
||||
# def fix_thumbnails():
|
||||
# new_height = 256
|
||||
# new_width = 256
|
||||
# print("Start fix thumbnail size")
|
||||
# rows = get_db().execute("SELECT * FROM rpiwebapp.comic_thumbnails")
|
||||
# print("got list of all thumbnails\n")
|
||||
#
|
||||
# for row in rows:
|
||||
# image = Image(file=BytesIO(row["image"]))
|
||||
# if image.width > new_width or image.height > new_height:
|
||||
# print("id:", row["id"], "pageNumber:", row["pageNumber"])
|
||||
# get_db().execute("UPDATE rpiwebapp.comic_thumbnails SET image=? WHERE comic_id=? AND pageNumber=?",
|
||||
# [resize_image(image, new_width, new_height).make_blob(), row["id"], row["pageNumber"]])
|
||||
# get_db().commit()
|
||||
# print("Finished fix thumbnail size")
|
||||
|
||||
|
||||
def get_user(email):
|
||||
|
@ -9,6 +9,7 @@ import os, re
|
||||
import inspect
|
||||
import json
|
||||
import enzyme
|
||||
import requests
|
||||
|
||||
from scripts import database
|
||||
|
||||
@ -17,6 +18,7 @@ comic_loaded = rpi_signals.signal("comic-loaded")
|
||||
movie_loaded = rpi_signals.signal("movie-loaded")
|
||||
tv_show_loaded = rpi_signals.signal("tv_show_loaded")
|
||||
tv_episodes_loaded = rpi_signals.signal("tv_episodes_loaded")
|
||||
games_loaded = rpi_signals.signal("games_loaded")
|
||||
|
||||
publishers_to_ignore = ["***REMOVED***"]
|
||||
|
||||
@ -26,16 +28,18 @@ RPI_COMICS_DIRECTORY = "/usb/storage/media/Comics/"
|
||||
RPI_MOVIES_DIRECTORY = "/usb/storage/media/Videos/Movies/"
|
||||
RPI_TV_SHOWS_DIRECTORY = "/usb/storage/media/Videos/TV/"
|
||||
RPI_VIDEOS_DIRECTORY = "/usb/storage/media/Videos/Videos/"
|
||||
RPI_GAMES_DIRECTORY = "/usb/storage/media/games/"
|
||||
RPI_GAMES_DIRECTORY = "/usb/storage/Games/"
|
||||
RPI_MUSIC_DIRECTORY = "/usb/storage/media/Music/"
|
||||
|
||||
MC_COMICS_DIRECTORY = "/mnt/c/Users/Matthew/Documents/Comics"
|
||||
MC_MOVIES_DIRECTORY = "/mnt/c/Users/Matthew/Documents/Movies"
|
||||
MC_TV_SHOWS_DIRECTORY = "/mnt/c/Users/Matthew/Documents/TV"
|
||||
MC_COMICS_DIRECTORY = "/mnt/c/Users/Matthew/Documents/Comics/"
|
||||
MC_MOVIES_DIRECTORY = "/mnt/c/Users/Matthew/Documents/Movies/"
|
||||
MC_TV_SHOWS_DIRECTORY = "/mnt/c/Users/Matthew/Documents/TV/"
|
||||
MC_GAMES_DIRECTORY = "/mnt/g/Humble Bundle/rpi/"
|
||||
|
||||
COMICS_DIRECTORY = RPI_COMICS_DIRECTORY if os.path.exists(RPI_COMICS_DIRECTORY) else MC_COMICS_DIRECTORY
|
||||
MOVIES_DIRECTORY = RPI_MOVIES_DIRECTORY if os.path.exists(RPI_MOVIES_DIRECTORY) else MC_MOVIES_DIRECTORY
|
||||
TV_SHOWS_DIRECTORY = RPI_TV_SHOWS_DIRECTORY if os.path.exists(RPI_TV_SHOWS_DIRECTORY) else MC_TV_SHOWS_DIRECTORY
|
||||
GAMES_DIRECTORY = RPI_GAMES_DIRECTORY if os.path.exists(RPI_GAMES_DIRECTORY) else MC_GAMES_DIRECTORY
|
||||
|
||||
#############
|
||||
|
||||
@ -423,3 +427,52 @@ def get_tags(path):
|
||||
if simple.name == "SUMMARY":
|
||||
mkv_info["movie"]["summary"] = simple.string
|
||||
return mkv_info
|
||||
|
||||
|
||||
def get_games():
|
||||
games = []
|
||||
cover_url = "https://api-v3.igdb.com/covers"
|
||||
games_url = "https://api-v3.igdb.com/games"
|
||||
headers = {
|
||||
"accept": "application/json",
|
||||
"user-key": "641f7f0e3af5273dcc1105ce851ea804"
|
||||
}
|
||||
i = 0
|
||||
for folder in sorted(os.listdir(GAMES_DIRECTORY), key=str.casefold):
|
||||
root = os.path.join(GAMES_DIRECTORY, folder)
|
||||
if os.path.isdir(os.path.join(root)):
|
||||
path = os.path.join(root, "info.json")
|
||||
with open(path, "r") as f:
|
||||
info = json.load(f)
|
||||
game_id = info["id"]
|
||||
if not database.game_in_db(game_id):
|
||||
current_app.logger.info(f"start loading game: {info['name']}:{info['id']}")
|
||||
data = f"fields summary;limit 1;where id={game_id};"
|
||||
r = requests.get(games_url, headers=headers, data=data).json()[0]
|
||||
description = ""
|
||||
if "summary" in r.keys():
|
||||
description = r["summary"]
|
||||
data = f"fields image_id;limit 1;where game={game_id};"
|
||||
r = requests.get(cover_url, headers=headers, data=data).json()
|
||||
poster_path = None
|
||||
if r:
|
||||
if "image_id" in r[0].keys():
|
||||
poster_path = "https://images.igdb.com/igdb/image/upload/t_cover_big/" + r[0]["image_id"] + ".jpg"
|
||||
windows = None
|
||||
mac = None
|
||||
linux = None
|
||||
if "windows" in info.keys():
|
||||
windows = info["windows"]
|
||||
if "mac" in info.keys():
|
||||
mac = info["mac"]
|
||||
if "linux" in info.keys():
|
||||
linux = info["linux"]
|
||||
game = (info["name"], game_id, description, poster_path, windows, mac, linux)
|
||||
games.append(game)
|
||||
i += 1
|
||||
if i >= 5:
|
||||
games_loaded.send("anonymous", games=games.copy())
|
||||
games.clear()
|
||||
i = 0
|
||||
games_loaded.send("anonymous", games=games)
|
||||
current_app.logger.info("finished loading games")
|
||||
|
5
templates/404.html
Normal file
5
templates/404.html
Normal file
@ -0,0 +1,5 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Page not found</h1>
|
||||
{% endblock %}
|
@ -35,6 +35,9 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for("tv_movies.index") }}">Tv & Movies</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for("games.index") }}">Games</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
|
5
templates/error.html
Normal file
5
templates/error.html
Normal file
@ -0,0 +1,5 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
{{ e }}
|
||||
{% endblock %}
|
@ -20,7 +20,6 @@
|
||||
<button type="submit">Prev</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
<h1 style="display: inline-block">Episode {{ episode.episode }}: {{ episode.title }}</h1>
|
||||
{% if loop.index0 + 1 < episodes|length %}
|
||||
<form style="display: inline-block; float: right; margin-top: 5px" action="" method="get">
|
||||
<input name="season" value="{{ episodes[loop.index0 + 1].season }}" hidden>
|
||||
@ -28,6 +27,8 @@
|
||||
<button type="submit">Next</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
<h1 style="display: inline-block">Episode {{ episode.episode }}: {{ episode.title }}</h1>
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<p style="text-align: left">{{ episode.description }}</p>
|
||||
|
Loading…
Reference in New Issue
Block a user