Added user data and Google OAuth
Added initial implementation of user data for tv shows and movies as well as OAuth for Google sign in.
@ -1,9 +1,7 @@
|
||||
from flask import Blueprint, flash, redirect, url_for, render_template
|
||||
from flask_login import login_required, current_user
|
||||
from sqlite_web import sqlite_web
|
||||
|
||||
Admin = Blueprint("admin", __name__, template_folder="templates")
|
||||
login_required(sqlite_web.index)
|
||||
|
||||
|
||||
@Admin.route("/admin")
|
||||
|
@ -26,7 +26,6 @@ def index():
|
||||
return render_template("comics/index.html", title="Comics", publishers=publishers, page=page, max_items=max_items, start=start, end=end, item_count=len(publishers))
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
return str(type(e)) + " " + str(e)
|
||||
|
||||
|
||||
@ -70,7 +69,6 @@ def search():
|
||||
publisher_end=publisher_end, series_end=series_end, comics_end=comics_end)
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
return str(type(e))+" "+str(e)
|
||||
|
||||
|
||||
@ -102,7 +100,6 @@ def comics_publisher(publisher):
|
||||
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))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
return str(type(e)) + " " + str(e)
|
||||
|
||||
|
||||
@ -115,7 +112,7 @@ def comic_viewer(publisher, series, series_year, issue):
|
||||
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"])
|
||||
page_count = int(meta.pageCount)
|
||||
|
||||
prev_page = page_number - 1
|
||||
next_page = page_number + 1
|
||||
@ -125,11 +122,10 @@ def comic_viewer(publisher, series, series_year, issue):
|
||||
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 "")
|
||||
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))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
return str(type(e)) + " " + str(e)
|
||||
|
||||
|
||||
@ -139,11 +135,10 @@ def comic_gallery(publisher, series, series_year, issue):
|
||||
max_items = request.args.get("max_items", 30, type=int)
|
||||
meta = database.db_get_comic(publisher, series, series_year, issue)
|
||||
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"])
|
||||
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)
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
return str(type(e)) + " " + str(e)
|
||||
|
||||
|
||||
@ -151,12 +146,12 @@ def comic_gallery(publisher, series, series_year, issue):
|
||||
@login_required
|
||||
def get_comic_page(comic_id, page_number):
|
||||
meta = database.db_get_comic_by_id(comic_id)
|
||||
comic = func.open_comic(meta["path"])
|
||||
comic = func.open_comic(meta.path)
|
||||
byte_image = BytesIO(comic.getPage(page_number))
|
||||
image = Image(file=byte_image)
|
||||
response = make_response(image.make_blob())
|
||||
response.headers["cache-control"] = "public"
|
||||
date = pytz.utc.localize(datetime.datetime.utcfromtimestamp(os.path.getmtime(meta["path"])))
|
||||
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
|
||||
@ -167,9 +162,9 @@ def get_comic_page(comic_id, page_number):
|
||||
def get_comic_thumbnail(comic_id, page_number):
|
||||
meta = database.db_get_comic_by_id(comic_id)
|
||||
thumb = database.db_get_thumbnail_by_id_page(comic_id, page_number)
|
||||
response = make_response(thumb["image"])
|
||||
response = make_response(thumb.image)
|
||||
response.headers["cache-control"] = "public"
|
||||
date = pytz.utc.localize(datetime.datetime.utcfromtimestamp(os.path.getmtime(meta["path"])))
|
||||
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-type"] = thumb.type
|
||||
return response
|
||||
|
@ -1,10 +1,10 @@
|
||||
{% 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"] }}">
|
||||
<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"] }}
|
||||
{{ publisher_series[i].series }} {{ publisher_series[i].seriesYear }}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
@ -8,9 +8,9 @@
|
||||
<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 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 %}
|
||||
|
@ -17,7 +17,7 @@
|
||||
{% endif %}
|
||||
</a>
|
||||
<a href="{{ next_url }}" ondragstart="return false">
|
||||
<img class="comic-page" ondragstart="return false" id="image" src="/comics/get_comic/{{ comic["id"] }}/{{ page_number }}" alt="">
|
||||
<img class="comic-page" ondragstart="return false" id="image" src="/comics/get_comic/{{ comic.id }}/{{ page_number }}" alt="">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
{% 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 }}">
|
||||
<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 %}
|
||||
{{ 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>
|
||||
|
@ -1,4 +1,4 @@
|
||||
from flask import Blueprint, render_template, request, make_response, send_file, send_from_directory, current_app
|
||||
from flask import Blueprint, render_template, request, make_response, send_from_directory, current_app
|
||||
from flask_login import login_required
|
||||
import inspect
|
||||
|
||||
@ -19,7 +19,6 @@ def index():
|
||||
return render_template("movies/index.html", title="Movies", movies=movies, page=page, max_items=max_items, start=start, end=end, item_count=len(movies))
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(type(e), e)
|
||||
return str(type(e)) + " " + str(e)
|
||||
|
||||
|
||||
@ -40,19 +39,26 @@ def search():
|
||||
return render_template("movies/search.html", title="Movies", movies=results, page=page, max_items=max_items, start=start, end=end, item_count=len(results))
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(type(e), e)
|
||||
return str(type(e)) + " " + str(e)
|
||||
|
||||
|
||||
@Movies.route("/movies/<imdb_id>")
|
||||
@Movies.route("/movies/<imdb_id>", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def movie_view(imdb_id):
|
||||
try:
|
||||
movie_data = database.db_get_movie_by_imdb_id(imdb_id)
|
||||
return render_template("movies/movieViewer.html", title="Movies: " + movie_data["title"], movie=movie_data)
|
||||
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)
|
||||
return make_response("", 201)
|
||||
else:
|
||||
movie_data = database.db_get_movie_by_imdb_id(imdb_id)
|
||||
user_data = database.db_get_user_tv_movie_data(movie_data.imdb_id)
|
||||
if not user_data:
|
||||
user_data = database.update_user_tv_movie_data(movie_data.imdb_id, None, 0, 0)
|
||||
return render_template("movies/movieViewer.html", title="Movies: " + movie_data.title, movie=movie_data, user_data=user_data)
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(type(e), e)
|
||||
return str(type(e)) + " " + str(e)
|
||||
|
||||
|
||||
@ -61,10 +67,9 @@ def movie_view(imdb_id):
|
||||
def movie_view_extended(imdb_id):
|
||||
try:
|
||||
movie_data = database.db_get_movie_by_imdb_id(imdb_id, extended=1)
|
||||
return render_template("movies/movieViewer.html", title="Movies: " + movie_data["title"], movie=movie_data)
|
||||
return render_template("movies/movieViewer.html", title="Movies: " + movie_data.title, movie=movie_data)
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(type(e), e)
|
||||
return str(type(e)) + " " + str(e)
|
||||
|
||||
|
||||
@ -73,10 +78,9 @@ def movie_view_extended(imdb_id):
|
||||
def movie_view_directors_cut(imdb_id):
|
||||
try:
|
||||
movie_data = database.db_get_movie_by_imdb_id(imdb_id, directors_cut=1)
|
||||
return render_template("movies/movieViewer.html", title="Movies: " + movie_data["title"], movie=movie_data)
|
||||
return render_template("movies/movieViewer.html", title="Movies: " + movie_data.title, movie=movie_data)
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(type(e), e)
|
||||
return str(type(e)) + " " + str(e)
|
||||
|
||||
|
||||
@ -84,7 +88,7 @@ def movie_view_directors_cut(imdb_id):
|
||||
@login_required
|
||||
def get_movie(imdb_id):
|
||||
movie_data = database.db_get_movie_by_imdb_id(imdb_id)
|
||||
filename = movie_data["title"]+" ("+str(movie_data["year"])+").mkv"
|
||||
filename = movie_data.title+" ("+str(movie_data.year)+").mkv"
|
||||
response = make_response(send_from_directory(func.MOVIES_DIRECTORY, filename))
|
||||
response.headers["content-type"] = "video/webm"
|
||||
return response
|
||||
@ -94,7 +98,7 @@ def get_movie(imdb_id):
|
||||
@login_required
|
||||
def get_movie_extended(imdb_id):
|
||||
movie_data = database.db_get_movie_by_imdb_id(imdb_id, extended=1)
|
||||
filename = movie_data["title"]+" ("+str(movie_data["year"])+").mkv"
|
||||
filename = movie_data.title+" ("+str(movie_data.year)+").mkv"
|
||||
response = make_response(send_from_directory(func.MOVIES_DIRECTORY, filename))
|
||||
response.headers["content-type"] = "video/webm"
|
||||
return response
|
||||
@ -104,7 +108,7 @@ def get_movie_extended(imdb_id):
|
||||
@login_required
|
||||
def get_movie_directors_cut(imdb_id):
|
||||
movie_data = database.db_get_movie_by_imdb_id(imdb_id, directors_cut=1)
|
||||
filename = movie_data["title"]+" ("+str(movie_data["year"])+").mkv"
|
||||
filename = movie_data.title+" ("+str(movie_data.year)+").mkv"
|
||||
response = make_response(send_from_directory(func.MOVIES_DIRECTORY, filename))
|
||||
response.headers["content-type"] = "video/webm"
|
||||
return response
|
||||
|
@ -2,16 +2,17 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="container" style="text-align: center">
|
||||
<video class="video-js vjs-big-play-centered" style="display: inline-block" controls preload="auto" width="1100"
|
||||
poster="https://image.tmdb.org/t/p/original{{ movie["backdrop_path"] }}" data-setup="{}">
|
||||
<source src="{{ url_for("movies.index") }}/get_movie/{{ movie["imdb_id"] }}{% if movie["extended"] == 1 %}/extended{% endif %}{% if movie["directors_cut"]==1 %}/directors_cut{% endif %}" type="video/webm">
|
||||
<video id="player" class="video-js vjs-big-play-centered" style="display: inline-block" controls preload="auto" width="1100"
|
||||
poster="https://image.tmdb.org/t/p/original{{ movie.backdrop_path }}" data-setup="{}">
|
||||
<source src="{{ url_for("movies.index") }}/get_movie/{{ movie.imdb_id }}{% if movie.extended == 1 %}/extended{% endif %}{% if movie.directors_cut==1 %}/directors_cut{% endif %}" type="video/webm">
|
||||
<p class='vjs-no-js'>
|
||||
To view this video please enable JavaScript, and consider upgrading to a web browser that
|
||||
<a href='https://videojs.com/html5-video-support/' target='_blank'>supports HTML5 video</a>
|
||||
</p>
|
||||
</video>
|
||||
<h1>{{ movie["title"] }}</h1>
|
||||
<p style="text-align: left">{{ movie["description"] }}</p>
|
||||
<h1>{{ movie.title }}</h1>
|
||||
<p style="text-align: left">{{ movie.description }}</p>
|
||||
<a class="btn btn-primary" href="{{ url_for("movies.index") }}/get_movie/{{ movie.imdb_id }}{% if movie.extended == 1 %}/extended{% endif %}{% if movie.directors_cut==1 %}/directors_cut{% endif %}" download="{{ movie.title }}">Download</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@ -20,4 +21,40 @@
|
||||
<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>
|
||||
videojs("player").ready(function(){
|
||||
let myPlayer = videojs.getPlayer("player");
|
||||
let saved_time = {{ user_data.time }};
|
||||
let length = 0;
|
||||
if (saved_time > 5) {
|
||||
myPlayer.currentTime(saved_time);
|
||||
}
|
||||
|
||||
function reqListener() {
|
||||
console.log(this.responseText);
|
||||
}
|
||||
|
||||
let time = myPlayer.currentTime();
|
||||
let timestamp = document.getElementById("timestamp");
|
||||
myPlayer.on("timeupdate", function () {
|
||||
if (myPlayer.currentTime()-time >= 10) {
|
||||
length = myPlayer.duration();
|
||||
let oReq = new XMLHttpRequest();
|
||||
oReq.addEventListener("load", reqListener);
|
||||
oReq.open("POST", "https://rpi.narnian.us/movies/{{ movie.imdb_id }}?time="+(time+5)+"&length="+length);
|
||||
oReq.send();
|
||||
time = myPlayer.currentTime();
|
||||
}
|
||||
});
|
||||
myPlayer.on("pause", function () {
|
||||
length = myPlayer.duration();
|
||||
let oReq = new XMLHttpRequest();
|
||||
oReq.addEventListener("load", reqListener);
|
||||
oReq.open("POST", "https://rpi.narnian.us/movies/{{ movie.imdb_id }}?time="+(time+5)+"&length="+length);
|
||||
oReq.send();
|
||||
time = myPlayer.currentTime();
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock footer_content %}
|
||||
|
@ -1,10 +1,10 @@
|
||||
{% for i in range(start, end) %}
|
||||
<div class="col-4" style="padding: 10px">
|
||||
<a href="/movies/{{ movies[i]["imdb_id"] }}{% if movies[i]["extended"] == 1 %}/extended{% endif %}{% if movies[i]["directors_cut"]==1 %}/directors_cut{% endif %}">
|
||||
<a href="/movies/{{ movies[i].imdb_id }}{% if movies[i].extended == 1 %}/extended{% endif %}{% if movies[i].directors_cut==1 %}/directors_cut{% endif %}">
|
||||
<div class="card">
|
||||
<img class="card-img" src="https://image.tmdb.org/t/p/original{{ movies[i]["poster_path"] }}" alt="" onerror="this.src='/static/images/default.png'">
|
||||
<img class="card-img" src="https://image.tmdb.org/t/p/original{{ movies[i].poster_path }}" alt="" onerror="this.src='/static/images/default.png'">
|
||||
<div class="card-body">
|
||||
{{ movies[i]["title"] }} ({{ movies[i]["year"] }})
|
||||
{{ movies[i].title }} ({{ movies[i].year }})
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
@ -7,5 +7,5 @@ location / {
|
||||
include fastcgi_params;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
fastcgi_param SCRIPT_NAME "";
|
||||
fastcgi_pass unix:/run/matt/rpiWebApp/fcgi.sock;
|
||||
fastcgi_pass unix:/run/rpiWebApp/fcgi.sock;
|
||||
}
|
||||
|
112
rpiWebApp.py
@ -1,12 +1,16 @@
|
||||
from flask import Flask
|
||||
from flask import render_template, request, g, redirect, url_for, flash, current_app
|
||||
from flask_login import LoginManager, current_user, login_user, logout_user, login_required
|
||||
from flask_log import Logging
|
||||
|
||||
from oauthlib.oauth2 import WebApplicationClient
|
||||
|
||||
import threading
|
||||
import logging
|
||||
import inotify.adapters, inotify.constants
|
||||
import inspect
|
||||
import datetime
|
||||
import requests
|
||||
import json
|
||||
|
||||
import scripts.func as func
|
||||
from scripts import database
|
||||
@ -26,15 +30,25 @@ nullLog = NullHandler()
|
||||
inotify.adapters._LOGGER = nullLog
|
||||
|
||||
|
||||
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()
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
app.register_blueprint(comics.Comics)
|
||||
app.register_blueprint(admin.Admin)
|
||||
app.register_blueprint(movies.Movies)
|
||||
app.register_blueprint(tv.TV)
|
||||
app.config["SECRET_KEY"] = "***REMOVED***"
|
||||
app.config["FLASK_LOG_LEVEL"] = "DEBUG"
|
||||
app.config["FLASK_LOG_FACILITY"] = "daemon"
|
||||
flask_log = Logging(app)
|
||||
app.logger.setLevel("DEBUG")
|
||||
|
||||
login_manager = LoginManager(app)
|
||||
login_manager.login_view = "login"
|
||||
@ -99,7 +113,6 @@ def update_comic_db(sender, **kw):
|
||||
database.add_comics(kw["meta"], kw["thumbnails"])
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
|
||||
|
||||
def update_movie_db(sender, **kw):
|
||||
@ -107,17 +120,13 @@ def update_movie_db(sender, **kw):
|
||||
database.add_movies(kw["movies"])
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
|
||||
|
||||
def update_tv_show_db(sender, **kw):
|
||||
try:
|
||||
database.add_tv_shows(kw["tv_show"])
|
||||
if kw["tv_episodes"]:
|
||||
database.add_tv_episodes(kw["tv_episodes"])
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
|
||||
|
||||
def update_tv_episodes_db(sender, **kw):
|
||||
@ -125,7 +134,6 @@ def update_tv_episodes_db(sender, **kw):
|
||||
database.add_tv_episodes(kw["tv_episodes"])
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
|
||||
|
||||
func.comic_loaded.connect(update_comic_db)
|
||||
@ -135,26 +143,96 @@ func.tv_episodes_loaded.connect(update_tv_episodes_db)
|
||||
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(username):
|
||||
return database.get_user(username)
|
||||
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))
|
||||
|
||||
|
||||
@app.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
try:
|
||||
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"],
|
||||
)
|
||||
|
||||
if request.method == "POST":
|
||||
username = request.form.get("username")
|
||||
email = request.form.get("email")
|
||||
password = request.form.get("password")
|
||||
user = database.get_user(username)
|
||||
user = database.get_user(email)
|
||||
if user is None or not user.check_password(password):
|
||||
flash("invalid username or password")
|
||||
flash("invalid email or password")
|
||||
return redirect(url_for("login"))
|
||||
login_user(user)
|
||||
login_user(user, remember=True, duration=datetime.timedelta(days=7))
|
||||
next_page = request.args.get("next")
|
||||
if not next_page:
|
||||
next_page = url_for("home")
|
||||
return redirect(next_page)
|
||||
return render_template("login.html", title="login")
|
||||
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"))
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
return str(e)
|
||||
|
@ -1 +0,0 @@
|
||||
import click
|
@ -1,5 +1,5 @@
|
||||
from flask import g, current_app
|
||||
from flask_login import UserMixin
|
||||
from flask_login import UserMixin, current_user
|
||||
|
||||
from werkzeug.security import check_password_hash
|
||||
from io import BytesIO
|
||||
@ -8,17 +8,19 @@ from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy import orm
|
||||
from sqlalchemy import Column, Integer, String, BLOB, Boolean, Table, MetaData, DateTime
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
from sqlalchemy.pool import QueuePool, NullPool
|
||||
import sqlite3
|
||||
import os
|
||||
import inspect
|
||||
import logging
|
||||
|
||||
from comicapi.issuestring import IssueString
|
||||
|
||||
from scripts import tmdb
|
||||
|
||||
RPI_DATABASE = "/var/lib/rpiWebApp/database.db"
|
||||
RPI_IMDB_DATABASE = "/var/lib/rpiWebApp/imdb.db"
|
||||
RPI_DATABASE = "/usb/storage/rpiWebApp/database.db"
|
||||
RPI_IMDB_DATABASE = "/usb/storage/rpiWebApp/imdb.db"
|
||||
|
||||
MC_DATABASE = "***REMOVED***"
|
||||
MC_IMDB_DATABASE = "C:\\Users\\Matthew\\Documents\\MyPrograms\\Websites\\rpi_web_interface\\imdb.db"
|
||||
@ -27,9 +29,11 @@ DATABASE = RPI_DATABASE if os.path.exists(RPI_DATABASE) else MC_DATABASE
|
||||
IMDB_DATABASE = RPI_IMDB_DATABASE if os.path.exists(RPI_IMDB_DATABASE) else MC_IMDB_DATABASE
|
||||
|
||||
|
||||
engine = create_engine("sqlite:///"+DATABASE+"?check_same_thread=False")
|
||||
Session = sessionmaker(bind=engine)
|
||||
session = Session()
|
||||
engine = create_engine("sqlite:///"+DATABASE+"?check_same_thread=False", poolclass=NullPool)
|
||||
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
|
||||
session_factory = sessionmaker(bind=engine)
|
||||
Session = scoped_session(session_factory)
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
|
||||
@ -84,7 +88,6 @@ class Comic(Base):
|
||||
i += 1
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) +" "+ str(e))
|
||||
#print(inspect.stack()[0][3], type(e), e)
|
||||
|
||||
def __repr__(self):
|
||||
return "<Comic: {series} {issue}>".format(series=self.series, issue=self.issueText)
|
||||
@ -109,7 +112,6 @@ class ComicThumbnail(Base):
|
||||
i += 1
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) +" "+ str(e))
|
||||
#print(inspect.stack()[0][3], type(e), e)
|
||||
|
||||
|
||||
class Movie(Base):
|
||||
@ -135,7 +137,6 @@ class Movie(Base):
|
||||
i += 1
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) +" "+ str(e))
|
||||
#print(inspect.stack()[0][3], type(e), e)
|
||||
|
||||
|
||||
class TvShow(Base):
|
||||
@ -157,7 +158,6 @@ class TvShow(Base):
|
||||
i += 1
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
|
||||
|
||||
class TvEpisode(Base):
|
||||
@ -181,104 +181,78 @@ class TvEpisode(Base):
|
||||
i += 1
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
|
||||
|
||||
class User(Base, UserMixin):
|
||||
__tablename__ = "users"
|
||||
|
||||
username = Column(String, unique=True, primary_key=True)
|
||||
id = Column(String, primary_key=True)
|
||||
username = Column(String)
|
||||
email = Column(String, unique=True)
|
||||
passwordHash = Column(String(128))
|
||||
isAdmin = Column(Boolean, default=False)
|
||||
|
||||
def __init__(self, data):
|
||||
i = 0
|
||||
for column in self.__table__.columns:
|
||||
setattr(self, column.name, data[i])
|
||||
i += 1
|
||||
self.init_user_data()
|
||||
|
||||
@orm.reconstructor
|
||||
def init_user_data(self):
|
||||
meta = MetaData()
|
||||
|
||||
self.comics = Table(
|
||||
"comics", meta,
|
||||
Column("comic_id", Integer, primary_key=True),
|
||||
Column("viewed", Boolean, default=False),
|
||||
Column("date", DateTime)
|
||||
)
|
||||
|
||||
self.movies = Table(
|
||||
"movies", meta,
|
||||
Column("imdb_id", Integer, primary_key=True),
|
||||
Column("viewed", Boolean, default=False),
|
||||
Column("date", DateTime)
|
||||
)
|
||||
|
||||
self.tv_episodes = Table(
|
||||
"tv_episodes", meta,
|
||||
Column("imdb_id", Integer, primary_key=True),
|
||||
Column("viewed", Boolean, default=False),
|
||||
Column("date", DateTime)
|
||||
)
|
||||
|
||||
self.tv_shows = Table(
|
||||
"tv_shows", meta,
|
||||
Column("imdb_id", Integer, primary_key=True),
|
||||
Column("viewed", Boolean, default=False),
|
||||
Column("date", DateTime)
|
||||
)
|
||||
|
||||
user_engine = create_engine("sqlite:///" + "user_" + self.username + ".db" + "?check_same_thread=False")
|
||||
self.conn = engine.connect()
|
||||
|
||||
meta.create_all(user_engine)
|
||||
|
||||
def set_comic_viewed(self, comic_id, val=True):
|
||||
self.conn.execute(self.comics.insert().values(comic_id=comic_id, viewed=val))
|
||||
|
||||
def is_comic_viewed(self, comic_id):
|
||||
q = self.comics.select().where(self.comics.c.comic_id == comic_id)
|
||||
result = self.conn.execute(q).fetchone()
|
||||
if result:
|
||||
return result["viewed"]
|
||||
|
||||
def set_movie_viewed(self, imdb_id, val=True):
|
||||
self.conn.execute(self.movies.insert().values(comic_id=imdb_id, viewed=val))
|
||||
|
||||
def is_movie_viewed(self, imdb_id):
|
||||
q = self.movies.select().where(self.movies.c.imdb_id == imdb_id)
|
||||
result = self.conn.execute(q).fetchone()
|
||||
if result:
|
||||
return result["viewed"]
|
||||
|
||||
def set_tv_episode_viewed(self, imdb_id, val=True):
|
||||
self.conn.execute(self.tv_episodes.insert().values(comic_id=imdb_id, viewed=val))
|
||||
|
||||
def is_tv_episode_viewed(self, imdb_id):
|
||||
q = self.tv_episodes.select().where(self.tv_episodes.c.imdb_id == imdb_id)
|
||||
result = self.conn.execute(q).fetchone()
|
||||
if result:
|
||||
return result["viewed"]
|
||||
|
||||
def set_tv_show_viewed(self, imdb_id, val=True):
|
||||
self.conn.execute(self.tv_shows.insert().values(comic_id=imdb_id, viewed=val))
|
||||
|
||||
def is_tv_show_viewed(self, imdb_id):
|
||||
q = self.tv_shows.select().where(self.tv_shows.c.imdb_id == imdb_id)
|
||||
result = self.conn.execute(q).fetchone()
|
||||
if result:
|
||||
return result["viewed"]
|
||||
try:
|
||||
for column in self.__table__.columns:
|
||||
setattr(self, column.name, data[i])
|
||||
i += 1
|
||||
pass
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
|
||||
def get_id(self):
|
||||
return self.username
|
||||
return self.email
|
||||
|
||||
def check_password(self, password):
|
||||
if not self.passwordHash:
|
||||
return
|
||||
result = check_password_hash(self.passwordHash, password)
|
||||
return result
|
||||
|
||||
|
||||
class UserTvMovieData(Base):
|
||||
__tablename__ = "user_tv_movie_data"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
user = Column(String)
|
||||
imdb_id = Column(String)
|
||||
parent_imdb_id = Column(String)
|
||||
time = Column(Integer)
|
||||
length = Column(Integer)
|
||||
finished = Column(Boolean, default=False)
|
||||
|
||||
def __init__(self, data):
|
||||
i = 0
|
||||
try:
|
||||
for column in self.__table__.columns:
|
||||
if column.name == "id":
|
||||
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"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
user = Column(String)
|
||||
comic_id = Column(Integer)
|
||||
viewed = Column(Boolean, default=False)
|
||||
|
||||
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))"""
|
||||
|
||||
|
||||
def get_db():
|
||||
db = getattr(g, '_database', None)
|
||||
if db is None:
|
||||
@ -336,22 +310,24 @@ def initialize_db():
|
||||
"teams" TEXT,
|
||||
"locations" TEXT,
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE
|
||||
)""")
|
||||
)""")
|
||||
get_db().execute("""CREATE TABLE IF NOT EXISTS "credits" (
|
||||
"id" INTEGER NOT NULL,
|
||||
"role" TEXT,
|
||||
"name" TEXT,
|
||||
"primary" INTEGER NOT NULL
|
||||
)""")
|
||||
)""")
|
||||
get_db().execute("""CREATE TABLE IF NOT EXISTS "comic_thumbnails" (
|
||||
"comic_id" INTEGER,
|
||||
"pageNumber" INTEGER,
|
||||
"image" BLOB,
|
||||
"type" TEXT,
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
)""")
|
||||
)""")
|
||||
get_db().execute("""CREATE TABLE IF NOT EXISTS "users" (
|
||||
"username" TEXT UNIQUE PRIMARY KEY,
|
||||
"id" TEXT PRIMARY KEY,
|
||||
"username" TEXT,
|
||||
"email" TEXT UNIQUE,
|
||||
"passwordHash" VARCHAR(128),
|
||||
"isAdmin" INTEGER NOT NULL DEFAULT 0
|
||||
)""")
|
||||
@ -367,7 +343,7 @@ def initialize_db():
|
||||
"directors_cut" INTEGER,
|
||||
"poster_path" TEXT,
|
||||
"backdrop_path" TEXT
|
||||
)""")
|
||||
)""")
|
||||
get_db().execute("""CREATE TABLE IF NOT EXISTS "tv_shows" (
|
||||
"imdb_id" TEXT PRIMARY KEY ,
|
||||
"tmdb_id" INTEGER UNIQUE,
|
||||
@ -387,7 +363,16 @@ def initialize_db():
|
||||
"description" TEXT,
|
||||
"still_path" TEXT,
|
||||
"path" TEXT
|
||||
)""")
|
||||
)""")
|
||||
get_db().execute("""CREATE TABLE IF NOT EXISTS "user_tv_movie_data" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
"user" TEXT,
|
||||
"imdb_id" TEXT,
|
||||
"parent_imdb_id" TEXT,
|
||||
"time" INTEGER,
|
||||
"length" INTEGER,
|
||||
"finished" INTEGER DEFAULT 0
|
||||
)""")
|
||||
get_db().execute("CREATE INDEX IF NOT EXISTS path_index ON comics(path);")
|
||||
get_db().execute("CREATE INDEX IF NOT EXISTS comic_id_index ON comic_thumbnails(comic_id);")
|
||||
get_db().commit()
|
||||
@ -398,7 +383,34 @@ def initialize_db():
|
||||
get_imdb().commit()
|
||||
|
||||
|
||||
def update_user_tv_movie_data(imdb_id, parent_id, time, length, finished=False):
|
||||
session = Session()
|
||||
email = current_user.email
|
||||
user_data = session.query(UserTvMovieData).filter(UserTvMovieData.imdb_id == imdb_id, UserTvMovieData.user == email).one_or_none()
|
||||
if user_data:
|
||||
user_data.time = time
|
||||
user_data.finished = finished
|
||||
if not user_data.length > 0 and length > 0:
|
||||
user_data.length = length
|
||||
session.commit()
|
||||
return user_data
|
||||
else:
|
||||
data = UserTvMovieData((email, imdb_id, parent_id, time, length, finished))
|
||||
session.add(data)
|
||||
session.commit()
|
||||
return data
|
||||
|
||||
|
||||
def add_user(data):
|
||||
session = Session()
|
||||
user = User(data)
|
||||
session.add(user)
|
||||
session.commit()
|
||||
return user
|
||||
|
||||
|
||||
def add_movies(movies):
|
||||
session = Session()
|
||||
for movie_data in movies:
|
||||
movie = Movie(movie_data)
|
||||
session.add(movie)
|
||||
@ -407,15 +419,16 @@ def add_movies(movies):
|
||||
|
||||
def add_tv_shows(tv_show_data):
|
||||
try:
|
||||
session = Session()
|
||||
tv_show = TvShow(tv_show_data)
|
||||
session.add(tv_show)
|
||||
session.commit()
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
|
||||
|
||||
def add_tv_episodes(episodes):
|
||||
session = Session()
|
||||
for episode_data in episodes:
|
||||
try:
|
||||
episode = TvEpisode(episode_data)
|
||||
@ -424,10 +437,10 @@ def add_tv_episodes(episodes):
|
||||
session.commit()
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
|
||||
|
||||
def add_comics(meta, thumbnails):
|
||||
session = Session()
|
||||
data = []
|
||||
for info in meta:
|
||||
issue = IssueString(info[1].issue).asFloat()
|
||||
@ -458,93 +471,96 @@ def add_comics(meta, thumbnails):
|
||||
|
||||
|
||||
def db_get_all_comics():
|
||||
session = Session()
|
||||
result = session.query(Comic).all()
|
||||
return result
|
||||
|
||||
|
||||
def db_get_series_by_publisher(publisher):
|
||||
session = Session()
|
||||
result = session.query(Comic).filter(Comic.publisher == publisher).group_by(Comic.publisher, Comic.series, Comic.seriesYear).order_by(Comic.series, Comic.seriesYear).all()
|
||||
series = [comic.__dict__ for comic in result]
|
||||
series = result
|
||||
return series
|
||||
|
||||
|
||||
def db_get_comics_in_series(series, publisher, series_year):
|
||||
session = Session()
|
||||
result = session.query(Comic).filter(Comic.publisher == publisher, Comic.series == series, Comic.seriesYear == series_year)\
|
||||
.order_by(Comic.issue).all()
|
||||
comics = [comic.__dict__ for comic in result]
|
||||
comics = result
|
||||
return comics
|
||||
|
||||
|
||||
def get_publishers():
|
||||
session = Session()
|
||||
result = session.query(Comic.publisher).distinct(Comic.publisher).order_by(Comic.publisher).all()
|
||||
publishers = [r for (r,) in result]
|
||||
return publishers
|
||||
|
||||
|
||||
def db_get_comic_by_id(comic_id):
|
||||
comic = session.query(Comic).filter(Comic.id == comic_id).one().__dict__
|
||||
session = Session()
|
||||
comic = session.query(Comic).filter(Comic.id == comic_id).one_or_none()
|
||||
return comic
|
||||
|
||||
|
||||
def db_get_thumbnail_by_id_page(comic_id, pageNumber):
|
||||
thumbnail = session.query(ComicThumbnail).filter(ComicThumbnail.comic_id == comic_id, ComicThumbnail.pageNumber == pageNumber).one().__dict__
|
||||
session = Session()
|
||||
thumbnail = session.query(ComicThumbnail).filter(ComicThumbnail.comic_id == comic_id, ComicThumbnail.pageNumber == pageNumber).one_or_none()
|
||||
return thumbnail
|
||||
|
||||
|
||||
def db_get_comic(publisher, series, series_year, issue):
|
||||
comic = session.query(Comic).filter(Comic.publisher == publisher, Comic.series == series, Comic.seriesYear == series_year, Comic.issue == issue).one().__dict__
|
||||
session = Session()
|
||||
comic = session.query(Comic).filter(Comic.publisher == publisher, Comic.series == series, Comic.seriesYear == series_year, Comic.issue == issue).one_or_none()
|
||||
return comic
|
||||
|
||||
|
||||
def comic_path_in_db(path):
|
||||
try:
|
||||
session = Session()
|
||||
result = session.query(Comic).filter(Comic.path == path).one_or_none()
|
||||
if result:
|
||||
return True
|
||||
except Exception as e:
|
||||
# print(path)
|
||||
current_app.logger.info(path)
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
return False
|
||||
|
||||
|
||||
def movie_path_in_db(path):
|
||||
try:
|
||||
session = Session()
|
||||
result = session.query(Movie).filter(Movie.path == path).one_or_none()
|
||||
if result:
|
||||
return True
|
||||
except Exception as e:
|
||||
# print(path)
|
||||
current_app.logger.info(path)
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
return False
|
||||
|
||||
|
||||
def tv_show_path_in_db(path):
|
||||
try:
|
||||
session = Session()
|
||||
result = session.query(TvShow).filter(TvShow.path == path).one_or_none()
|
||||
if result:
|
||||
return True
|
||||
except Exception as e:
|
||||
# print(path)
|
||||
current_app.logger.info(path)
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
return False
|
||||
|
||||
|
||||
def tv_episode_path_in_db(path):
|
||||
try:
|
||||
session = Session()
|
||||
result = session.query(TvEpisode).filter(TvEpisode.path == path).one_or_none()
|
||||
if result:
|
||||
return True
|
||||
except Exception as e:
|
||||
# print(path)
|
||||
current_app.logger.info(path)
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
return False
|
||||
|
||||
|
||||
@ -603,32 +619,53 @@ def tmdb_get_tv_episode_by_imdb_id(imdb_id):
|
||||
|
||||
|
||||
def db_get_all_movies():
|
||||
session = Session()
|
||||
movies = session.query(Movie).order_by(Movie.title, Movie.year).all()
|
||||
return movies
|
||||
|
||||
|
||||
def db_get_movie_by_imdb_id(imdb_id, extended=False, directors_cut=False):
|
||||
session = Session()
|
||||
result = session.query(Movie).filter(Movie.imdb_id == imdb_id, Movie.extended == extended,
|
||||
Movie.directors_cut == directors_cut).one()
|
||||
Movie.directors_cut == directors_cut).one_or_none()
|
||||
return result
|
||||
|
||||
|
||||
def get_all_tv_shows():
|
||||
session = Session()
|
||||
result = session.query(TvShow).order_by(TvShow.title, TvShow.year).all()
|
||||
return result
|
||||
|
||||
|
||||
def get_tv_show_episodes_by_imdb_id(imdb_id):
|
||||
session = Session()
|
||||
result = session.query(TvEpisode).filter(TvEpisode.parent_imdb_id == imdb_id).order_by(TvEpisode.season, TvEpisode.episode).all()
|
||||
return result
|
||||
|
||||
|
||||
def db_get_episode_by_imdb_id(imdb_id):
|
||||
result = session.query(TvEpisode).filter(TvEpisode.imdb_id == imdb_id).one()
|
||||
session = Session()
|
||||
result = session.query(TvEpisode).filter(TvEpisode.imdb_id == imdb_id).one_or_none()
|
||||
return result
|
||||
|
||||
|
||||
def db_get_user_tv_movie_data(imdb_id):
|
||||
session = Session()
|
||||
email = current_user.email
|
||||
result = session.query(UserTvMovieData).filter(UserTvMovieData.user == email, UserTvMovieData.imdb_id == imdb_id).one_or_none()
|
||||
return result
|
||||
|
||||
|
||||
def db_get_user_tv_show_episodes_data(parent_imdb_id) -> list:
|
||||
session = Session()
|
||||
email = current_user.email
|
||||
result = session.query(UserTvMovieData).filter(UserTvMovieData.user == email,
|
||||
UserTvMovieData.parent_imdb_id == parent_imdb_id).all()
|
||||
return result
|
||||
|
||||
|
||||
def db_search_table_columns_by_query(query, table, columns, group=[], order=[]):
|
||||
session = Session()
|
||||
results = {}
|
||||
final_query = "%" + query.replace(" ", "%") + "%"
|
||||
for column in columns:
|
||||
@ -644,22 +681,18 @@ def db_search_comics(query):
|
||||
results = db_search_table_columns_by_query(query, Comic, [Comic.publisher, Comic.title, Comic.series, Comic.year])
|
||||
series_results = db_search_table_columns_by_query(query, Comic, [Comic.publisher, Comic.title, Comic.series, Comic.year],
|
||||
group=[Comic.series, Comic.seriesYear], order=[Comic.issue])
|
||||
|
||||
for row in results["publisher"]:
|
||||
if row["publisher"] not in publishers:
|
||||
publishers.append(row.publisher)
|
||||
for row in series_results["series"]:
|
||||
dict = row.__dict__
|
||||
if dict not in series:
|
||||
series.append(dict)
|
||||
if row not in series:
|
||||
series.append(row)
|
||||
for row in results["title"]:
|
||||
dict = row.__dict__
|
||||
if dict not in comics:
|
||||
comics.append(dict)
|
||||
if row not in comics:
|
||||
comics.append(row)
|
||||
for row in results["year"]:
|
||||
dict = row.__dict__
|
||||
if dict not in comics:
|
||||
comics.append(dict)
|
||||
if row not in comics:
|
||||
comics.append(row)
|
||||
|
||||
return {"publisher": publishers, "series": series, "comics": comics}
|
||||
|
||||
@ -668,14 +701,14 @@ def db_search_movies(query):
|
||||
results = db_search_table_columns_by_query(query, Movie, [Movie.title, Movie.year, Movie.description], order=[Movie.title])
|
||||
movies = []
|
||||
for movie in results["title"]:
|
||||
if movie.__dict__ not in movies:
|
||||
movies.append(movie.__dict__)
|
||||
if movie not in movies:
|
||||
movies.append(movie)
|
||||
for movie in results["description"]:
|
||||
if movie.__dict__ not in movies:
|
||||
movies.append(movie.__dict__)
|
||||
if movie not in movies:
|
||||
movies.append(movie)
|
||||
for movie in results["year"]:
|
||||
if movie.__dict__ not in movies:
|
||||
movies.append(movie.__dict__)
|
||||
if movie not in movies:
|
||||
movies.append(movie)
|
||||
return movies
|
||||
|
||||
|
||||
@ -683,14 +716,14 @@ def db_search_tv_shows(query):
|
||||
results = db_search_table_columns_by_query(query, TvShow, [TvShow.title, TvShow.year, TvShow.description], order=[TvShow.title])
|
||||
tv_shows = []
|
||||
for show in results["title"]:
|
||||
if show.__dict__ not in tv_shows:
|
||||
tv_shows.append(show.__dict__)
|
||||
if show not in tv_shows:
|
||||
tv_shows.append(show)
|
||||
for show in results["description"]:
|
||||
if show.__dict__ not in tv_shows:
|
||||
tv_shows.append(show.__dict__)
|
||||
if show not in tv_shows:
|
||||
tv_shows.append(show)
|
||||
for show in results["year"]:
|
||||
if show.__dict__ not in tv_shows:
|
||||
tv_shows.append(show.__dict__)
|
||||
if show not in tv_shows:
|
||||
tv_shows.append(show)
|
||||
return tv_shows
|
||||
|
||||
|
||||
@ -725,8 +758,12 @@ def fix_thumbnails():
|
||||
print("Finished fix thumbnail size")
|
||||
|
||||
|
||||
def get_user(username):
|
||||
result = session.query(User).filter(User.username == username).one()
|
||||
if result:
|
||||
return result
|
||||
return None
|
||||
def get_user(email):
|
||||
try:
|
||||
session = Session()
|
||||
result = session.query(User).filter(User.email == email).one_or_none()
|
||||
if result:
|
||||
return result
|
||||
return None
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
|
@ -3,7 +3,7 @@ from wand.image import Image
|
||||
import sqlite3, os
|
||||
|
||||
|
||||
RPI_DATABASE = "/var/lib/rpiWebApp/database.db"
|
||||
RPI_DATABASE = "/usb/storage/rpiWebApp/database.db"
|
||||
|
||||
MC_DATABASE = "***REMOVED***"
|
||||
|
||||
|
109
scripts/func.py
@ -1,4 +1,5 @@
|
||||
from flask import current_app
|
||||
from flask import g
|
||||
from comicapi import comicarchive
|
||||
from blinker import Namespace
|
||||
|
||||
@ -54,18 +55,20 @@ def get_comics():
|
||||
test_path = path.encode("utf8")
|
||||
except Exception as e:
|
||||
current_app.logger.info("encoding failed on: "+path)
|
||||
# print("encoding failed on:", path)
|
||||
continue
|
||||
archive = open_comic(path)
|
||||
md = archive.readCIX()
|
||||
if md.publisher in publishers_to_ignore:
|
||||
continue
|
||||
current_app.logger.info(path)
|
||||
# print(path)
|
||||
meta.append((path, md))
|
||||
thumbnails.append(get_comic_thumbnails(archive))
|
||||
comics_added += 1
|
||||
i += 1
|
||||
try:
|
||||
meta.append((path, md))
|
||||
thumbnails.append(get_comic_thumbnails(archive))
|
||||
comics_added += 1
|
||||
i += 1
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
continue
|
||||
if i >= 2:
|
||||
comic_loaded.send("anonymous", meta=meta.copy(), thumbnails=thumbnails.copy())
|
||||
meta.clear()
|
||||
@ -75,9 +78,6 @@ def get_comics():
|
||||
current_app.logger.info("total number of comics: "+str(total_comics))
|
||||
current_app.logger.info("comics in database: "+str(comics_in_db))
|
||||
current_app.logger.info("number of comics added: "+str(comics_added))
|
||||
# print("total number of comics:", total_comics)
|
||||
# print("comics in database:", comics_in_db)
|
||||
# print("number of comics added:", comics_added)
|
||||
comic_loaded.send("anonymous", meta=meta, thumbnails=thumbnails)
|
||||
|
||||
|
||||
@ -90,16 +90,18 @@ def get_comic(path):
|
||||
test_path = path.encode("utf8")
|
||||
except Exception as e:
|
||||
current_app.logger.info("encoding failed on: "+path)
|
||||
# print("encoding failed on:", path)
|
||||
return
|
||||
archive = open_comic(path)
|
||||
md = archive.readCIX()
|
||||
if md.publisher in publishers_to_ignore:
|
||||
return
|
||||
current_app.logger.info(path)
|
||||
# print(path)
|
||||
meta.append((path, md))
|
||||
thumbnails.append(get_comic_thumbnails(archive))
|
||||
try:
|
||||
thumbnails.append(get_comic_thumbnails(archive))
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
return
|
||||
comic_loaded.send("anonymous", meta=meta, thumbnails=thumbnails)
|
||||
|
||||
|
||||
@ -131,7 +133,6 @@ def open_comic(path):
|
||||
|
||||
def get_movies():
|
||||
current_app.logger.info("start load movies")
|
||||
# print("start load movies")
|
||||
pattern = r"(.+) \((....)\)(\(extended\))?( Director's Cut)?(\.mkv)"
|
||||
movies = []
|
||||
total_movies = 0
|
||||
@ -147,13 +148,10 @@ def get_movies():
|
||||
match = re.fullmatch(pattern, f)
|
||||
if not match:
|
||||
current_app.logger.info(f+" did not match regex.")
|
||||
# print(f, "did not match regex.")
|
||||
continue
|
||||
current_app.logger.info("movie path: "+path)
|
||||
# print("movie path:", path)
|
||||
title = match.group(1)
|
||||
current_app.logger.info("movie title: "+title)
|
||||
# print("movie title:", title)
|
||||
year = int(match.group(2))
|
||||
extended = False
|
||||
directors_cut = False
|
||||
@ -167,7 +165,6 @@ def get_movies():
|
||||
imdb_data = database.imdb_get_movie(title, year)
|
||||
if not imdb_data:
|
||||
current_app.logger.info("could not get imdb data for: "+title+" "+str(year))
|
||||
# print("could not get imdb data for:", title, year)
|
||||
continue
|
||||
imdb_id = imdb_data["tconst"]
|
||||
length = imdb_data["runtimeMinutes"]
|
||||
@ -175,7 +172,6 @@ def get_movies():
|
||||
tmdb_data = database.tmdb_get_movie_by_imdb_id(imdb_id)
|
||||
if not tmdb_data:
|
||||
current_app.logger.info("could not get tmdb data")
|
||||
# print("could not get tmdb data")
|
||||
continue
|
||||
tmdb_id = tmdb_data[0]
|
||||
description = tmdb_data[1]
|
||||
@ -196,10 +192,6 @@ def get_movies():
|
||||
current_app.logger.info("total movies: "+str(total_movies))
|
||||
current_app.logger.info("movies in database: "+str(movies_in_db))
|
||||
current_app.logger.info("movies added: "+str(movies_added))
|
||||
# print("finish load movies")
|
||||
# print("total movies:", total_movies)
|
||||
# print("movies in database:", movies_in_db)
|
||||
# print("movies added:", movies_added)
|
||||
|
||||
|
||||
def get_tv_shows():
|
||||
@ -221,7 +213,7 @@ def get_tv_shows():
|
||||
if not tmdb_data:
|
||||
current_app.logger.info("could not get tmdb data for:" + series_name + " " + str(series_year))
|
||||
# print("could not get tmdb data for:", series_name, series_year)
|
||||
with open("/var/lib/rpiWebApp/log.txt", "a") as f:
|
||||
with open("/usb/storage/rpiWebApp/log.txt", "a") as f:
|
||||
f.write("could not get tmdb data for: " + imdb_id + " " + series_name + " " + str(series_year)+"\n")
|
||||
continue
|
||||
tmdb_id = tmdb_data[0]
|
||||
@ -230,41 +222,42 @@ def get_tv_shows():
|
||||
tv_show_data = (imdb_id, tmdb_id, series_name, series_year, description, poster_path, path)
|
||||
tv_show_loaded.send("anonymous", tv_show=tv_show_data)
|
||||
current_app.logger.info("finished load tv shows.")
|
||||
# print("finished load tv shows.")
|
||||
|
||||
|
||||
def get_tv_episodes():
|
||||
video_pattern = r"S(..)E(..) - (.+)(.mp4|.mkv)"
|
||||
rows = database.get_all_tv_shows()
|
||||
for tv_show in rows:
|
||||
episodes = []
|
||||
for video in sorted(os.listdir(tv_show.path)):
|
||||
video_match = re.fullmatch(video_pattern, video)
|
||||
if video_match:
|
||||
path = tv_show.path + video
|
||||
if not database.tv_episode_path_in_db(path):
|
||||
season = int(video_match.group(1))
|
||||
episode = int(video_match.group(2))
|
||||
episode_name = video_match.group(3)
|
||||
episode_imdb_data = database.imdb_get_tv_episode(tv_show.imdb_id, season, episode)
|
||||
if not episode_imdb_data:
|
||||
current_app.logger.info("could not get imdb data for: "+tv_show.title+" "+str(tv_show.year)+" "+str(season)+" "+str(episode))
|
||||
print("could not get imdb data for:", tv_show.title, tv_show.year, season, episode)
|
||||
continue
|
||||
episode_imdb_id = episode_imdb_data["tconst"]
|
||||
episode_tmdb_data = database.tmdb_get_tv_episode_by_imdb_id(episode_imdb_id)
|
||||
if not episode_tmdb_data:
|
||||
current_app.logger.info("could not get tmdb data for: "+tv_show.title+" "+str(tv_show.year)+" "+str(season)+" "+str(episode))
|
||||
# print("could not get tmdb data for:", tv_show.title, tv_show.year, season, episode)
|
||||
with open("/var/lib/rpiWebApp/log.txt", "a") as f:
|
||||
f.write("could not get tmdb data for: " + episode_imdb_id + " " + tv_show.title + " " + str(
|
||||
tv_show.year) + " " + str(season) + " " + str(episode) + "\n")
|
||||
continue
|
||||
episode_tmdb_id = episode_tmdb_data[0]
|
||||
episode_description = episode_tmdb_data[1]
|
||||
episode_still_path = episode_tmdb_data[2]
|
||||
episodes.append((episode_imdb_id, tv_show.imdb_id, episode_tmdb_id, episode_name, season, episode,
|
||||
episode_description, episode_still_path, path))
|
||||
tv_episodes_loaded.send("anonymous", tv_episodes=episodes)
|
||||
current_app.logger.info("finished load tv episodes.")
|
||||
# print("finish load tv episodes.")
|
||||
try:
|
||||
video_pattern = r"S(\d+)E(\d+) - (.+)(.mp4|.mkv)"
|
||||
rows = database.get_all_tv_shows()
|
||||
for tv_show in rows:
|
||||
episodes = []
|
||||
for video in sorted(os.listdir(tv_show.path)):
|
||||
video_match = re.fullmatch(video_pattern, video)
|
||||
if video_match:
|
||||
path = tv_show.path + video
|
||||
if not database.tv_episode_path_in_db(path):
|
||||
season = int(video_match.group(1))
|
||||
episode = int(video_match.group(2))
|
||||
episode_name = video_match.group(3)
|
||||
episode_imdb_data = database.imdb_get_tv_episode(tv_show.imdb_id, season, episode)
|
||||
if not episode_imdb_data:
|
||||
current_app.logger.info("could not get imdb data for: "+tv_show.title+" "+str(tv_show.year)+" "+str(season)+" "+str(episode))
|
||||
print("could not get imdb data for:", tv_show.title, tv_show.year, season, episode)
|
||||
continue
|
||||
episode_imdb_id = episode_imdb_data["tconst"]
|
||||
episode_tmdb_data = database.tmdb_get_tv_episode_by_imdb_id(episode_imdb_id)
|
||||
if not episode_tmdb_data:
|
||||
current_app.logger.info("could not get tmdb data for: "+tv_show.title+" "+str(tv_show.year)+" "+str(season)+" "+str(episode))
|
||||
with open("/usb/storage/rpiWebApp/log.txt", "w") as f:
|
||||
f.write("could not get tmdb data for: " + episode_imdb_id + " " + tv_show.title + " " + str(
|
||||
tv_show.year) + " " + str(season) + " " + str(episode) + "\n")
|
||||
continue
|
||||
episode_tmdb_id = episode_tmdb_data[0]
|
||||
episode_description = episode_tmdb_data[1]
|
||||
episode_still_path = episode_tmdb_data[2]
|
||||
episodes.append((episode_imdb_id, tv_show.imdb_id, episode_tmdb_id, episode_name, season, episode,
|
||||
episode_description, episode_still_path, path))
|
||||
tv_episodes_loaded.send("anonymous", tv_episodes=episodes)
|
||||
current_app.logger.info("finished load tv episodes.")
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
import sqlite3, subprocess, os
|
||||
|
||||
RPI_IMDB_DATABASE = "/var/lib/rpiWebApp/"
|
||||
RPI_IMDB_DATABASE = "/usb/storage/rpiWebApp/"
|
||||
RPI_TSV_DIRECTORY = "/usb/storage/imdb-rename/"
|
||||
RPI_CSV_DIRECTORY = "/home/matt/"
|
||||
|
||||
MC_IMDB_DATABASE = "C:\\Users\\Matthew\\Documents\\MyPrograms\\Websites\\rpi_web_interface\\"
|
||||
MC_TSV_DIRECTORY = "C:\\\\Users\\\\Matthew\\\\Documents\\\\IMDB\\\\"
|
||||
MC_CSV_DIRECTORY = "C:\\\\Users\\\\Matthew\\\\Documents\\\\IMDB\\\\"
|
||||
MC_IMDB_DATABASE = "***REMOVED***"
|
||||
MC_TSV_DIRECTORY = "***REMOVED***"
|
||||
MC_CSV_DIRECTORY = "***REMOVED***"
|
||||
|
||||
|
||||
IMDB_DATABASE = RPI_IMDB_DATABASE if os.path.exists(RPI_IMDB_DATABASE) else MC_IMDB_DATABASE
|
||||
|
@ -1,9 +1,6 @@
|
||||
from flask import current_app
|
||||
import requests
|
||||
import logging
|
||||
import inspect
|
||||
logging.getLogger("requests").setLevel(logging.WARNING)
|
||||
logging.getLogger("urllib3").setLevel(logging.WARNING)
|
||||
|
||||
API_KEY = "***REMOVED***"
|
||||
TMDB_FIND_URL = "https://api.themoviedb.org/3/find/"
|
||||
@ -18,18 +15,15 @@ def get_movie_data(imdb_id):
|
||||
"language": "en-US",
|
||||
"external_source": "imdb_id"
|
||||
}
|
||||
r = requests.get(TMDB_FIND_URL+imdb_id, data=data)
|
||||
r = requests.get(TMDB_FIND_URL+imdb_id, params=data)
|
||||
info = dict(r.json())
|
||||
if "status_code" in info.keys():
|
||||
current_app.logger.info("error getting tmdb data, status code: "+str(info["status_code"]))
|
||||
# print("error getting tmdb data, status code:", info["status_code"])
|
||||
current_app.logger.info("error getting tmdb movie data, status code: "+str(info["status_code"])+" "+str(info["status_message"]))
|
||||
return None
|
||||
if info["movie_results"] == []:
|
||||
current_app.logger.info("no tmdb results for: " + str(imdb_id))
|
||||
# print("no tmdb results for:", imdb_id)
|
||||
return None
|
||||
current_app.logger.info("tmdb movie title: " + str(info["movie_results"][0]["title"]))
|
||||
# print("tmdb movie title:", info["movie_results"][0]["title"])
|
||||
movie_id = info["movie_results"][0]["id"]
|
||||
overview = info["movie_results"][0]["overview"]
|
||||
poster_path = info["movie_results"][0]["poster_path"]
|
||||
@ -38,7 +32,6 @@ def get_movie_data(imdb_id):
|
||||
return movie_id, overview, poster_path, backdrop_path
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
|
||||
|
||||
def get_tv_show_data(imdb_id):
|
||||
@ -48,18 +41,15 @@ def get_tv_show_data(imdb_id):
|
||||
"language": "en-US",
|
||||
"external_source": "imdb_id"
|
||||
}
|
||||
r = requests.get(TMDB_FIND_URL+imdb_id, data=data)
|
||||
r = requests.get(TMDB_FIND_URL+imdb_id, params=data)
|
||||
info = dict(r.json())
|
||||
if "status_code" in info.keys():
|
||||
current_app.logger.info("error getting tmdb data, status code: " + str(info["status_code"]))
|
||||
# print("error getting tmdb data, status code:", info["status_code"])
|
||||
current_app.logger.info("error getting tmdb tv show data, status code: " + str(info["status_code"])+" "+str(info["status_message"]))
|
||||
return None
|
||||
if info["tv_results"] == []:
|
||||
current_app.logger.info("no tmdb results for: " + str(imdb_id))
|
||||
# print("no tmdb results for:", imdb_id)
|
||||
return None
|
||||
current_app.logger.info("tmdb tv show title: " + str(info["tv_results"][0]["name"]))
|
||||
# print("tmdb tv show title:", info["tv_results"][0]["name"])
|
||||
tv_show_id = info["tv_results"][0]["id"]
|
||||
overview = info["tv_results"][0]["overview"]
|
||||
poster_path = info["tv_results"][0]["poster_path"]
|
||||
@ -67,7 +57,6 @@ def get_tv_show_data(imdb_id):
|
||||
return tv_show_id, overview, poster_path
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
|
||||
|
||||
def get_tv_episode_data(imdb_id):
|
||||
@ -77,18 +66,15 @@ def get_tv_episode_data(imdb_id):
|
||||
"language": "en-US",
|
||||
"external_source": "imdb_id"
|
||||
}
|
||||
r = requests.get(TMDB_FIND_URL+imdb_id, data=data)
|
||||
r = requests.get(TMDB_FIND_URL+imdb_id, params=data)
|
||||
info = dict(r.json())
|
||||
if "status_code" in info.keys():
|
||||
current_app.logger.info("error getting tmdb data, status code: " + str(info["status_code"]))
|
||||
# print("error getting tmdb data, status code:", info["status_code"])
|
||||
current_app.logger.info("error getting tmdb tv episode data, status code: " + str(info["status_code"])+" "+str(info["status_message"]))
|
||||
return None
|
||||
if info["tv_episode_results"] == []:
|
||||
current_app.logger.info("no tmdb results for: " + str(imdb_id))
|
||||
# print("no tmdb results for:", imdb_id)
|
||||
return None
|
||||
current_app.logger.info("tmdb tv_episode title: " + str(info["tv_episode_results"][0]["name"]))
|
||||
# print("tmdb tv episode title:", info["tv_episode_results"][0]["name"])
|
||||
tv_episode_id = info["tv_episode_results"][0]["id"]
|
||||
name = info["tv_episode_results"][0]["name"]
|
||||
overview = info["tv_episode_results"][0]["overview"]
|
||||
@ -97,4 +83,3 @@ def get_tv_episode_data(imdb_id):
|
||||
return tv_episode_id, overview, still_path
|
||||
except Exception as e:
|
||||
current_app.logger.info(inspect.stack()[0][3] + " " + str(type(e)) + " " + str(e))
|
||||
# print(inspect.stack()[0][3], type(e), e)
|
||||
|
BIN
static/images/Ajax-Farrell.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
static/images/Caliber Comics.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
static/images/DC.png
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
static/images/Dark Horse Manga.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
static/images/Epic.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
static/images/Fantagraphics.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
static/images/Fox Comics (US).png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
static/images/Gold Key.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
static/images/Image.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
static/images/Marvel Digital Comics Unlimited.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
static/images/Marvel Knights.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
static/images/Marvel UK.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
static/images/Panini Comics.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
static/images/Sablevision.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
static/images/Storm King Comics.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
static/images/T-Publications.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
static/images/Tangent Comics.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
static/images/Yen Press.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
static/images/btn_google_signin_dark_disabled_web.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
static/images/btn_google_signin_dark_focus_web.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
static/images/btn_google_signin_dark_normal_web.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
static/images/btn_google_signin_dark_pressed_web.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
static/images/btn_google_signin_light_disabled_web.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
static/images/btn_google_signin_light_focus_web.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
static/images/btn_google_signin_light_normal_web.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
static/images/btn_google_signin_light_pressed_web.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
12
static/video-js-7.6.0/alt/video.core.min.js
vendored
20
static/video-js-7.6.0/alt/video.novtt.min.js
vendored
@ -1,34 +0,0 @@
|
||||
videojs.addLanguage('ar', {
|
||||
"Play": "تشغيل",
|
||||
"Pause": "إيقاف",
|
||||
"Current Time": "الوقت الحالي",
|
||||
"Duration": "مدة",
|
||||
"Remaining Time": "الوقت المتبقي",
|
||||
"Stream Type": "نوع التيار",
|
||||
"LIVE": "مباشر",
|
||||
"Loaded": "تم التحميل",
|
||||
"Progress": "التقدم",
|
||||
"Fullscreen": "ملء الشاشة",
|
||||
"Non-Fullscreen": "تعطيل ملء الشاشة",
|
||||
"Mute": "صامت",
|
||||
"Unmute": "غير الصامت",
|
||||
"Playback Rate": "معدل التشغيل",
|
||||
"Subtitles": "الترجمة",
|
||||
"subtitles off": "إيقاف الترجمة",
|
||||
"Captions": "التعليقات",
|
||||
"captions off": "إيقاف التعليقات",
|
||||
"Chapters": "فصول",
|
||||
"You aborted the media playback": "لقد ألغيت تشغيل الفيديو",
|
||||
"A network error caused the media download to fail part-way.": "تسبب خطأ في الشبكة بفشل تحميل الفيديو بالكامل.",
|
||||
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "لا يمكن تحميل الفيديو بسبب فشل في الخادوم أو الشبكة ، أو فشل بسبب عدم إمكانية قراءة تنسيق الفيديو.",
|
||||
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "تم إيقاف تشغيل الفيديو بسبب مشكلة فساد أو لأن الفيديو المستخدم يستخدم ميزات غير مدعومة من متصفحك.",
|
||||
"No compatible source was found for this media.": "فشل العثور على أي مصدر متوافق مع هذا الفيديو.",
|
||||
"Play Video": "تشغيل الفيديو",
|
||||
"Close": "أغلق",
|
||||
"Modal Window": "نافذة مشروطة",
|
||||
"This is a modal window": "هذه نافذة مشروطة",
|
||||
"This modal can be closed by pressing the Escape key or activating the close button.": "يمكن غلق هذه النافذة المشروطة عن طريق الضغط على زر الخروج أو تفعيل زر الإغلاق",
|
||||
", opens captions settings dialog": ", تفتح نافذة خيارات التعليقات",
|
||||
", opens subtitles settings dialog": ", تفتح نافذة خيارات الترجمة",
|
||||
", selected": ", مختار"
|
||||
});
|
@ -1,34 +0,0 @@
|
||||
{
|
||||
"Play": "تشغيل",
|
||||
"Pause": "إيقاف",
|
||||
"Current Time": "الوقت الحالي",
|
||||
"Duration": "مدة",
|
||||
"Remaining Time": "الوقت المتبقي",
|
||||
"Stream Type": "نوع التيار",
|
||||
"LIVE": "مباشر",
|
||||
"Loaded": "تم التحميل",
|
||||
"Progress": "التقدم",
|
||||
"Fullscreen": "ملء الشاشة",
|
||||
"Non-Fullscreen": "تعطيل ملء الشاشة",
|
||||
"Mute": "صامت",
|
||||
"Unmute": "غير الصامت",
|
||||
"Playback Rate": "معدل التشغيل",
|
||||
"Subtitles": "الترجمة",
|
||||
"subtitles off": "إيقاف الترجمة",
|
||||
"Captions": "التعليقات",
|
||||
"captions off": "إيقاف التعليقات",
|
||||
"Chapters": "فصول",
|
||||
"You aborted the media playback": "لقد ألغيت تشغيل الفيديو",
|
||||
"A network error caused the media download to fail part-way.": "تسبب خطأ في الشبكة بفشل تحميل الفيديو بالكامل.",
|
||||
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "لا يمكن تحميل الفيديو بسبب فشل في الخادوم أو الشبكة ، أو فشل بسبب عدم إمكانية قراءة تنسيق الفيديو.",
|
||||
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "تم إيقاف تشغيل الفيديو بسبب مشكلة فساد أو لأن الفيديو المستخدم يستخدم ميزات غير مدعومة من متصفحك.",
|
||||
"No compatible source was found for this media.": "فشل العثور على أي مصدر متوافق مع هذا الفيديو.",
|
||||
"Play Video": "تشغيل الفيديو",
|
||||
"Close": "أغلق",
|
||||
"Modal Window": "نافذة مشروطة",
|
||||
"This is a modal window": "هذه نافذة مشروطة",
|
||||
"This modal can be closed by pressing the Escape key or activating the close button.": "يمكن غلق هذه النافذة المشروطة عن طريق الضغط على زر الخروج أو تفعيل زر الإغلاق",
|
||||
", opens captions settings dialog": ", تفتح نافذة خيارات التعليقات",
|
||||
", opens subtitles settings dialog": ", تفتح نافذة خيارات الترجمة",
|
||||
", selected": ", مختار"
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
videojs.addLanguage('es', {
|
||||
"Play": "Reproducción",
|
||||
"Play Video": "Reproducción Vídeo",
|
||||
"Pause": "Pausa",
|
||||
"Current Time": "Tiempo reproducido",
|
||||
"Duration": "Duración total",
|
||||
"Remaining Time": "Tiempo restante",
|
||||
"Stream Type": "Tipo de secuencia",
|
||||
"LIVE": "DIRECTO",
|
||||
"Loaded": "Cargado",
|
||||
"Progress": "Progreso",
|
||||
"Fullscreen": "Pantalla completa",
|
||||
"Non-Fullscreen": "Pantalla no completa",
|
||||
"Mute": "Silenciar",
|
||||
"Unmute": "No silenciado",
|
||||
"Playback Rate": "Velocidad de reproducción",
|
||||
"Subtitles": "Subtítulos",
|
||||
"subtitles off": "Subtítulos desactivados",
|
||||
"Captions": "Subtítulos especiales",
|
||||
"captions off": "Subtítulos especiales desactivados",
|
||||
"Chapters": "Capítulos",
|
||||
"You aborted the media playback": "Ha interrumpido la reproducción del vídeo.",
|
||||
"A network error caused the media download to fail part-way.": "Un error de red ha interrumpido la descarga del vídeo.",
|
||||
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "No se ha podido cargar el vídeo debido a un fallo de red o del servidor o porque el formato es incompatible.",
|
||||
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "La reproducción de vídeo se ha interrumpido por un problema de corrupción de datos o porque el vídeo precisa funciones que su navegador no ofrece.",
|
||||
"No compatible source was found for this media.": "No se ha encontrado ninguna fuente compatible con este vídeo."
|
||||
});
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"Play": "Reproducción",
|
||||
"Play Video": "Reproducción Vídeo",
|
||||
"Pause": "Pausa",
|
||||
"Current Time": "Tiempo reproducido",
|
||||
"Duration": "Duración total",
|
||||
"Remaining Time": "Tiempo restante",
|
||||
"Stream Type": "Tipo de secuencia",
|
||||
"LIVE": "DIRECTO",
|
||||
"Loaded": "Cargado",
|
||||
"Progress": "Progreso",
|
||||
"Fullscreen": "Pantalla completa",
|
||||
"Non-Fullscreen": "Pantalla no completa",
|
||||
"Mute": "Silenciar",
|
||||
"Unmute": "No silenciado",
|
||||
"Playback Rate": "Velocidad de reproducción",
|
||||
"Subtitles": "Subtítulos",
|
||||
"subtitles off": "Subtítulos desactivados",
|
||||
"Captions": "Subtítulos especiales",
|
||||
"captions off": "Subtítulos especiales desactivados",
|
||||
"Chapters": "Capítulos",
|
||||
"You aborted the media playback": "Ha interrumpido la reproducción del vídeo.",
|
||||
"A network error caused the media download to fail part-way.": "Un error de red ha interrumpido la descarga del vídeo.",
|
||||
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "No se ha podido cargar el vídeo debido a un fallo de red o del servidor o porque el formato es incompatible.",
|
||||
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "La reproducción de vídeo se ha interrumpido por un problema de corrupción de datos o porque el vídeo precisa funciones que su navegador no ofrece.",
|
||||
"No compatible source was found for this media.": "No se ha encontrado ninguna fuente compatible con este vídeo."
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
videojs.addLanguage('nb', {
|
||||
"Play": "Spill",
|
||||
"Pause": "Pause",
|
||||
"Current Time": "Aktuell tid",
|
||||
"Duration": "Varighet",
|
||||
"Remaining Time": "Gjenstående tid",
|
||||
"Stream Type": "Type strøm",
|
||||
"LIVE": "DIREKTE",
|
||||
"Loaded": "Lastet inn",
|
||||
"Progress": "Status",
|
||||
"Fullscreen": "Fullskjerm",
|
||||
"Non-Fullscreen": "Lukk fullskjerm",
|
||||
"Mute": "Lyd av",
|
||||
"Unmute": "Lyd på",
|
||||
"Playback Rate": "Avspillingsrate",
|
||||
"Subtitles": "Undertekst på",
|
||||
"subtitles off": "Undertekst av",
|
||||
"Captions": "Undertekst for hørselshemmede på",
|
||||
"captions off": "Undertekst for hørselshemmede av",
|
||||
"Chapters": "Kapitler",
|
||||
"You aborted the media playback": "Du avbrøt avspillingen.",
|
||||
"A network error caused the media download to fail part-way.": "En nettverksfeil avbrøt nedlasting av videoen.",
|
||||
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "Videoen kunne ikke lastes ned, på grunn av nettverksfeil eller serverfeil, eller fordi formatet ikke er støttet.",
|
||||
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "Videoavspillingen ble avbrudt på grunn av ødelagte data eller fordi videoen ville gjøre noe som nettleseren din ikke har støtte for.",
|
||||
"No compatible source was found for this media.": "Fant ikke en kompatibel kilde for dette mediainnholdet."
|
||||
});
|
@ -1,26 +0,0 @@
|
||||
{
|
||||
"Play": "Spill",
|
||||
"Pause": "Pause",
|
||||
"Current Time": "Aktuell tid",
|
||||
"Duration": "Varighet",
|
||||
"Remaining Time": "Gjenstående tid",
|
||||
"Stream Type": "Type strøm",
|
||||
"LIVE": "DIREKTE",
|
||||
"Loaded": "Lastet inn",
|
||||
"Progress": "Status",
|
||||
"Fullscreen": "Fullskjerm",
|
||||
"Non-Fullscreen": "Lukk fullskjerm",
|
||||
"Mute": "Lyd av",
|
||||
"Unmute": "Lyd på",
|
||||
"Playback Rate": "Avspillingsrate",
|
||||
"Subtitles": "Undertekst på",
|
||||
"subtitles off": "Undertekst av",
|
||||
"Captions": "Undertekst for hørselshemmede på",
|
||||
"captions off": "Undertekst for hørselshemmede av",
|
||||
"Chapters": "Kapitler",
|
||||
"You aborted the media playback": "Du avbrøt avspillingen.",
|
||||
"A network error caused the media download to fail part-way.": "En nettverksfeil avbrøt nedlasting av videoen.",
|
||||
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "Videoen kunne ikke lastes ned, på grunn av nettverksfeil eller serverfeil, eller fordi formatet ikke er støttet.",
|
||||
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "Videoavspillingen ble avbrudt på grunn av ødelagte data eller fordi videoen ville gjøre noe som nettleseren din ikke har støtte for.",
|
||||
"No compatible source was found for this media.": "Fant ikke en kompatibel kilde for dette mediainnholdet."
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
videojs.addLanguage('nn', {
|
||||
"Play": "Spel",
|
||||
"Pause": "Pause",
|
||||
"Current Time": "Aktuell tid",
|
||||
"Duration": "Varigheit",
|
||||
"Remaining Time": "Tid attende",
|
||||
"Stream Type": "Type straum",
|
||||
"LIVE": "DIREKTE",
|
||||
"Loaded": "Lasta inn",
|
||||
"Progress": "Status",
|
||||
"Fullscreen": "Fullskjerm",
|
||||
"Non-Fullscreen": "Stenga fullskjerm",
|
||||
"Mute": "Ljod av",
|
||||
"Unmute": "Ljod på",
|
||||
"Playback Rate": "Avspelingsrate",
|
||||
"Subtitles": "Teksting på",
|
||||
"subtitles off": "Teksting av",
|
||||
"Captions": "Teksting for høyrselshemma på",
|
||||
"captions off": "Teksting for høyrselshemma av",
|
||||
"Chapters": "Kapitel",
|
||||
"You aborted the media playback": "Du avbraut avspelinga.",
|
||||
"A network error caused the media download to fail part-way.": "Ein nettverksfeil avbraut nedlasting av videoen.",
|
||||
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "Videoen kunne ikkje lastas ned, på grunn av ein nettverksfeil eller serverfeil, eller av di formatet ikkje er stoda.",
|
||||
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "Videoavspelinga blei broten på grunn av øydelagde data eller av di videoen ville gjera noe som nettlesaren din ikkje stodar.",
|
||||
"No compatible source was found for this media.": "Fant ikke en kompatibel kilde for dette mediainnholdet."
|
||||
});
|
@ -1,26 +0,0 @@
|
||||
{
|
||||
"Play": "Spel",
|
||||
"Pause": "Pause",
|
||||
"Current Time": "Aktuell tid",
|
||||
"Duration": "Varigheit",
|
||||
"Remaining Time": "Tid attende",
|
||||
"Stream Type": "Type straum",
|
||||
"LIVE": "DIREKTE",
|
||||
"Loaded": "Lasta inn",
|
||||
"Progress": "Status",
|
||||
"Fullscreen": "Fullskjerm",
|
||||
"Non-Fullscreen": "Stenga fullskjerm",
|
||||
"Mute": "Ljod av",
|
||||
"Unmute": "Ljod på",
|
||||
"Playback Rate": "Avspelingsrate",
|
||||
"Subtitles": "Teksting på",
|
||||
"subtitles off": "Teksting av",
|
||||
"Captions": "Teksting for høyrselshemma på",
|
||||
"captions off": "Teksting for høyrselshemma av",
|
||||
"Chapters": "Kapitel",
|
||||
"You aborted the media playback": "Du avbraut avspelinga.",
|
||||
"A network error caused the media download to fail part-way.": "Ein nettverksfeil avbraut nedlasting av videoen.",
|
||||
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "Videoen kunne ikkje lastas ned, på grunn av ein nettverksfeil eller serverfeil, eller av di formatet ikkje er stoda.",
|
||||
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "Videoavspelinga blei broten på grunn av øydelagde data eller av di videoen ville gjera noe som nettlesaren din ikkje stodar.",
|
||||
"No compatible source was found for this media.": "Fant ikke en kompatibel kilde for dette mediainnholdet."
|
||||
}
|
1
static/video-js-7.6.0/video-js.min.css
vendored
20
static/video-js-7.6.0/video.min.js
vendored
@ -664,7 +664,7 @@ body.vjs-full-window {
|
||||
max-height: 25em;
|
||||
}
|
||||
|
||||
.vjs-workinghover .vjs-menu-button-popup:hover .vjs-menu,
|
||||
.vjs-workinghover .vjs-menu-button-popup.vjs-hover .vjs-menu,
|
||||
.vjs-menu-button-popup .vjs-menu.vjs-lock-showing {
|
||||
display: block;
|
||||
}
|
||||
@ -996,21 +996,23 @@ body.vjs-full-window {
|
||||
.video-js .vjs-volume-panel {
|
||||
transition: width 1s;
|
||||
}
|
||||
.video-js .vjs-volume-panel:hover .vjs-volume-control, .video-js .vjs-volume-panel:active .vjs-volume-control, .video-js .vjs-volume-panel:focus .vjs-volume-control, .video-js .vjs-volume-panel .vjs-volume-control:hover, .video-js .vjs-volume-panel .vjs-volume-control:active, .video-js .vjs-volume-panel .vjs-mute-control:hover ~ .vjs-volume-control, .video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active {
|
||||
.video-js .vjs-volume-panel.vjs-hover .vjs-volume-control, .video-js .vjs-volume-panel:active .vjs-volume-control, .video-js .vjs-volume-panel:focus .vjs-volume-control, .video-js .vjs-volume-panel .vjs-volume-control:active, .video-js .vjs-volume-panel.vjs-hover .vjs-mute-control ~ .vjs-volume-control, .video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
position: relative;
|
||||
transition: visibility 0.1s, opacity 0.1s, height 0.1s, width 0.1s, left 0s, top 0s;
|
||||
}
|
||||
.video-js .vjs-volume-panel:hover .vjs-volume-control.vjs-volume-horizontal, .video-js .vjs-volume-panel:active .vjs-volume-control.vjs-volume-horizontal, .video-js .vjs-volume-panel:focus .vjs-volume-control.vjs-volume-horizontal, .video-js .vjs-volume-panel .vjs-volume-control:hover.vjs-volume-horizontal, .video-js .vjs-volume-panel .vjs-volume-control:active.vjs-volume-horizontal, .video-js .vjs-volume-panel .vjs-mute-control:hover ~ .vjs-volume-control.vjs-volume-horizontal, .video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active.vjs-volume-horizontal {
|
||||
.video-js .vjs-volume-panel.vjs-hover .vjs-volume-control.vjs-volume-horizontal, .video-js .vjs-volume-panel:active .vjs-volume-control.vjs-volume-horizontal, .video-js .vjs-volume-panel:focus .vjs-volume-control.vjs-volume-horizontal, .video-js .vjs-volume-panel .vjs-volume-control:active.vjs-volume-horizontal, .video-js .vjs-volume-panel.vjs-hover .vjs-mute-control ~ .vjs-volume-control.vjs-volume-horizontal, .video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active.vjs-volume-horizontal {
|
||||
width: 5em;
|
||||
height: 3em;
|
||||
margin-right: 0;
|
||||
}
|
||||
.video-js .vjs-volume-panel:hover .vjs-volume-control.vjs-volume-vertical, .video-js .vjs-volume-panel:active .vjs-volume-control.vjs-volume-vertical, .video-js .vjs-volume-panel:focus .vjs-volume-control.vjs-volume-vertical, .video-js .vjs-volume-panel .vjs-volume-control:hover.vjs-volume-vertical, .video-js .vjs-volume-panel .vjs-volume-control:active.vjs-volume-vertical, .video-js .vjs-volume-panel .vjs-mute-control:hover ~ .vjs-volume-control.vjs-volume-vertical, .video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active.vjs-volume-vertical {
|
||||
.video-js .vjs-volume-panel.vjs-hover .vjs-volume-control.vjs-volume-vertical, .video-js .vjs-volume-panel:active .vjs-volume-control.vjs-volume-vertical, .video-js .vjs-volume-panel:focus .vjs-volume-control.vjs-volume-vertical, .video-js .vjs-volume-panel .vjs-volume-control:active.vjs-volume-vertical, .video-js .vjs-volume-panel.vjs-hover .vjs-mute-control ~ .vjs-volume-control.vjs-volume-vertical, .video-js .vjs-volume-panel .vjs-volume-control.vjs-slider-active.vjs-volume-vertical {
|
||||
left: -3.5em;
|
||||
transition: left 0s;
|
||||
}
|
||||
.video-js .vjs-volume-panel.vjs-volume-panel-horizontal:hover, .video-js .vjs-volume-panel.vjs-volume-panel-horizontal:active, .video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active {
|
||||
width: 9em;
|
||||
.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-hover, .video-js .vjs-volume-panel.vjs-volume-panel-horizontal:active, .video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active {
|
||||
width: 10em;
|
||||
transition: width 0.1s;
|
||||
}
|
||||
.video-js .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-mute-toggle-only {
|
1
static/video-js-7.7.5/alt/video-js-cdn.min.css
vendored
Normal file
19
static/video-js-7.7.5/alt/video.core.min.js
vendored
Normal file
19
static/video-js-7.7.5/alt/video.core.novtt.min.js
vendored
Normal file
28
static/video-js-7.7.5/alt/video.novtt.min.js
vendored
Normal file
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
86
static/video-js-7.7.5/lang/ar.js
Normal file
@ -0,0 +1,86 @@
|
||||
videojs.addLanguage('ar', {
|
||||
"Play": "تشغيل",
|
||||
"Pause": "إيقاف",
|
||||
"Current Time": "الوقت الحالي",
|
||||
"Duration": "مدة",
|
||||
"Remaining Time": "الوقت المتبقي",
|
||||
"Stream Type": "نوع التيار",
|
||||
"LIVE": "مباشر",
|
||||
"Loaded": "تم التحميل",
|
||||
"Progress": "التقدم",
|
||||
"Fullscreen": "ملء الشاشة",
|
||||
"Non-Fullscreen": "تعطيل ملء الشاشة",
|
||||
"Mute": "صامت",
|
||||
"Unmute": "غير الصامت",
|
||||
"Playback Rate": "معدل التشغيل",
|
||||
"Subtitles": "الترجمة",
|
||||
"subtitles off": "إيقاف الترجمة",
|
||||
"Captions": "التعليقات",
|
||||
"captions off": "إيقاف التعليقات",
|
||||
"Chapters": "فصول",
|
||||
"You aborted the media playback": "لقد ألغيت تشغيل الفيديو",
|
||||
"A network error caused the media download to fail part-way.": "تسبب خطأ في الشبكة بفشل تحميل الفيديو بالكامل.",
|
||||
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "لا يمكن تحميل الفيديو بسبب فشل في الخادوم أو الشبكة ، أو فشل بسبب عدم إمكانية قراءة تنسيق الفيديو.",
|
||||
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "تم إيقاف تشغيل الفيديو بسبب مشكلة فساد أو لأن الفيديو المستخدم يستخدم ميزات غير مدعومة من متصفحك.",
|
||||
"No compatible source was found for this media.": "فشل العثور على أي مصدر متوافق مع هذا الفيديو.",
|
||||
"Play Video": "تشغيل الفيديو",
|
||||
"Close": "أغلق",
|
||||
"Modal Window": "نافذة مشروطة",
|
||||
"This is a modal window": "هذه نافذة مشروطة",
|
||||
"This modal can be closed by pressing the Escape key or activating the close button.": "يمكن غلق هذه النافذة المشروطة عن طريق الضغط على زر الخروج أو تفعيل زر الإغلاق",
|
||||
", opens captions settings dialog": ", تفتح نافذة خيارات التعليقات",
|
||||
", opens subtitles settings dialog": ", تفتح نافذة خيارات الترجمة",
|
||||
", selected": ", مختار",
|
||||
"Audio Player": "مشغل الصوت",
|
||||
"Video Player": "مشغل الفيديو",
|
||||
"Replay": "إعادة التشغيل",
|
||||
"Seek to live, currently behind live": "ذهاب إلى نقطة البث المباشر، متأخر عن البث المباشر حاليًا",
|
||||
"Seek to live, currently playing live": "ذهاب إلى نقطة البث المباشر، البث المباشر قيد التشغيل حاليًا",
|
||||
"Progress Bar": "شريط التقدم",
|
||||
"Descriptions": "الأوصاف",
|
||||
"descriptions off": "إخفاء الأوصاف",
|
||||
"Audio Track": "المسار الصوتي",
|
||||
"Volume Level": "مستوى الصوت",
|
||||
"The media is encrypted and we do not have the keys to decrypt it.": "الوسائط مشفرة وليس لدينا الرموز اللازمة لفك شفرتها.",
|
||||
"Close Modal Dialog": "إغلاق مربع الحوار المشروط",
|
||||
", opens descriptions settings dialog": "، يفتح مربع حوار إعدادات الأوصاف",
|
||||
"captions settings": "إعدادات التعليقات التوضيحية",
|
||||
"subtitles settings": "إعدادات الترجمات",
|
||||
"descriptions settings": "إعدادات الأوصاف",
|
||||
"Text": "النص",
|
||||
"White": "أبيض",
|
||||
"Black": "أسود",
|
||||
"Red": "أحمر",
|
||||
"Green": "أخضر",
|
||||
"Blue": "أزرق",
|
||||
"Yellow": "أصفر",
|
||||
"Magenta": "أرجواني",
|
||||
"Cyan": "أزرق سماوي",
|
||||
"Background": "الخلفية",
|
||||
"Window": "نافذة",
|
||||
"Transparent": "شفاف",
|
||||
"Semi-Transparent": "نصف شفاف",
|
||||
"Opaque": "معتم",
|
||||
"Font Size": "حجم الخط",
|
||||
"Text Edge Style": "نمط حواف النص",
|
||||
"None": "لا شيء",
|
||||
"Raised": "بارز",
|
||||
"Depressed": "منخفض",
|
||||
"Uniform": "منتظم",
|
||||
"Dropshadow": "ظل خلفي",
|
||||
"Font Family": "عائلة الخطوط",
|
||||
"Proportional Sans-Serif": "Proportional Sans-Serif",
|
||||
"Monospace Sans-Serif": "Monospace Sans-Serif",
|
||||
"Proportional Serif": "Proportional Serif",
|
||||
"Monospace Serif": "Monospace Serif",
|
||||
"Casual": "Casual",
|
||||
"Script": "Script",
|
||||
"Small Caps": "Small Caps",
|
||||
"Reset": "إعادة الضبط",
|
||||
"restore all settings to the default values": "استعادة كل الإعدادات إلى القيم الافتراضية",
|
||||
"Done": "تم",
|
||||
"Caption Settings Dialog": "مربع حوار إعدادات التعليقات التوضيحية",
|
||||
"Beginning of dialog window. Escape will cancel and close the window.": "بداية نافذة مربع حوار. الضغط على زر \"Escape\" سيؤدي إلى الإلغاء وإغلاق النافذة.",
|
||||
"End of dialog window.": "نهاية نافذة مربع حوار.",
|
||||
"{1} is loading.": "{1} قيد التحميل."
|
||||
});
|
86
static/video-js-7.7.5/lang/ar.json
Normal file
@ -0,0 +1,86 @@
|
||||
{
|
||||
"Play": "تشغيل",
|
||||
"Pause": "إيقاف",
|
||||
"Current Time": "الوقت الحالي",
|
||||
"Duration": "مدة",
|
||||
"Remaining Time": "الوقت المتبقي",
|
||||
"Stream Type": "نوع التيار",
|
||||
"LIVE": "مباشر",
|
||||
"Loaded": "تم التحميل",
|
||||
"Progress": "التقدم",
|
||||
"Fullscreen": "ملء الشاشة",
|
||||
"Non-Fullscreen": "تعطيل ملء الشاشة",
|
||||
"Mute": "صامت",
|
||||
"Unmute": "غير الصامت",
|
||||
"Playback Rate": "معدل التشغيل",
|
||||
"Subtitles": "الترجمة",
|
||||
"subtitles off": "إيقاف الترجمة",
|
||||
"Captions": "التعليقات",
|
||||
"captions off": "إيقاف التعليقات",
|
||||
"Chapters": "فصول",
|
||||
"You aborted the media playback": "لقد ألغيت تشغيل الفيديو",
|
||||
"A network error caused the media download to fail part-way.": "تسبب خطأ في الشبكة بفشل تحميل الفيديو بالكامل.",
|
||||
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "لا يمكن تحميل الفيديو بسبب فشل في الخادوم أو الشبكة ، أو فشل بسبب عدم إمكانية قراءة تنسيق الفيديو.",
|
||||
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "تم إيقاف تشغيل الفيديو بسبب مشكلة فساد أو لأن الفيديو المستخدم يستخدم ميزات غير مدعومة من متصفحك.",
|
||||
"No compatible source was found for this media.": "فشل العثور على أي مصدر متوافق مع هذا الفيديو.",
|
||||
"Play Video": "تشغيل الفيديو",
|
||||
"Close": "أغلق",
|
||||
"Modal Window": "نافذة مشروطة",
|
||||
"This is a modal window": "هذه نافذة مشروطة",
|
||||
"This modal can be closed by pressing the Escape key or activating the close button.": "يمكن غلق هذه النافذة المشروطة عن طريق الضغط على زر الخروج أو تفعيل زر الإغلاق",
|
||||
", opens captions settings dialog": ", تفتح نافذة خيارات التعليقات",
|
||||
", opens subtitles settings dialog": ", تفتح نافذة خيارات الترجمة",
|
||||
", selected": ", مختار",
|
||||
"Audio Player": "مشغل الصوت",
|
||||
"Video Player": "مشغل الفيديو",
|
||||
"Replay": "إعادة التشغيل",
|
||||
"Seek to live, currently behind live": "ذهاب إلى نقطة البث المباشر، متأخر عن البث المباشر حاليًا",
|
||||
"Seek to live, currently playing live": "ذهاب إلى نقطة البث المباشر، البث المباشر قيد التشغيل حاليًا",
|
||||
"Progress Bar": "شريط التقدم",
|
||||
"Descriptions": "الأوصاف",
|
||||
"descriptions off": "إخفاء الأوصاف",
|
||||
"Audio Track": "المسار الصوتي",
|
||||
"Volume Level": "مستوى الصوت",
|
||||
"The media is encrypted and we do not have the keys to decrypt it.": "الوسائط مشفرة وليس لدينا الرموز اللازمة لفك شفرتها.",
|
||||
"Close Modal Dialog": "إغلاق مربع الحوار المشروط",
|
||||
", opens descriptions settings dialog": "، يفتح مربع حوار إعدادات الأوصاف",
|
||||
"captions settings": "إعدادات التعليقات التوضيحية",
|
||||
"subtitles settings": "إعدادات الترجمات",
|
||||
"descriptions settings": "إعدادات الأوصاف",
|
||||
"Text": "النص",
|
||||
"White": "أبيض",
|
||||
"Black": "أسود",
|
||||
"Red": "أحمر",
|
||||
"Green": "أخضر",
|
||||
"Blue": "أزرق",
|
||||
"Yellow": "أصفر",
|
||||
"Magenta": "أرجواني",
|
||||
"Cyan": "أزرق سماوي",
|
||||
"Background": "الخلفية",
|
||||
"Window": "نافذة",
|
||||
"Transparent": "شفاف",
|
||||
"Semi-Transparent": "نصف شفاف",
|
||||
"Opaque": "معتم",
|
||||
"Font Size": "حجم الخط",
|
||||
"Text Edge Style": "نمط حواف النص",
|
||||
"None": "لا شيء",
|
||||
"Raised": "بارز",
|
||||
"Depressed": "منخفض",
|
||||
"Uniform": "منتظم",
|
||||
"Dropshadow": "ظل خلفي",
|
||||
"Font Family": "عائلة الخطوط",
|
||||
"Proportional Sans-Serif": "Proportional Sans-Serif",
|
||||
"Monospace Sans-Serif": "Monospace Sans-Serif",
|
||||
"Proportional Serif": "Proportional Serif",
|
||||
"Monospace Serif": "Monospace Serif",
|
||||
"Casual": "Casual",
|
||||
"Script": "Script",
|
||||
"Small Caps": "Small Caps",
|
||||
"Reset": "إعادة الضبط",
|
||||
"restore all settings to the default values": "استعادة كل الإعدادات إلى القيم الافتراضية",
|
||||
"Done": "تم",
|
||||
"Caption Settings Dialog": "مربع حوار إعدادات التعليقات التوضيحية",
|
||||
"Beginning of dialog window. Escape will cancel and close the window.": "بداية نافذة مربع حوار. الضغط على زر \"Escape\" سيؤدي إلى الإلغاء وإغلاق النافذة.",
|
||||
"End of dialog window.": "نهاية نافذة مربع حوار.",
|
||||
"{1} is loading.": "{1} قيد التحميل."
|
||||
}
|
@ -62,13 +62,13 @@ videojs.addLanguage('de', {
|
||||
"Depressed": "Gedrückt",
|
||||
"Uniform": "Uniform",
|
||||
"Dropshadow": "Schlagschatten",
|
||||
"Font Family": "Schristfamilie",
|
||||
"Font Family": "Schriftfamilie",
|
||||
"Proportional Sans-Serif": "Proportionale Sans-Serif",
|
||||
"Monospace Sans-Serif": "Monospace Sans-Serif",
|
||||
"Proportional Serif": "Proportionale Serif",
|
||||
"Monospace Serif": "Monospace Serif",
|
||||
"Casual": "Zwanglos",
|
||||
"Script": "Schreibeschrift",
|
||||
"Script": "Schreibschrift",
|
||||
"Small Caps": "Small-Caps",
|
||||
"Reset": "Zurücksetzen",
|
||||
"restore all settings to the default values": "Alle Einstellungen auf die Standardwerte zurücksetzen",
|
||||
@ -80,7 +80,7 @@ videojs.addLanguage('de', {
|
||||
"Video Player": "Video-Player",
|
||||
"Progress Bar": "Forschrittsbalken",
|
||||
"progress bar timing: currentTime={1} duration={2}": "{1} von {2}",
|
||||
"Volume Level": "Lautstärkestufe",
|
||||
"Volume Level": "Lautstärke",
|
||||
"{1} is loading.": "{1} wird geladen.",
|
||||
"Seek to live, currently behind live": "Zur Live-Übertragung wechseln. Aktuell wird es nicht live abgespielt.",
|
||||
"Seek to live, currently playing live": "Zur Live-Übertragung wechseln. Es wird aktuell live abgespielt."
|
@ -62,13 +62,13 @@
|
||||
"Depressed": "Gedrückt",
|
||||
"Uniform": "Uniform",
|
||||
"Dropshadow": "Schlagschatten",
|
||||
"Font Family": "Schristfamilie",
|
||||
"Font Family": "Schriftfamilie",
|
||||
"Proportional Sans-Serif": "Proportionale Sans-Serif",
|
||||
"Monospace Sans-Serif": "Monospace Sans-Serif",
|
||||
"Proportional Serif": "Proportionale Serif",
|
||||
"Monospace Serif": "Monospace Serif",
|
||||
"Casual": "Zwanglos",
|
||||
"Script": "Schreibeschrift",
|
||||
"Script": "Schreibschrift",
|
||||
"Small Caps": "Small-Caps",
|
||||
"Reset": "Zurücksetzen",
|
||||
"restore all settings to the default values": "Alle Einstellungen auf die Standardwerte zurücksetzen",
|
||||
@ -80,7 +80,7 @@
|
||||
"Video Player": "Video-Player",
|
||||
"Progress Bar": "Forschrittsbalken",
|
||||
"progress bar timing: currentTime={1} duration={2}": "{1} von {2}",
|
||||
"Volume Level": "Lautstärkestufe",
|
||||
"Volume Level": "Lautstärke",
|
||||
"{1} is loading.": "{1} wird geladen.",
|
||||
"Seek to live, currently behind live": "Zur Live-Übertragung wechseln. Aktuell wird es nicht live abgespielt.",
|
||||
"Seek to live, currently playing live": "Zur Live-Übertragung wechseln. Es wird aktuell live abgespielt."
|