Initial commit

This commit is contained in:
Matthew Welch 2019-07-06 23:00:00 -07:00
commit d3eadee951
19 changed files with 554 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/.idea
/__pycache__

1
README.md Normal file
View File

@ -0,0 +1 @@
rpiWebApp

98
app.py Normal file
View File

@ -0,0 +1,98 @@
from flask import Flask
from flask import render_template
from flask import request
from flask import g
import threading
from urllib import parse
import scripts.func as func
from scripts import database
app = Flask(__name__)
def get_comics():
with app.app_context():
func.get_comics()
def verify_paths():
with app.app_context():
database.verify_paths()
with app.app_context():
database.initialize_db()
thread = threading.Thread(target=get_comics, args=())
thread.daemon = True
thread.start()
thread2 = threading.Thread(target=verify_paths, args=())
thread2.daemon = True
thread2.start()
@app.teardown_appcontext
def close_connection(exception):
db = getattr(g, '_database', None)
if db is not None:
db.close()
def update_comic_db(sender, **kw):
try:
database.add_comics(kw["meta"])
except Exception as e:
print(e)
func.comic_loaded.connect(update_comic_db)
@app.route('/')
def hello_world():
return render_template("index.html", title="Hello World")
@app.route("/movies")
def movies():
return "No Movies"
@app.route("/music")
def music():
return "No music"
@app.route("/games")
def games():
return "No Games"
@app.route("/comics")
def comics():
polling = request.args.get("polling")
if polling:
try:
return render_template("publisherList.html", comics=database.get_publishers())
except Exception as e:
print(e)
return "Sucks to be you"
try:
return render_template("publisherView.html", title="Comics", comics=database.get_publishers())
except Exception as e:
print(e)
@app.route("/comics/<publisher>")
def comics_publisher(publisher):
publisher = parse.unquote(publisher)
series = request.args.get("series")
series_year = request.args.get("seriesYear")
comic = request.args.get("comic")
if series:
return render_template("comicView.html", title="Comics", comics=database.db_get_comics_in_series(series, publisher, series_year))
return render_template("seriesView.html", title="Comics", comics=database.db_get_series_by_publisher(publisher))
if __name__ == '__main__':
app.run()

8
nginx.conf Normal file
View File

@ -0,0 +1,8 @@
server_name rpi.narnian.us;
#location / { try_files $uri @rpiWebApp; }
location / {
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_NAME "";
fastcgi_pass unix:/run/matt/rpiWebApp/fcgi.sock;
}

Binary file not shown.

Binary file not shown.

160
scripts/database.py Normal file
View File

@ -0,0 +1,160 @@
from flask import Flask
from flask import g
import sqlite3
import os, time
from comicapi.issuestring import IssueString
DATABASE = "/var/lib/rpiWebApp/database.db"
def get_db():
db = getattr(g, '_database', None)
if db is None:
db = g._database = sqlite3.connect(DATABASE)
return db
def initialize_db():
get_db().execute("""CREATE TABLE IF NOT EXISTS "comics" (
"path" TEXT UNIQUE,
"tagOrigin" TEXT,
"series" TEXT,
"issue" REAL,
"issueText" TEXT,
"title" TEXT,
"publisher" TEXT,
"month" INTEGER,
"year" INTEGER,
"day" INTEGER,
"seriesYear" INTEGER,
"issueCount" INTEGER,
"volume" TEXT,
"genre" TEXT,
"language" TEXT,
"comments" TEXT,
"volumeCount" INTEGER,
"criticalRating" TEXT,
"country" TEXT,
"alternateSeries" TEXT,
"alternateNumber" TEXT,
"alternateCount" INTEGER,
"imprint" TEXT,
"notes" TEXT,
"webLink" TEXT,
"format" TEXT,
"manga" TEXT,
"blackAndWhite" TEXT,
"pageCount" TEXT,
"maturityRating" TEXT,
"storyArc" TEXT,
"seriesGroup" TEXT,
"scanInfo" TEXT,
"characters" TEXT,
"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 INDEX IF NOT EXISTS path_index ON comics(path);")
get_db().commit()
def table_exists(table_name):
cursor = get_db().execute("SELECT name FROM sqlite_master WHERE type='table' AND name='{}'".format(table_name))
get_db().commit()
if cursor.rowcount == 0:
return False
return True
def add_comics(meta):
data = []
for info in meta:
issue = IssueString(info[1].issue).asFloat()
data.append((info[0], info[1].tagOrigin, info[1].series, (issue or -1), info[1].issue, info[1].title, info[1].publisher,
info[1].month, info[1].year, info[1].day, info[1].seriesYear, info[1].issueCount, info[1].volume, info[1].genre,
info[1].language, info[1].comments, info[1].volumeCount, info[1].criticalRating, info[1].country,
info[1].alternateSeries, info[1].alternateNumber, info[1].alternateCount, info[1].imprint,
info[1].notes, info[1].webLink, info[1].format, info[1].manga, info[1].blackAndWhite,
info[1].pageCount, info[1].maturityRating, info[1].storyArc, info[1].seriesGroup, info[1].scanInfo,
info[1].characters, info[1].teams, info[1].locations))
get_db().executemany(
"""INSERT into comics(path, tagOrigin, series, issue, issueText, title, publisher,
month, year, day, seriesYear, issueCount, volume, genre, language, comments, volumeCount,
criticalRating, country, alternateSeries, alternateNumber, alternateCount, imprint,
notes, webLink, format, manga, blackAndWhite, pageCount, maturityRating, storyArc,
seriesGroup, scanInfo, characters, teams, locations)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",
data)
get_db().commit()
def db_get_all_comics():
original_factory = get_db().row_factory
def dict_factory(cursor, row):
d = {}
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
get_db().row_factory = dict_factory
result = get_db().execute("SELECT series, issue, title FROM comics ORDER BY series, issue").fetchall()
get_db().commit()
get_db().row_factory = original_factory
return result
def db_get_series_by_publisher(publisher):
series = []
rows = get_db().execute("SELECT DISTINCT series, seriesYear, publisher FROM comics WHERE publisher LIKE ? ORDER BY series, seriesYear", [publisher]).fetchall()
for row in rows:
series.append(row)
return series
def db_get_comics_in_series(series, publisher, series_year):
comics = []
rows = get_db().execute("SELECT series, issue, title FROM comics WHERE series LIKE ? AND publisher LIKE ? AND seriesYear LIKE ? ORDER BY series, issue", [series, publisher, series_year]).fetchall()
get_db().commit()
for row in rows:
comics.append(row)
return comics
def get_publishers():
publishers = []
rows = get_db().execute("SELECT DISTINCT publisher FROM comics ORDER BY publisher").fetchall()
for row in rows:
publishers.append(row[0])
return publishers
def comic_path_in_db(path):
try:
result = get_db().execute("SELECT path FROM comics WHERE path LIKE ?", [path])
get_db().commit()
if result.fetchone():
return True
except Exception as e:
print(path)
print(e)
return False
def verify_paths():
while True:
paths = get_db().execute("SELECT path FROM comics").fetchall()
get_db().commit()
for path in paths:
if not os.path.exists(path[0]):
get_db().execute("DELETE FROM comics WHERE path LIKE ?", [path[0]])
get_db().commit()
time.sleep(60*60*24*5)

67
scripts/func.py Normal file
View File

@ -0,0 +1,67 @@
from comicapi import comicarchive
from blinker import Namespace
import os, sys
from scripts import database
rpi_signals = Namespace()
comic_loaded = rpi_signals.signal("comic-loaded")
# Directories
COMICS_DIRECTORY = "/usb/storage/media/Comics/"
MOVIES_DIRECTORY = "/usb/storage/media/Videos/Movies/"
TV_SHOWS_DIRECTORY = "/usb/storage/media/Videos/TV/"
VIDEOS_DIRECTORY = "/usb/storage/media/Videos/Videos/"
GAMES_DIRECTORY = "/usb/storage/media/games/"
MUSIC_DIRECTORY = "/usb/storage/media/Music/"
#############
def get_comics():
meta = []
i = 0
for root, dirs, files in os.walk(COMICS_DIRECTORY):
for f in files:
if f.endswith(".cbr"):
path = os.path.join(root, f)
if not database.comic_path_in_db(path):
archive = comicarchive.ComicArchive(path, default_image_path="/usb/www/matthew/rpiWebApp/static/icon.png")
meta.append((path, archive.readCIX()))
i += 1
if i > 20:
comic_loaded.send("anonymous", meta=meta.copy())
meta.clear()
i = 0
comic_loaded.send("anonymous", meta=meta)
def bytestring_path(path):
"""Given a path, which is either a bytes or a unicode, returns a str
path (ensuring that we never deal with Unicode pathnames).
"""
# Pass through bytestrings.
if isinstance(path, bytes):
return path
# Try to encode with default encodings, but fall back to UTF8.
try:
return path.encode(_fsencoding())
except (UnicodeError, LookupError):
return path.encode('utf8')
def _fsencoding():
"""Get the system's filesystem encoding. On Windows, this is always
UTF-8 (not MBCS).
"""
encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
if encoding == 'mbcs':
# On Windows, a broken encoding known to Python as "MBCS" is
# used for the filesystem. However, we only use the Unicode API
# for Windows paths, so the encoding is actually immaterial so
# we can avoid dealing with this nastiness. We arbitrarily
# choose UTF-8.
encoding = 'utf8'
return encoding

BIN
static/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

15
templates/base.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
<link rel="icon" type="image/png" href="static/icon.png" sizes="32x32">
{% block head %}
{% endblock %}
</head>
<body>
{% block content %}
<p>Hello World!</p>
{% endblock %}
</body>
</html>

5
templates/comicList.html Normal file
View File

@ -0,0 +1,5 @@
{% for comic in comics %}
<li>
{{ comic[0] }} {% if comic[1] > 0 %}{{ "#{0:g}".format(comic[1]) }}{% endif %} {% if comic[2] != None %}{{ comic[2] }} {% endif %}
</li>
{% endfor %}

7
templates/comicView.html Normal file
View File

@ -0,0 +1,7 @@
{% extends "base.html" %}
{% block content %}
<ul id="comics">
{% include "comicList.html" %}
</ul>
{% endblock %}

1
templates/index.html Normal file
View File

@ -0,0 +1 @@
{% extends "base.html" %}

View File

@ -0,0 +1,3 @@
{% for publisher in comics %}
<li><a href="/comics/{{ publisher }}">{{ publisher }}</a></li>
{% endfor %}

View File

@ -0,0 +1,27 @@
{% extends "base.html" %}
{% block content %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
window.setInterval(function () {
$.ajax({
url: "comics",
type: "get",
data: {polling: true},
success: function(response) {
$("#publishers").html(response);
},
error: function(xhr) {
//Do Something to handle error
}
});
}, 5000);
</script>
<ul id="publishers">
{% include "publisherList.html" %}
</ul>
{% endblock %}

View File

@ -0,0 +1,3 @@
{% for comic in comics %}
<li><a href="/comics/{{ comic[2]|urlencode }}?series={{ comic[0]|urlencode }}&seriesYear={{ comic[1] }}">{{ comic[0] }} {{ comic[1] }}</a></li>
{% endfor %}

View File

@ -0,0 +1,7 @@
{% extends "base.html" %}
{% block content %}
<ul id="series">
{% include "seriesList.html" %}
</ul>
{% endblock %}

142
test.py Normal file
View File

@ -0,0 +1,142 @@
import threading
import time
import os
import sqlite3
from comicapi import comicarchive
from comicapi.issuestring import IssueString
from urllib import parse
os.environ["UNRAR_LIB_PATH"] = 'C:\\Program Files (x86)\\UnrarDLL\\UnRAR.dll'
COMICS_DIRECTORY = "F:\\comics"
print(b'\xE2\x80\x93'.decode("utf-8", "replace"))
#os._exit(0)
def get_comics():
meta = []
i = 0
for root, dirs, files in os.walk(COMICS_DIRECTORY):
for f in files:
if f.endswith(".cbr"):
path = os.path.join(root, f)
print(path)
if not og_comic_path_in_db(path):
archive = comicarchive.ComicArchive(path, default_image_path="C:\\Users\\Matthew\\Documents\\MyPrograms\\Websites\\rpi web interface\\rpiWebApp\\static\\icon.png")
meta.append((path, archive.readCIX()))
return meta
'''
thread = threading.Thread(target=get_comics, args=())
thread.daemon = True
print('start')
thread.start()
time.sleep(3)'''
DATABASE = "C:\\Users\\Matthew\\Documents\\MyPrograms\\Websites\\rpi web interface\\database.db"
db = sqlite3.connect(DATABASE)
def get_db():
global db
return db
def initialize_db():
get_db().execute("""CREATE TABLE IF NOT EXISTS "comics" (
"path" TEXT UNIQUE,
"tagOrigin" TEXT,
"series" TEXT,
"issue" REAL,
"issueText" TEXT,
"title" TEXT,
"publisher" TEXT,
"month" INTEGER,
"year" INTEGER,
"day" INTEGER,
"issueCount" INTEGER,
"volume" TEXT,
"genre" TEXT,
"language" TEXT,
"comments" TEXT,
"volumeCount" INTEGER,
"criticalRating" TEXT,
"country" TEXT,
"alternateSeries" TEXT,
"alternateNumber" TEXT,
"alternateCount" INTEGER,
"imprint" TEXT,
"notes" TEXT,
"webLink" TEXT,
"format" TEXT,
"manga" TEXT,
"blackAndWhite" TEXT,
"pageCount" TEXT,
"maturityRating" TEXT,
"storyArc" TEXT,
"seriesGroup" TEXT,
"scanInfo" TEXT,
"characters" TEXT,
"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 INDEX IF NOT EXISTS path_index ON comics(path);")
get_db().commit()
def add_comics(meta):
data = []
for info in meta:
issue = IssueString(info[1].issue).asFloat()
data.append((info[0], info[1].tagOrigin, info[1].series, (issue or -1), info[1].issue, info[1].title, info[1].publisher,
info[1].month, info[1].year, info[1].day, info[1].issueCount, info[1].volume, info[1].genre,
info[1].language, info[1].comments, info[1].volumeCount, info[1].criticalRating, info[1].country,
info[1].alternateSeries, info[1].alternateNumber, info[1].alternateCount, info[1].imprint,
info[1].notes, info[1].webLink, info[1].format, info[1].manga, info[1].blackAndWhite,
info[1].pageCount, info[1].maturityRating, info[1].storyArc, info[1].seriesGroup, info[1].scanInfo,
info[1].characters, info[1].teams, info[1].locations))
get_db().executemany(
"""INSERT into comics(path, tagOrigin, series, issue, issueText, title, publisher,
month, year, day, issueCount, volume, genre, language, comments, volumeCount,
criticalRating, country, alternateSeries, alternateNumber, alternateCount, imprint,
notes, webLink, format, manga, blackAndWhite, pageCount, maturityRating, storyArc,
seriesGroup, scanInfo, characters, teams, locations)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",
data)
get_db().commit()
def og_comic_path_in_db(path):
result = get_db().execute("SELECT EXISTS(SELECT * FROM comics WHERE path=?) LIMIT 1;", (path,))
if result.fetchone()[0] == 1:
return True
return False
def comic_path_in_db(path):
result = get_db().execute("SELECT path FROM comics WHERE path LIKE ?", [path.encode("utf8")])
if result.fetchone():
return True
return False
#initialize_db()
#add_comics(get_comics())
#for row in get_db().execute('SELECT * FROM comics ORDER BY series'):
# print(row)
#test_path = "/usb/storage/media/Comics/Marvel/Marvel Super Hero Adventures - Spider-Man Web Designers 2019/Marvel Super Hero Adventures - Spider-Man Web Designers #001 (2019).cbr"
#print(comic_path_in_db(test_path))

8
yourapplication.fcgi Normal file
View File

@ -0,0 +1,8 @@
#!/usr/bin/python3
from flup.server.fcgi import WSGIServer
from app import app
if __name__ == '__main__':
app.debug = True
WSGIServer(app, bindAddress='/run/matt/rpiWebApp/fcgi.sock').run()