commit d3eadee95154634d2257fd64ae4eeea76eed9c2a Author: Matthew Welch Date: Sat Jul 6 23:00:00 2019 -0700 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bf6d7e2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.idea +/__pycache__ diff --git a/README.md b/README.md new file mode 100644 index 0000000..84a69bd --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +rpiWebApp diff --git a/app.py b/app.py new file mode 100644 index 0000000..40a11ec --- /dev/null +++ b/app.py @@ -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/") +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() diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..a9dd980 --- /dev/null +++ b/nginx.conf @@ -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; +} diff --git a/scripts/__pycache__/database.cpython-37.pyc b/scripts/__pycache__/database.cpython-37.pyc new file mode 100644 index 0000000..c22418d Binary files /dev/null and b/scripts/__pycache__/database.cpython-37.pyc differ diff --git a/scripts/__pycache__/func.cpython-37.pyc b/scripts/__pycache__/func.cpython-37.pyc new file mode 100644 index 0000000..950d87f Binary files /dev/null and b/scripts/__pycache__/func.cpython-37.pyc differ diff --git a/scripts/database.py b/scripts/database.py new file mode 100644 index 0000000..73b2232 --- /dev/null +++ b/scripts/database.py @@ -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) diff --git a/scripts/func.py b/scripts/func.py new file mode 100644 index 0000000..fe4fea1 --- /dev/null +++ b/scripts/func.py @@ -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 diff --git a/static/icon.png b/static/icon.png new file mode 100644 index 0000000..6a5417d Binary files /dev/null and b/static/icon.png differ diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..6727e58 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,15 @@ + + + + + {{ title }} + + {% block head %} + {% endblock %} + + +{% block content %} +

Hello World!

+{% endblock %} + + diff --git a/templates/comicList.html b/templates/comicList.html new file mode 100644 index 0000000..cd833fc --- /dev/null +++ b/templates/comicList.html @@ -0,0 +1,5 @@ +{% for comic in comics %} +
  • + {{ comic[0] }} {% if comic[1] > 0 %}{{ "#{0:g}".format(comic[1]) }}{% endif %} {% if comic[2] != None %}{{ comic[2] }} {% endif %} +
  • +{% endfor %} diff --git a/templates/comicView.html b/templates/comicView.html new file mode 100644 index 0000000..0840532 --- /dev/null +++ b/templates/comicView.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} + +{% block content %} + +{% endblock %} diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..94d9808 --- /dev/null +++ b/templates/index.html @@ -0,0 +1 @@ +{% extends "base.html" %} diff --git a/templates/publisherList.html b/templates/publisherList.html new file mode 100644 index 0000000..f0e9b6d --- /dev/null +++ b/templates/publisherList.html @@ -0,0 +1,3 @@ +{% for publisher in comics %} +
  • {{ publisher }}
  • +{% endfor %} diff --git a/templates/publisherView.html b/templates/publisherView.html new file mode 100644 index 0000000..8599678 --- /dev/null +++ b/templates/publisherView.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} + +{% block content %} + + + + + + + +{% endblock %} diff --git a/templates/seriesList.html b/templates/seriesList.html new file mode 100644 index 0000000..d95d7ef --- /dev/null +++ b/templates/seriesList.html @@ -0,0 +1,3 @@ +{% for comic in comics %} +
  • {{ comic[0] }} {{ comic[1] }}
  • +{% endfor %} diff --git a/templates/seriesView.html b/templates/seriesView.html new file mode 100644 index 0000000..31e5e1f --- /dev/null +++ b/templates/seriesView.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} + +{% block content %} + +{% endblock %} diff --git a/test.py b/test.py new file mode 100644 index 0000000..03ba372 --- /dev/null +++ b/test.py @@ -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)) diff --git a/yourapplication.fcgi b/yourapplication.fcgi new file mode 100644 index 0000000..66ffa80 --- /dev/null +++ b/yourapplication.fcgi @@ -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()