updated the comics viewer to dynamically load all the comics pages

moved pagination code from python to javascript
temporarily removed comics searched until it can be re-written for the new pagination
This commit is contained in:
Matthew Welch 2020-04-11 17:14:06 -07:00
parent c44de9b333
commit 2a5f7ae67f
19 changed files with 629 additions and 209 deletions

View File

@ -2,8 +2,7 @@ from flask import Blueprint, render_template, request, make_response, current_ap
from flask_login import login_required
from urllib import parse
from io import BytesIO
from wand.image import Image
import filetype
import os, pytz, datetime
import inspect
@ -91,52 +90,41 @@ def comics_publisher(publisher):
start = (max_items * (page - 1))
end = len(comics) if len(comics) < max_items * page else max_items * page
if issue:
if page_number:
return comic_viewer(publisher, series, series_year, issue)
return comic_gallery(publisher, series, series_year, issue)
return render_template("comics/seriesView.html", title="Comics", comics=comics,
comics_dict = []
for i in comics:
item = i.__dict__
item.pop('_sa_instance_state', None)
item.pop('path', None)
comics_dict.append(item)
return render_template("comics/seriesView.html", title="Comics", comics=comics_dict,
start=start, end=end, page=page, max_items=max_items, item_count=len(comics))
return render_template("comics/publisherSeriesView.html", title="Comics", publisher_series=publisher_series,
pub_series_dict = []
for i in publisher_series:
item = i.__dict__
item.pop('_sa_instance_state', None)
item.pop('path', None)
pub_series_dict.append(item)
return render_template("comics/publisherSeriesView.html", title="Comics", publisher_series=pub_series_dict,
start=start, end=end, page=page, max_items=max_items, item_count=len(publisher_series))
except Exception as e:
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
return str(type(e)) + " " + str(e)
def comic_viewer(publisher, series, series_year, issue):
try:
on_mobile = False
if request.user_agent.platform in MOBILE_DEVICES:
on_mobile = True
publisher_parsed = parse.quote(publisher)
series_parsed = parse.quote(series)
page_number = int(request.args.get("pageNumber"))
meta = database.db_get_comic(publisher, series, series_year, issue)
page_count = int(meta.pagecount)
prev_page = page_number - 1
next_page = page_number + 1
if next_page >= page_count:
next_page = 0
if prev_page < 0:
prev_page = page_count - 1
prev_url = "/comics/{}?series={}&seriesYear={}&issue={}&pageNumber={}".format(publisher_parsed, series_parsed, series_year, issue, prev_page)
next_url = "/comics/{}?series={}&seriesYear={}&issue={}&pageNumber={}".format(publisher_parsed, series_parsed, series_year, issue, next_page)
title = "Comics: "+meta.series+": #"+meta.issuetext+" "+(meta.title or "")
return render_template("comics/comicView.html", title=title, on_mobile=on_mobile, prev_url=prev_url, next_url=next_url, comic=meta, page_number=page_number)
except Exception as e:
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
return str(type(e)) + " " + str(e)
def comic_gallery(publisher, series, series_year, issue):
@Comics.route("/comics/<int:comic_id>")
@login_required
def comic_gallery(comic_id):
try:
page = request.args.get("page", 1, type=int)
max_items = request.args.get("max_items", 30, type=int)
meta = database.db_get_comic(publisher, series, series_year, issue)
meta = database.db_get_comic(comic_id)
start = (max_items*(page-1))
end = meta.pagecount if meta.pagecount < max_items*page else max_items*page
return render_template("comics/comicGallery.html", title="Comics", comic=meta, start=start, end=end, page=page, max_items=max_items, item_count=meta.pagecount)
comic_dict = meta.__dict__
comic_dict.pop('_sa_instance_state', None)
comic_dict.pop('path', None)
return render_template("comics/comicGallery.html", title="Comics", comic=comic_dict, start=start, end=end, page=page, max_items=max_items, item_count=meta.pagecount)
except Exception as e:
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
return str(type(e)) + " " + str(e)
@ -147,13 +135,13 @@ def comic_gallery(publisher, series, series_year, issue):
def get_comic_page(comic_id, page_number):
meta = database.db_get_comic_by_id(comic_id)
comic = func.open_comic(meta.path)
byte_image = BytesIO(comic.getPage(page_number))
image = Image(file=byte_image)
response = make_response(image.make_blob())
byte_image = comic.getPage(page_number)
type = filetype.guess(byte_image).mime
response = make_response(byte_image)
response.headers["content-type"] = type
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-type"] = "image/" + image.format
return response

View File

@ -1,12 +0,0 @@
{% for i in range(start, end) %}
<div class="col-3" style="padding: 10px">
<a href="/comics/{{ publisher_series[i].publisher|urlencode }}?series={{ publisher_series[i].series|urlencode }}&seriesYear={{ publisher_series[i].seriesyear }}">
<div class="card">
<img class="card-img" src="/comics/get_comic/{{ publisher_series[i]['id'] }}/0/thumbnail" onerror="this.src='/static/images/default.png'">
<div class="card-body">
{{ publisher_series[i].series }} {{ publisher_series[i].seriesyear }}
</div>
</div>
</a>
</div>
{% endfor %}

View File

@ -1,22 +1,205 @@
{% extends "base.html" %}
{% block head %}
<script src="/static/hammer.js"></script>
<style>
/* The Modal (background) */
.light-box {
display: none;
position: fixed;
z-index: 1;
padding-top: 100px;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: black;
}
/* Modal Content */
.light-box-content {
position: relative;
background-color: #fefefe;
margin: auto;
padding: 0;
width: 90%;
max-width: 1200px;
}
/* The Close Button */
.close {
color: white;
position: absolute;
top: 10px;
right: 25px;
font-size: 35px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: #999;
text-decoration: none;
cursor: pointer;
}
/* Hide the slides by default */
.mySlides {
display: none;
}
/* Next & previous buttons */
.prev,
.next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
padding: 16px;
margin-top: -50px;
color: white;
font-weight: bold;
font-size: 20px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
-webkit-user-select: none;
}
/* Position the "next button" to the right */
.next {
right: 0;
border-radius: 3px 0 0 3px;
}
/* On hover, add a black background color with a little bit see-through */
.prev:hover,
.next:hover {
background-color: rgba(0, 0, 0, 0.8);
}
/* Number text (1/3 etc) */
.numbertext {
color: #f2f2f2;
font-size: 12px;
padding: 8px 12px;
position: absolute;
top: 0;
}
</style>
{% endblock %}
{% block content %}
<div style="text-align: center">
{% include "pagination.html" %}
</div>
<div style="text-align: center">
<div class="comic-grid">
{% for page_number in range(start, end) %}
<div style="margin: auto" class="comic-thumbnail card bg-dark text-white">
<a href="/comics/{{ comic.publisher|urlencode }}?series={{ comic.series|urlencode }}&seriesYear={{ comic.seriesyear }}&issue={{ comic.issue|urlencode }}&pageNumber={{ page_number }}">
<img src="/comics/get_comic/{{ comic.id }}/{{ page_number }}/thumbnail" alt="" style="display: inline" onerror="this.src='/static/images/default.png'">
<p class="card-text">{{ 1+page_number }}/{{ comic.pagecount }}</p>
</a>
</div>
{% endfor %}
</div>
<div id="page-container" class="comic-grid"></div>
</div>
<div style="text-align: center">
{% include "pagination.html" %}
</div>
<div id="page" class="light-box">
<span class="close cursor" onclick="closeLightBox()">&times;</span>
<div id="light-box-content" class="light-box-content">
<a id="prev" class="prev" onclick="offsetImages(-1)">&#10094;</a>
<a id="next" class="next" onclick="offsetImages(1)">&#10095;</a>
</div>
</div>
{% endblock %}
{% block footer %}
<script>
var comic = {{ comic|tojson }};
function populate_page() {
page_container.innerHTML = "";
for (i = start;i < end; i++) {
var list_element = `<div style="margin: auto" class="comic-thumbnail card bg-dark text-white">
<img src="/comics/get_comic/${comic.id}/${i}/thumbnail" alt="" style="display: inline" onerror="this.src='/static/images/default.png';this.height='256'" onclick="openLightBox();currentImage(${1+i})">
<p class="card-text">${1+i}/${comic.pagecount}</p>
</div>`;
page_container.innerHTML += list_element;
}
}
go_to_page(page_num);
</script>
<script>
let page_count = {{ comic.pagecount }};
let comic_id = {{ comic.id }};
let nav_display = document.getElementsByTagName("nav")[0].style.display;
let light_box_content = document.getElementById("light-box-content");
let next_image = document.getElementById("next");
let prev_image = document.getElementById("prev");
function load_next_image(page_number) {
if (document.getElementById(page_number.toString())) {return;}
if (page_number >= page_count) {return;}
console.log("start loading: page "+(page_number+1).toString());
let image = '<div class="images">';
image += `<div class="numbertext">${1 + page_number} / ${page_count}</div>`;
image += `<img id="${page_number}" style="width: 100%" src="/comics/get_comic/${comic_id}/${page_number}" alt="" onerror="this.src=\'/static/images/default.png\';load_next_image(${page_number + 1})" ondragstart="return false" onload="load_next_image(${page_number + 1})">`;
image += '</div>';
light_box_content.innerHTML += image;
}
// Open the Modal
function openLightBox() {
document.getElementById("page").style.display = "block";
document.getElementsByTagName("nav")[0].style.display = "none";
}
// Close the Modal
function closeLightBox() {
document.getElementById("page").style.display = "none";
document.getElementsByTagName("nav")[0].style.display = nav_display;
}
var imageIndex = 1;
// Next/previous controls
function offsetImages(n) {
showImage(imageIndex += n);
document.getElementById("page").scrollTo(0,0);
}
// Thumbnail image controls
function currentImage(n) {
showImage(imageIndex = n);
document.getElementById("page").scrollTo(0,0);
}
function showImage(n) {
var i;
var slides = document.getElementsByClassName("images");
if (n > slides.length) {imageIndex = 1}
if (n < 1) {imageIndex = slides.length}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
slides[imageIndex-1].style.display = "block";
}
document.addEventListener("keydown", function (event) {
if (event.key == "ArrowRight") {
next_image.click();
}
else if (event.key == "ArrowLeft") {
prev_image.click();
}
})
let page = document.getElementById("page");
let hammer = new Hammer(page);
hammer.on("swiperight", function (ev) {
prev_image.click();
});
hammer.on("swipeleft", function (ev) {
next_image.click();
});
load_next_image(0);
</script>
{% endblock %}

View File

@ -1,15 +1,15 @@
{% extends "base.html" %}
{% block nav %}
<nav class="navbar navbar-expand">
<ul class="navbar-nav mr-auto"></ul>
<form class="form-inline" method="get" action="/comics/search">
<div class="form-group mx-2">
<input type="text" class="form-control" minlength="3" name="q">
</div>
<button type="submit" class="btn btn-primary">Search</button>
</form>
</nav>
{# <nav class="navbar navbar-expand">#}
{# <ul class="navbar-nav mr-auto"></ul>#}
{# <form class="form-inline" method="get" action="/comics/search">#}
{# <div class="form-group mx-2">#}
{# <input type="text" class="form-control" minlength="3" name="q">#}
{# </div>#}
{# <button type="submit" class="btn btn-primary">Search</button>#}
{# </form>#}
{# </nav>#}
{% endblock %}
{% block content %}
@ -17,11 +17,32 @@
{% include "pagination.html" %}
</div>
<div class="container col-7">
<div class="row justify-content-start">
{% include "comics/publisherList.html" %}
</div>
<div id="page-container" class="row justify-content-start"></div>
</div>
<div style="text-align: center">
{% include "pagination.html" %}
</div>
{% endblock %}
{% block footer %}
<script>
var publishers = {{ publishers|tojson }};
function populate_page() {
page_container.innerHTML = "";
for (i = start;i < end; i++) {
var list_element = `<div class="col-4" style="padding: 10px">
<a href="/comics/${publishers[i]}">
<div class="card">
<img class="card-img" src="/static/images/${publishers[i]}.png" onerror="this.src='/static/images/default_banner.png'">
<div class="card-body">
${publishers[i]}
</div>
</div>
</a>
</div>`;
page_container.innerHTML += list_element;
}
}
go_to_page(page_num);
</script>
{% endblock %}

View File

@ -1,12 +0,0 @@
{% for i in range(start, end) %}
<div class="col-4" style="padding: 10px">
<a href="/comics/{{ publishers[i] }}">
<div class="card">
<img class="card-img" src="/static/images/{{ publishers[i] }}.png" onerror="this.src='/static/images/default_banner.png'">
<div class="card-body">
{{ publishers[i] }}
</div>
</div>
</a>
</div>
{% endfor %}

View File

@ -5,11 +5,32 @@
{% include "pagination.html" %}
</div>
<div class="container col-7">
<div class="row justify-content-start">
{% include "comics/PublisherSeriesList.html" %}
</div>
<div id="page-container" class="row justify-content-start"></div>
</div>
<div style="text-align: center">
{% include "pagination.html" %}
</div>
{% endblock %}
{% block footer %}
<script>
var publisher_series = {{ publisher_series|tojson }};
function populate_page() {
page_container.innerHTML = "";
for (i = start;i < end; i++) {
var list_element = `<div class="col-3" style="padding: 10px">
<a href="/comics/${encodeURI(publisher_series[i].publisher)}?series=${encodeURI(publisher_series[i].series)}&seriesYear=${publisher_series[i].seriesyear}">
<div class="card">
<img class="card-img" src="/comics/get_comic/${publisher_series[i]['id']}/0/thumbnail" onerror="this.src='/static/images/default.png'">
<div class="card-body">
${publisher_series[i].series} ${publisher_series[i].seriesyear}
</div>
</div>
</a>
</div>`;
page_container.innerHTML += list_element;
}
}
go_to_page(page_num);
</script>
{% endblock %}

View File

@ -1,12 +0,0 @@
{% for i in range(start, end) %}
<div class="col-3" style="padding: 10px">
<a href="/comics/{{ comics[i].publisher|urlencode }}?series={{ comics[i].series|urlencode }}&seriesYear={{ comics[i].seriesyear }}&issue={{ comics[i].issue|urlencode }}">
<div class="card">
<img class="card-img" src="/comics/get_comic/{{ comics[i]['id'] }}/0/thumbnail" onerror="this.src='/static/images/default.png'">
<div class="card-body">
{{ comics[i].series }} {% if comics[i].issue > 0 %}{{ "#{0:g}".format(comics[i].issue) }}{% endif %} {% if comics[i].title != None %}{{ comics[i].title }} {% endif %}
</div>
</div>
</a>
</div>
{% endfor %}

View File

@ -5,11 +5,33 @@
{% include "pagination.html" %}
</div>
<div class="container col-7">
<div class="row justify-content-start">
{% include "comics/seriesList.html" %}
</div>
<div id="page-container" class="row justify-content-start"></div>
</div>
<div style="text-align: center">
{% include "pagination.html" %}
</div>
{% endblock %}
{% block footer %}
<script>
var comics = {{ comics|tojson }};
function populate_page() {
page_container.innerHTML = "";
for (i = start;i < end; i++) {
var title = comics[i].title ? comics[i].title : "";
var list_element = `<div class="col-3" style="padding: 10px">
<a href="/comics/${encodeURI(comics[i].id)}">
<div class="card">
<img class="card-img" src="/comics/get_comic/${ comics[i]['id']}/0/thumbnail" onerror="this.src='/static/images/default.png'">
<div class="card-body">
${comics[i].series} #${comics[i].issue}: ${title}
</div>
</div>
</a>
</div>`;
page_container.innerHTML += list_element;
}
}
go_to_page(page_num);
</script>
{% endblock %}

View File

@ -261,7 +261,7 @@ def root():
@login_required
def home():
try:
return render_template("home.html", title="Hello World", current_user=current_user)
return render_template("home.html", title="Home", current_user=current_user)
except Exception as e:
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
return str(e)

View File

@ -7,7 +7,7 @@ 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
from sqlalchemy import Column, Integer, String, BLOB, Boolean, DateTime, Numeric, func, over, ARRAY, TIMESTAMP
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.pool import NullPool
from sqlalchemy.sql.expression import cast
@ -295,6 +295,28 @@ class UserTvMovieData(Base):
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
class TvMovieKeywords(Base):
__tablename__ = "tv_movie_keywords"
imdb_id = Column(String)
extended = Column(Boolean, default=False)
directors_cut = Column(Boolean, default=False)
key_words = Column(ARRAY(String))
id = Column(Integer, primary_key=True)
date = Column(TIMESTAMP)
def __init__(self, data):
i = 0
try:
for column in self.__table__.columns:
if column.name == "id" or column.name == "date":
continue
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 UserComicData(Base):
__tablename__ = "user_comic_data"
@ -447,7 +469,6 @@ def db_get_series_by_publisher(publisher):
def db_get_comics_in_series(series, publisher, series_year):
session = Session()
current_app.logger.info(str(session.query(Comic).filter(Comic.publisher == publisher, Comic.series == series, Comic.seriesyear == series_year).order_by(Comic.issue)))
result = session.query(Comic).filter(Comic.publisher == publisher, Comic.series == series, Comic.seriesyear == series_year).order_by(Comic.issue).all()
comics = result
return comics
@ -472,9 +493,10 @@ def db_get_thumbnail_by_id_page(comic_id, pageNumber):
return thumbnail
def db_get_comic(publisher, series, series_year, issue):
def db_get_comic(comic_id):
session = Session()
comic = session.query(Comic).filter(Comic.publisher == publisher, Comic.series == series, Comic.seriesyear == series_year, Comic.issue == issue).one_or_none()
comic = session.query(Comic).filter(Comic.id == comic_id).one_or_none()
#comic = session.query(Comic).filter(Comic.publisher == publisher, Comic.series == series, Comic.seriesyear == series_year, Comic.issue == issue).one_or_none()
return comic
@ -615,6 +637,10 @@ def get_tv_movie_by_imdb_id(imdb_id, extended=False, directors_cut=False):
return result
def get_currently_watching():
pass
def get_all_tv_shows():
session = Session()
result = session.query(TvShow).order_by(TvShow.title, TvShow.year).all()

View File

@ -1,12 +1,14 @@
from flask import current_app
from comicapi import comicarchive
from blinker import Namespace
from datetime import timedelta
from io import BytesIO
from wand.image import Image
import os, re
import inspect
import json
import enzyme
from scripts import database
@ -353,3 +355,71 @@ def get_tv_episode(path):
tv_episodes_loaded.send("anonymous", tv_episodes=episodes)
current_app.logger.info("finished load tv episode")
def get_chapters(path):
try:
with open(path, 'rb') as f:
mkv = enzyme.MKV(f)
except Exception as e:
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
mkv_info = {}
for chapter in mkv.chapters:
if chapter.string == "Intro":
mkv_info["intro"] = {
"start": chapter.start.seconds,
"end": timedelta(microseconds=chapter.end//1000).seconds
}
if chapter.string == "Credits":
mkv_info["credits"] = {"start": chapter.start.seconds}
if chapter.string == "end-credit scene":
if "end-credit scene" not in mkv_info.keys():
mkv_info["end-credit scene"] = []
end_credit = {"start": chapter.start.seconds}
if chapter.end:
end_credit["end"] = timedelta(microseconds=chapter.end//1000).seconds
mkv_info["end-credit scene"].append(end_credit)
return mkv_info
def get_tags(path):
try:
with open(path, 'rb') as f:
mkv = enzyme.MKV(f)
except Exception as e:
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
mkv_info = {}
for tag in mkv.tags:
if tag.targets.data[0].data == 70:
mkv_info["collection"] = {}
for simple in tag.simpletags:
if simple.name == "TITLE":
mkv_info["collection"]["title"] = simple.string
if simple.name == "TOTAL_PARTS":
mkv_info["collection"]["episodes"] = int(simple.string)
if simple.name == "KEYWORDS":
mkv_info["collection"]["key_words"] = simple.string.split(",")
if simple.name == "DATE_RELEASED":
mkv_info["collection"]["year"] = int(simple.string)
if simple.name == "SUMMARY":
mkv_info["collection"]["summary"] = simple.string
if tag.targets.data[0].data == 60:
mkv_info["season"] = {}
for simple in tag.simpletags:
if simple.name == "TITLE":
mkv_info["season"]["title"] = simple.string
if simple.name == "TOTAL_PARTS":
mkv_info["season"]["episodes"] = int(simple.string)
if tag.targets.data[0].data == 50:
mkv_info["movie"] = {}
for simple in tag.simpletags:
if simple.name == "TITLE":
mkv_info["movie"]["title"] = simple.string
if simple.name == "DATE_RELEASED":
mkv_info["movie"]["year"] = int(simple.string)
if simple.name == "PART_NUMBER":
mkv_info["movie"]["episode"] = int(simple.string)
if simple.name == "KEYWORDS":
mkv_info["movie"]["key_words"] = simple.string.split(",")
if simple.name == "SUMMARY":
mkv_info["movie"]["summary"] = simple.string
return mkv_info

View File

@ -57,11 +57,87 @@
{% endblock %}
</div>
<script>
var page_num = {{ page }};
var max_items = {{ max_items }};
var item_count = {{ item_count }};
var start = max_items*(page_num-1);
var end;
if (item_count < max_items*page_num) {
end = item_count;
} else {
end = max_items * page_num;
}
var page_container = document.getElementById("page-container");
function go_to_page(pagenumber) {
page_num = pagenumber;
start = max_items*(page_num-1);
if (item_count < max_items*page_num) {
end = item_count;
} else {
end = max_items * page_num;
}
populate_page()
var page_count = Math.ceil(item_count/max_items);
if (page_count > 1) {
var min = 1 + page_num - 6;
var max = page_num + 6;
var prev = page_num - 1;
var next = page_num + 1;
if (min <= 1) {
min = 2;
}
if (max >= page_count) {
max = page_count;
}
var pagination_bars = document.getElementsByClassName("pagination");
for (let i = 0; i < pagination_bars.length; i++) {
pagination_bars[i].innerHTML = "";
if (page_num != 1) {
var prev_item = `<li class="page-item"><button name="page" value="${prev}" class="page-link" onclick="offset_page(-1)"><img src="/static/svg/chevron-left.svg"></button></li>`;
pagination_bars[i].innerHTML += prev_item;
}
first_active = "";
if (page_num == 1) {first_active = "active"}
var first_item = `<li class="page-item ${first_active}"><button name="page" value="1" class="page-link" onclick="go_to_page(1)">1</button></li>`;
pagination_bars[i].innerHTML += first_item;
if (min > 2) {pagination_bars[i].innerHTML += "...";}
for (x = min; x < max; x++) {
active = "";
if (page_num == x) {active = "active"}
var item = `<li class="page-item ${active}"><button name="page" value="${x}" class="page-link" onclick="go_to_page(${x})">${x}</button></li>`;
pagination_bars[i].innerHTML += item;
}
if (max < page_count) {pagination_bars[i].innerHTML += "...";}
last_active = "";
if (page_num == page_count) {last_active = "active"}
var last_item = `<li class="page-item ${last_active}"><button name="page" value="1" class="page-link" onclick="go_to_page(${page_count})">${page_count}</button></li>`;
pagination_bars[i].innerHTML += last_item;
if (page_num != page_count) {
var next_item = `<li class="page-item"><button name="page" value="${next}" class="page-link" onclick="offset_page(1)"><img src="/static/svg/chevron-right.svg"></button></li>`;
pagination_bars[i].innerHTML += next_item;
}
}
}
}
function offset_page(i) {
go_to_page(page_num += i);
}
</script>
{% block footer %}
<footer class="bg-secondary" style="flex-shrink: 0; padding: 20px;">
{% block footer_content %}
{% endblock footer_content %}
</footer>
{% endblock footer %}
<script>
</script>
</body>
</html>

View File

@ -1,48 +1,4 @@
{% with page_count=(item_count/max_items)|round(method="ceil")|int %}
{% if page_count > 1 %}
<nav aria-label="Page navigation example" style="display: inline-block; margin: 5px">
<form method="get" action="">
{% for key in request.args.keys() %}
{% if key != "page" %}<input type="hidden" name="{{ key }}" value="{{ request.args.get(key) }}">{% endif %}
{% endfor %}
{% with %}
{% set min = 1+page-6 %}
{% set max = page+6 %}
{% set prev = page-1 %}
{% set next = page+1 %}
{% if min <= 1 %}{% set min = 2 %}{% endif %}
{% if max >= page_count %}{% set max = page_count %}{% endif %}
<ul class="pagination">
{% if prev > 0 %}
<li class="page-item">
<button name="page" value="{{ prev }}" class="page-link"><img src="/static/svg/chevron-left.svg"></button>
</li>
{% endif %}
<li class="page-item{% if page == 1 %} active{% endif %}">
<button name="page" value="1" class="page-link">1</button>
</li>
{% if min >2 %}...{% endif %}
{% for i in range(min, max) %}
<li class="page-item{% if page == i %} active{% endif %}">
<button name="page" value="{{ i }}" class="page-link">{{ i }}</button>
</li>
{% endfor %}
{% if max < page_count %}...{% endif %}
<li class="page-item{% if page == page_count %} active{% endif %}">
<button name="page" value="{{ page_count }}" class="page-link">{{ page_count }}</button>
</li>
{% if next < page_count+1 %}
<li class="page-item">
<button name="page" value="{{ next }}" class="page-link"><img src="/static/svg/chevron-right.svg"></button>
</li>
{% endif %}
{% endwith %}
</ul>
</form>
</nav>
{% endif %}
{% endwith %}

View File

@ -51,12 +51,12 @@
<button type="submit" hidden>submit</button>
</form>
{% endwith %}
<div style="overflow: auto; white-space: nowrap">
<div id="episode_list" style="overflow: auto; white-space: nowrap">
<form action="" method="get">
<input name="season" value="{{ season_num }}" hidden>
{% for episode in episodes %}
{% if episode.season == season_num %}
<button name="episode" value="{{ episode.episode }}" onclick="this.form.submit()" style="border: none">
<button id="{{ episode.episode }}" name="episode" value="{{ episode.episode }}" onclick="this.form.submit()" style="border: none">
<div class="w3-display-container">
<img src="https://image.tmdb.org/t/p/original{{ episode.still_path }}" width="350px">
<div class="w3-display-topleft w3-container w3-round" style="background: rgba(105,105,105,0.61);color: white">Episode {{ episode.episode }}</div>
@ -91,15 +91,36 @@
<p>This product uses the TMDb API but is not endorsed or certified by TMDb.</p>
</div>
<script>
function findPos(obj) {
var curtop = 0;
if (obj.offsetParent) {
do {
curtop += obj.offsetLeft;
} while (obj = obj.offsetParent);
return curtop;
}
}
let episode = document.getElementById({{ episode_num }});
let width = episode.offsetWidth;
document.getElementById("episode_list").scrollLeft = findPos(episode)-(width*2);
videojs("player").ready(function(){
let myPlayer = videojs.getPlayer("player");
let saved_time = {{ user_data.time }};
let length = -1;
let end_time = -1;
let finished = {{ user_data.finished|string|lower }}; //converts python bool into javascript bool
let length = 0;
if (saved_time > 5 && !finished) {
myPlayer.currentTime(saved_time);
}
myPlayer.on("loadedmetadata", function () {
length = myPlayer.duration();
end_time = length-15;
{% if "credits" in chapters.keys() %}
end_time = {{ chapters["credits"]["start"] }};
{% endif %}
});
function reqListener() {
console.log(this.responseText);
}
@ -107,19 +128,21 @@
let time = myPlayer.currentTime();
myPlayer.on("timeupdate", function () {
if (myPlayer.currentTime()-time >= 10) {
length = myPlayer.duration();
finished = myPlayer.currentTime() >= end_time;
//length = myPlayer.duration();
let oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("POST", "https://rpi.narnian.us/tv_movies/{{ episode.imdb_id }}?time="+(time+5)+"&parent={{ episode.parent_imdb_id }}&length="+length);
oReq.open("POST", "https://rpi.narnian.us/tv_movies/{{ episode.imdb_id }}?time="+(time+5)+"&parent={{ episode.parent_imdb_id }}&length="+length+"&finished="+finished);
oReq.send();
time = myPlayer.currentTime();
}
});
myPlayer.on("pause", function () {
length = myPlayer.duration();
finished = myPlayer.currentTime() >= end_time;
//length = myPlayer.duration();
let oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("POST", "https://rpi.narnian.us/tv_movies/{{ episode.imdb_id }}?time="+(time+5)+"&parent={{ episode.parent_imdb_id }}&length="+length);
oReq.open("POST", "https://rpi.narnian.us/tv_movies/{{ episode.imdb_id }}?time="+(time+5)+"&parent={{ episode.parent_imdb_id }}&length="+length+"&finished="+finished);
oReq.send();
time = myPlayer.currentTime();
});

View File

@ -16,10 +16,8 @@
<div style="text-align: center">
{% include "pagination.html" %}
</div>
<div class="container col-7">
<div class="row justify-content-start">
{% include "tv_movies/tvMovieList.html" %}
</div>
<div class="container col-10">
<div id="page-container" class="row justify-content-start"></div>
</div>
<div style="text-align: center">
{% include "pagination.html" %}
@ -31,4 +29,39 @@
<img src="/static/svg/tmdb.svg" alt="" style="height: 40px;">
<p>This product uses the TMDb API but is not endorsed or certified by TMDb.</p>
</div>
<script>
var tv_shows = {{ tv_shows|tojson }};
function populate_page() {
page_container.innerHTML = "";
for (i = start;i < end; i++) {
var anchor = `<a href="/tv_movies/${tv_shows[i][0].imdb_id}">`;
if (tv_shows[i][0].extended && tv_shows[i][0].directors_cut) {
anchor = `<a href="/tv_movies/${tv_shows[i][0].imdb_id}?extended=True&directors_cut=True">`;
} else if (tv_shows[i][0].extended) {
anchor = `<a href="/tv_movies/${tv_shows[i][0].imdb_id}?extended=True">`;
} else if (tv_shows[i][0].directors_cut) {
anchor = `<a href="/tv_movies/${tv_shows[i][0].imdb_id}?directors_cut=True">`;
}
var finished = ``;
if (tv_shows[i][1]) {
finished = `<div class="w3-display-topright w3-container" style="background: rgba(105,105,105,0.61); border-radius: 5px 0 0 5px">
<img src="/static/svg/verified.svg" >
</div>`
}
var list_element = `<div class="col-3" style="padding: 10px">
${anchor}
<div class="card w3-display-container">
<img class="card-img" src="https://image.tmdb.org/t/p/original${tv_shows[i][0].poster_path}" alt="" onerror="this.src='/static/images/default.png'">
<div class="card-body">
${tv_shows[i][0].title} (${tv_shows[i][0].year})
</div>
${finished}
</div>
</a>
</div>`;
page_container.innerHTML += list_element;
}
}
go_to_page(page_num);
</script>
{% endblock %}

View File

@ -33,11 +33,21 @@
videojs("player").ready(function(){
let myPlayer = videojs.getPlayer("player");
let saved_time = {{ user_data.time }};
let length = 0;
if (saved_time > 5) {
let length = -1;
let end_time = -1;
let finished = {{ user_data.finished|string|lower }}; //converts python bool into javascript bool
if (saved_time > 5 && !finished) {
myPlayer.currentTime(saved_time);
}
myPlayer.on("loadedmetadata", function () {
length = myPlayer.duration();
end_time = length-15;
{% if "credits" in chapters.keys() %}
end_time = {{ chapters["credits"]["start"] }};
{% endif %}
});
function reqListener() {
console.log(this.responseText);
}
@ -46,19 +56,21 @@
let timestamp = document.getElementById("timestamp");
myPlayer.on("timeupdate", function () {
if (myPlayer.currentTime()-time >= 10) {
finished = myPlayer.currentTime() >= end_time;
length = myPlayer.duration();
let oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("POST", "https://rpi.narnian.us/tv_movies/{{ movie.imdb_id }}?time="+(time+5)+"&length="+length{% if movie.extended %}+"&extended=True"{% endif %}{% if movie.directors_cut %}+"&directors_cut=True"{% endif %});
oReq.open("POST", "https://rpi.narnian.us/tv_movies/{{ movie.imdb_id }}?time="+(time)+"&length="+length+"&finished="+finished{% if movie.extended %}+"&extended=True"{% endif %}{% if movie.directors_cut %}+"&directors_cut=True"{% endif %});
oReq.send();
time = myPlayer.currentTime();
}
});
myPlayer.on("pause", function () {
finished = myPlayer.currentTime() >= end_time;
length = myPlayer.duration();
let oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("POST", "https://rpi.narnian.us/tv_movies/{{ movie.imdb_id }}?time="+(time+5)+"&length="+length{% if movie.extended %}+"&extended=True"{% endif %}{% if movie.directors_cut %}+"&directors_cut=True"{% endif %});
oReq.open("POST", "https://rpi.narnian.us/tv_movies/{{ movie.imdb_id }}?time="+(time)+"&length="+length+"&finished="+finished{% if movie.extended %}+"&extended=True"{% endif %}{% if movie.directors_cut %}+"&directors_cut=True"{% endif %});
oReq.send();
time = myPlayer.currentTime();
});

View File

@ -16,11 +16,9 @@
<div style="text-align: center">
{% include "pagination.html" %}
</div>
<div class="container col-7">
<div class="container col-10">
{% if movies != [] %}
<div class="row justify-content-start">
{% include "tv_movies/tvMovieList.html" %}
</div>
<div id="page-container" class="row justify-content-start"></div>
{% else %}
<h1>No results.</h1>
{% endif %}
@ -35,4 +33,39 @@
<img src="/static/svg/tmdb.svg" alt="" style="height: 40px;">
<p>This product uses the TMDb API but is not endorsed or certified by TMDb.</p>
</div>
<script>
var tv_shows = {{ tv_shows|tojson }};
function populate_page() {
page_container.innerHTML = "";
for (i = start;i < end; i++) {
var anchor = `<a href="/tv_movies/${tv_shows[i][0].imdb_id}">`;
if (tv_shows[i][0].extended && tv_shows[i][0].directors_cut) {
anchor = `<a href="/tv_movies/${tv_shows[i][0].imdb_id}?extended=True&directors_cut=True">`;
} else if (tv_shows[i][0].extended) {
anchor = `<a href="/tv_movies/${tv_shows[i][0].imdb_id}?extended=True">`;
} else if (tv_shows[i][0].directors_cut) {
anchor = `<a href="/tv_movies/${tv_shows[i][0].imdb_id}?directors_cut=True">`;
}
var finished = ``;
if (tv_shows[i][1]) {
finished = `<div class="w3-display-topright w3-container" style="background: rgba(105,105,105,0.61); border-radius: 5px 0 0 5px">
<img src="/static/svg/verified.svg" >
</div>`
}
var list_element = `<div class="col-3" style="padding: 10px">
${anchor}
<div class="card w3-display-container">
<img class="card-img" src="https://image.tmdb.org/t/p/original${tv_shows[i][0].poster_path}" alt="" onerror="this.src='/static/images/default.png'">
<div class="card-body">
${tv_shows[i][0].title} (${tv_shows[i][0].year})
</div>
${finished}
</div>
</a>
</div>`;
page_container.innerHTML += list_element;
}
}
go_to_page(page_num);
</script>
{% endblock footer_content %}

View File

@ -1,25 +0,0 @@
{% for i in range(start, end) %}
<div class="col-4" style="padding: 10px">
{% if tv_shows[i][0].extended and tv_shows[i][0].directors_cut %}
<a href="/tv_movies/{{ tv_shows[i][0].imdb_id }}?extended=True&directors_cut=True">
{% elif tv_shows[i][0].extended %}
<a href="/tv_movies/{{ tv_shows[i][0].imdb_id }}?extended=True">
{% elif tv_shows[i][0].directors_cut %}
<a href="/tv_movies/{{ tv_shows[i][0].imdb_id }}?directors_cut=True">
{% else %}
<a href="/tv_movies/{{ tv_shows[i][0].imdb_id }}">
{% endif %}
<div class="card w3-display-container">
<img class="card-img" src="https://image.tmdb.org/t/p/original{{ tv_shows[i][0].poster_path }}" alt="" onerror="this.src='/static/images/default.png'">
<div class="card-body">
{{ tv_shows[i][0].title }} ({{ tv_shows[i][0].year }})
</div>
{% if tv_shows[i][1] %}
<div class="w3-display-topright w3-container" style="background: rgba(105,105,105,0.61); border-radius: 5px 0 0 5px">
<img src="/static/svg/verified.svg" >
</div>
{% endif %}
</div>
</a>
</div>
{% endfor %}

View File

@ -17,7 +17,13 @@ def index():
tv = database.get_all_tv_movies()
start = (max_items * (page - 1))
end = len(tv) if len(tv) < max_items * page else max_items * page
return render_template("tv_movies/index.html", title="tv_movies", tv_shows=tv, page=page, max_items=max_items, start=start, end=end, item_count=len(tv))
tv_dict = []
for tv_item in tv:
item = tv_item[0].__dict__
item.pop('_sa_instance_state', None)
item.pop('path', None)
tv_dict.append((item, tv_item[1]))
return render_template("tv_movies/index.html", title="tv & movies", tv_shows=tv_dict, page=page, max_items=max_items, start=start, end=end, item_count=len(tv))
except Exception as e:
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
return str(type(e))+" "+str(e)
@ -32,13 +38,19 @@ def search():
start = 0
end = 0
query = request.args.get("q")
tv_shows = []
tv = []
if query:
tv_shows = database.db_search_tv_movie(query)
tv = database.db_search_tv_movie(query)
start = (max_items * (page - 1))
end = len(tv_shows) if len(tv_shows) < max_items * page else max_items * page
return render_template("tv_movies/search.html", title="tv_movies", tv_shows=tv_shows, page=page, max_items=max_items,
start=start, end=end, item_count=len(tv_shows))
end = len(tv) if len(tv) < max_items * page else max_items * page
tv_dict = []
for tv_item in tv:
item = tv_item[0].__dict__
item.pop('_sa_instance_state', None)
item.pop('path', None)
tv_dict.append((item, tv_item[1]))
return render_template("tv_movies/search.html", title="tv_movies", tv_shows=tv_dict, page=page, max_items=max_items,
start=start, end=end, item_count=len(tv))
except Exception as e:
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
return str(type(e))+" "+str(e)
@ -66,14 +78,16 @@ def movie_view(imdb_id, extended=False, directors_cut=False):
if request.method == "POST":
time = int(request.args.get("time", type=float))
length = int(request.args.get("length", type=float, default=0))
database.update_user_tv_movie_data(imdb_id, None, time, 0, True if length-time <= 15 else False, extended, directors_cut)
finished = True if request.args.get("finished", default="false") == "true" else False
database.update_user_tv_movie_data(imdb_id, None, time, length, finished, extended, directors_cut)
return make_response("", 201)
else:
movie_data = database.db_get_movie_by_imdb_id(imdb_id, extended=extended, directors_cut=directors_cut)
user_data = database.db_get_user_tv_movie_data(movie_data.imdb_id, extended=extended, directors_cut=directors_cut)
chapters = func.get_chapters(movie_data.path)
if not user_data:
user_data = database.update_user_tv_movie_data(movie_data.imdb_id, None, 0, 0)
return render_template("tv_movies/movieViewer.html", title="Movies: " + movie_data.title, movie=movie_data, user_data=user_data)
return render_template("tv_movies/movieViewer.html", title="Movies: " + movie_data.title, movie=movie_data, user_data=user_data, chapters=chapters)
except Exception as e:
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
return str(type(e)) + " " + str(e)
@ -86,7 +100,8 @@ def episode_viewer(imdb_id):
time = int(request.args.get("time", type=float))
parent_id = request.args.get("parent", type=str)
length = int(request.args.get("length", type=float, default=0))
database.update_user_tv_movie_data(imdb_id, parent_id, time, length, True if length-time <= 15 else False)
finished = True if request.args.get("finished", default="false") == "true" else False
database.update_user_tv_movie_data(imdb_id, parent_id, time, length, finished)
return make_response("", 201)
else:
tv_show = database.get_tv_show(imdb_id)
@ -98,11 +113,12 @@ def episode_viewer(imdb_id):
(current_episode, user_data) = database.db_get_current_tv_show_episode_and_data(imdb_id, episodes)
season_num = current_episode.season
episode_num = current_episode.episode
chapters = func.get_chapters(current_episode.path)
if not user_data:
user_data = database.update_user_tv_movie_data(current_episode.imdb_id, imdb_id, 0, 0)
else:
current_episode = episodes[0]
user_data = database.UserTvMovieData(("", "", "", 0, 0, False, datetime.datetime.now()))
user_data = database.UserTvMovieData(("", "", "", 0, 0, False, datetime.datetime.min))
for episode in episodes:
if episode.season == season_num and episode.episode == episode_num:
current_episode = episode
@ -119,7 +135,8 @@ def episode_viewer(imdb_id):
if not user_data:
user_data = database.update_user_tv_movie_data(current_episode.imdb_id, imdb_id, 0, 0)
break
return render_template("tv_movies/episodeViewer.html", title="Tv: " + tv_show.title, episodes=episodes, season_num=season_num, episode_num=episode_num, episode=current_episode, user_data=user_data, user_tv_show_data=user_tv_show_data)
chapters = func.get_chapters(current_episode.path)
return render_template("tv_movies/episodeViewer.html", title="Tv: " + tv_show.title, episodes=episodes, season_num=season_num, episode_num=episode_num, episode=current_episode, user_data=user_data, user_tv_show_data=user_tv_show_data, chapters=chapters)
except Exception as e:
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
return str(type(e)) + " " + str(e)