refactored app structure
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -5,4 +5,6 @@ __pycache__
|
|||||||
*.egg-info
|
*.egg-info
|
||||||
sample
|
sample
|
||||||
.tox
|
.tox
|
||||||
*.sqlite
|
*.sqlite
|
||||||
|
migrations
|
||||||
|
.vscode
|
||||||
29
app/__init__.py
Normal file
29
app/__init__.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
from distutils.command.config import config
|
||||||
|
from flask import Flask
|
||||||
|
from flask_mail import Mail
|
||||||
|
from flask_moment import Moment
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from config import configuration, DevelopmentConfig, TestingConfig, ProductionConfig
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
mail =Mail()
|
||||||
|
moment = Moment()
|
||||||
|
db = SQLAlchemy()
|
||||||
|
|
||||||
|
|
||||||
|
def create_app(config_name):
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
app.config.from_object(configuration[config_name])
|
||||||
|
configuration[config_name].init_app(app)
|
||||||
|
|
||||||
|
mail.init_app(app)
|
||||||
|
moment.init_app(app)
|
||||||
|
db.init_app(app)
|
||||||
|
|
||||||
|
from .main import main as main_blueprint
|
||||||
|
|
||||||
|
app.register_blueprint(main_blueprint)
|
||||||
|
|
||||||
|
return app
|
||||||
23
app/email.py
Normal file
23
app/email.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import threading
|
||||||
|
|
||||||
|
from flask import current_app, render_template
|
||||||
|
from flask_mail import Message
|
||||||
|
|
||||||
|
from app import mail, config
|
||||||
|
|
||||||
|
|
||||||
|
def send_async_email(app, msg):
|
||||||
|
with app.app_context():
|
||||||
|
mail.send(msg)
|
||||||
|
|
||||||
|
def send_email(to, subject, template, **kwargs):
|
||||||
|
msg = Message(
|
||||||
|
|
||||||
|
current_app.config['MAIL_PREFIX'] + subject,
|
||||||
|
sender=current_app.config['MAIL_SENDER'], recipients=to)
|
||||||
|
msg.body = render_template(template + '.txt', **kwargs)
|
||||||
|
msg.html = render_template(template + '.html', **kwargs)
|
||||||
|
|
||||||
|
mail_thread = threading.Thread(target=send_async_email, args=[current_app._get_current_object(), msg])
|
||||||
|
mail_thread.start()
|
||||||
|
return mail_thread
|
||||||
7
app/main/__init__.py
Normal file
7
app/main/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from flask import Blueprint
|
||||||
|
|
||||||
|
|
||||||
|
main = Blueprint('main', __name__)
|
||||||
|
|
||||||
|
|
||||||
|
from . import views, errors
|
||||||
12
app/main/errors.py
Normal file
12
app/main/errors.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from flask import render_template
|
||||||
|
from . import main
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@main.app_errorhandler(404)
|
||||||
|
def not_found(e):
|
||||||
|
return render_template('404.html'), 404
|
||||||
|
|
||||||
|
@main.errorhandler(500)
|
||||||
|
def server_error(e):
|
||||||
|
return render_template('500.html'), 500
|
||||||
9
app/main/forms.py
Normal file
9
app/main/forms.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from flask_wtf import FlaskForm
|
||||||
|
from wtforms import StringField, BooleanField, SubmitField
|
||||||
|
from wtforms.validators import DataRequired
|
||||||
|
|
||||||
|
|
||||||
|
class DownloadForm(FlaskForm):
|
||||||
|
url = StringField('Comic URL', validators=[DataRequired()])
|
||||||
|
series = BooleanField('Series? ')
|
||||||
|
download = SubmitField('Download')
|
||||||
104
app/main/views.py
Normal file
104
app/main/views.py
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from flask import render_template, session, send_from_directory, redirect, url_for, flash
|
||||||
|
|
||||||
|
from app.main import main
|
||||||
|
from app.main.forms import DownloadForm
|
||||||
|
from app import db
|
||||||
|
from app.email import send_email
|
||||||
|
from app.models import User, Role, ComicMeta
|
||||||
|
from yoink.comic import Comic
|
||||||
|
from yoink.config import config
|
||||||
|
|
||||||
|
|
||||||
|
@main.route('/uploads/<path:filename>')
|
||||||
|
def download_file(filename):
|
||||||
|
return send_from_directory(os.path.join(config.library_path, 'comics'), filename, as_attachment=True)
|
||||||
|
|
||||||
|
|
||||||
|
def get_cover_path(comic):
|
||||||
|
return [image for image in os.listdir(os.path.join(config.library_path, 'comics', comic.title)) if image.endswith('000.jpg')][0]
|
||||||
|
|
||||||
|
|
||||||
|
def get_archive_path(comic):
|
||||||
|
return [image for image in os.listdir(os.path.join(config.library_path, 'comics', comic.title)) if image.endswith('.cbr')][0]
|
||||||
|
|
||||||
|
|
||||||
|
def get_comic_library_meta():
|
||||||
|
comic_meta = []
|
||||||
|
|
||||||
|
for comic in ComicMeta.query.order_by(ComicMeta.id.desc()).all():
|
||||||
|
comic_meta.append({
|
||||||
|
'cover': comic.cover_path,
|
||||||
|
'title': comic.title,
|
||||||
|
'archive': comic.archive_path
|
||||||
|
})
|
||||||
|
|
||||||
|
return comic_meta
|
||||||
|
|
||||||
|
|
||||||
|
def new_user(username, db, app, form):
|
||||||
|
user = User.query.filter_by(username=username).first()
|
||||||
|
|
||||||
|
if user is None:
|
||||||
|
user = User(username=form.username.data, role_id=3)
|
||||||
|
db.session.add(user)
|
||||||
|
if app.config['YOINK_ADMIN']:
|
||||||
|
send_email(app.config['YOINK_ADMIN'], 'New User', 'mail/new_user', user=user)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def check_setup():
|
||||||
|
if User.query.all() is None:
|
||||||
|
return redirect(url_for('setup'))
|
||||||
|
|
||||||
|
|
||||||
|
@main.route('/', methods=['post', 'get'])
|
||||||
|
def index():
|
||||||
|
url = None
|
||||||
|
series = False
|
||||||
|
form = DownloadForm()
|
||||||
|
latest = get_comic_library_meta()
|
||||||
|
|
||||||
|
if form.validate_on_submit():
|
||||||
|
url = form.url.data.strip()
|
||||||
|
series = form.series.data
|
||||||
|
|
||||||
|
comic = Comic(url)
|
||||||
|
comic_meta = ComicMeta.query.filter_by(title=comic.title).first()
|
||||||
|
|
||||||
|
if comic_meta is None:
|
||||||
|
comic.archiver.download()
|
||||||
|
comic.archiver.generate_archive()
|
||||||
|
|
||||||
|
comic_meta = ComicMeta()
|
||||||
|
comic_meta.title = comic.title
|
||||||
|
comic_meta.category = comic.category
|
||||||
|
comic_meta.issue = comic.issue_number
|
||||||
|
comic_meta.next_issue = comic.next
|
||||||
|
comic_meta.previous_issue = comic.prev
|
||||||
|
comic_meta.cover_path = os.path.join(comic.title, get_cover_path(comic))
|
||||||
|
comic_meta.archive_path = os.path.join(comic.title, get_archive_path(comic))
|
||||||
|
|
||||||
|
db.session.add(comic_meta)
|
||||||
|
db.session.commit()
|
||||||
|
else:
|
||||||
|
flash(f'Comic {comic.title} exists')
|
||||||
|
|
||||||
|
latest = get_comic_library_meta()
|
||||||
|
form.url.data = ''
|
||||||
|
|
||||||
|
return render_template('index.html', form=form, url=url, series=series, latest=latest), 200
|
||||||
|
|
||||||
|
|
||||||
|
if form.series.data:
|
||||||
|
print('Download the whole damn lot')
|
||||||
|
|
||||||
|
flash(f'{comic.title} downloaded to {os.path.join(config.library_path, "comics/" + comic.title)}')
|
||||||
|
|
||||||
|
latest = get_comic_library_meta()
|
||||||
|
comic.archiver.cleanup_worktree()
|
||||||
|
form.url.data = ''
|
||||||
|
|
||||||
|
return render_template('index.html', form=form, url=url, series=series, latest=latest), 200
|
||||||
31
app/models.py
Normal file
31
app/models.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
from app import db
|
||||||
|
|
||||||
|
|
||||||
|
class Role(db.Model):
|
||||||
|
__tablename__ = 'roles'
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
name = db.Column(db.String(64), unique=True)
|
||||||
|
users = db.relationship('User', backref='role', lazy='dynamic')
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'<Role {self.name!r}>'
|
||||||
|
|
||||||
|
|
||||||
|
class User(db.Model):
|
||||||
|
__tablename__ = 'users'
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
username = db.Column(db.String(64), unique=True, index=True)
|
||||||
|
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
|
||||||
|
|
||||||
|
def __repr__(self): return f'<User {self.username!r}>'
|
||||||
|
|
||||||
|
class ComicMeta(db.Model):
|
||||||
|
__tablename__ = 'comicmeta'
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
title = db.Column(db.String(256), unique=True, index=True)
|
||||||
|
issue = db.Column(db.Integer, nullable=True, index=True)
|
||||||
|
category = db.Column(db.String(128), index=True, nullable=True)
|
||||||
|
previous_issue = db.Column(db.String(256), nullable=True)
|
||||||
|
next_issue = db.Column(db.String(256), nullable=True)
|
||||||
|
cover_path = db.Column(db.String(256))
|
||||||
|
archive_path = db.Column(db.String(256))
|
||||||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
@@ -6,13 +6,13 @@
|
|||||||
{% for comic in comics %}
|
{% for comic in comics %}
|
||||||
<div class="col col-md-3">
|
<div class="col col-md-3">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<img src="{{ url_for('download_file', filename=comic['cover']) }}" alt="{{ comic['title'] }}" class="card-image-top position-relative">
|
<img src="{{ url_for('main.download_file', filename=comic['cover']) }}" alt="{{ comic['title'] }}" class="card-image-top position-relative">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 class="card-title">{{ comic['title'] }}</h4>
|
<h4 class="card-title">{{ comic['title'] }}</h4>
|
||||||
<p class="card-text">{{ comic['title'] }}</p>
|
<p class="card-text">{{ comic['title'] }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer text-center">
|
<div class="card-footer text-center">
|
||||||
<a href="{{url_for('download_file', filename=comic.archive) }}" class="btn btn-info">Download Archive</a>
|
<a href="{{url_for('main.download_file', filename=comic.archive) }}" class="btn btn-info">Download Archive</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
{% for comic in comics %}
|
{% for comic in comics %}
|
||||||
|
|
||||||
<h3>{{ comic['title'] }}</h3>
|
<h3>{{ comic['title'] }}</h3>
|
||||||
<img src="{{ url_for('download_file', filename=comic['cover']) }}">
|
<img src="{{ url_for('main.download_file', filename=comic['cover']) }}">
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% else %}
|
{% else %}
|
||||||
46
config.py
Normal file
46
config.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import os
|
||||||
|
from yoink.config import config
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
basedir = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
SECRET_KEY = os.environ.get('SECRET_KEY', 'snapekilleddumpledork')
|
||||||
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
|
MAIL_SERVER = os.environ.get('MAIL_SERVER', 'smtp.gmail.com')
|
||||||
|
MAIL_PORT = os.environ.get('MAIL_PORT', 465)
|
||||||
|
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS', False)
|
||||||
|
MAIL_USE_SSL = os.environ.get('MAIL_USE_SSL', True)
|
||||||
|
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
|
||||||
|
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
|
||||||
|
MAIL_PREFIX = os.environ.get('MAIL_PREFIX', '[YO!NK]')
|
||||||
|
MAIL_SENDER = os.environ.get('MAIL_SENDER', 'YO!NK Admin <yoinkmediaapp@gmail.com>')
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def init_app(app):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DevelopmentConfig(Config):
|
||||||
|
DEBUG = True
|
||||||
|
SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or f'sqlite:///{os.path.join(config.app_root, "data-dev.sqlite")}'
|
||||||
|
|
||||||
|
|
||||||
|
class TestingConfig(Config):
|
||||||
|
TESTING = True
|
||||||
|
SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or f'sqlite:///{os.path.join(config.app_root, "data-test.sqlite")}'
|
||||||
|
|
||||||
|
class ProductionConfig(Config):
|
||||||
|
SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or f'sqlite:///{os.path.join(config.app_root, "data.sqlite")}'
|
||||||
|
|
||||||
|
|
||||||
|
configuration = {
|
||||||
|
'development': DevelopmentConfig,
|
||||||
|
'testing': TestingConfig,
|
||||||
|
'production': ProductionConfig,
|
||||||
|
'default': DevelopmentConfig
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
|
alembic==1.7.7
|
||||||
asgiref==3.5.0
|
asgiref==3.5.0
|
||||||
attrs==21.4.0
|
attrs==21.4.0
|
||||||
beautifulsoup4==4.10.0
|
beautifulsoup4==4.10.0
|
||||||
|
blinker==1.4
|
||||||
bs4==0.0.1
|
bs4==0.0.1
|
||||||
certifi==2021.10.8
|
certifi==2021.10.8
|
||||||
charset-normalizer==2.0.12
|
charset-normalizer==2.0.12
|
||||||
@@ -10,11 +12,18 @@ coverage==6.3.2
|
|||||||
distlib==0.3.4
|
distlib==0.3.4
|
||||||
filelock==3.6.0
|
filelock==3.6.0
|
||||||
Flask==2.1.1
|
Flask==2.1.1
|
||||||
|
Flask-Mail==0.9.1
|
||||||
|
Flask-Migrate==3.1.0
|
||||||
|
Flask-Moment==1.0.2
|
||||||
|
Flask-SQLAlchemy==2.5.1
|
||||||
|
Flask-WTF==1.0.1
|
||||||
|
greenlet==1.1.2
|
||||||
idna==3.3
|
idna==3.3
|
||||||
importlib-metadata==4.11.3
|
importlib-metadata==4.11.3
|
||||||
iniconfig==1.1.1
|
iniconfig==1.1.1
|
||||||
itsdangerous==2.1.2
|
itsdangerous==2.1.2
|
||||||
Jinja2==3.1.1
|
Jinja2==3.1.1
|
||||||
|
Mako==1.2.0
|
||||||
MarkupSafe==2.1.1
|
MarkupSafe==2.1.1
|
||||||
packaging==21.3
|
packaging==21.3
|
||||||
platformdirs==2.5.1
|
platformdirs==2.5.1
|
||||||
@@ -25,10 +34,12 @@ pytest==7.1.0
|
|||||||
requests==2.27.1
|
requests==2.27.1
|
||||||
six==1.16.0
|
six==1.16.0
|
||||||
soupsieve==2.3.1
|
soupsieve==2.3.1
|
||||||
|
SQLAlchemy==1.4.34
|
||||||
toml==0.10.2
|
toml==0.10.2
|
||||||
tomli==2.0.1
|
tomli==2.0.1
|
||||||
tox==3.24.5
|
tox==3.24.5
|
||||||
urllib3==1.26.8
|
urllib3==1.26.8
|
||||||
virtualenv==20.14.0
|
virtualenv==20.14.0
|
||||||
Werkzeug==2.1.0
|
Werkzeug==2.1.0
|
||||||
|
WTForms==3.0.1
|
||||||
zipp==3.7.0
|
zipp==3.7.0
|
||||||
|
|||||||
2
setup.py
2
setup.py
@@ -10,7 +10,7 @@ with open('README.md', 'r') as readme:
|
|||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
name='yoink',
|
name='yoink',
|
||||||
version='0.2.0',
|
version='0.3.2',
|
||||||
author='Bryan Bailey',
|
author='Bryan Bailey',
|
||||||
author_email='brizzledev@gmail.com',
|
author_email='brizzledev@gmail.com',
|
||||||
description='',
|
description='',
|
||||||
|
|||||||
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
24
tests/test_web.py
Normal file
24
tests/test_web.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
from flask import current_app
|
||||||
|
|
||||||
|
from app import create_app, db
|
||||||
|
|
||||||
|
|
||||||
|
class BasicTestCase(unittest.TestCase):
|
||||||
|
def setUp(self) -> None:
|
||||||
|
self.app = create_app('testing')
|
||||||
|
self.app_context = self.app.app_context()
|
||||||
|
self.app_context.push()
|
||||||
|
db.create_all()
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
db.session.remove()
|
||||||
|
db.drop_all()
|
||||||
|
self.app_context.pop()
|
||||||
|
|
||||||
|
def test_app_exists(self):
|
||||||
|
self.assertFalse(current_app is None)
|
||||||
|
|
||||||
|
def test_app_is_testing(self):
|
||||||
|
self.assertTrue(current_app.config['TESTING'])
|
||||||
147
web.py
147
web.py
@@ -1,141 +1,22 @@
|
|||||||
import os
|
import os
|
||||||
import threading
|
|
||||||
from flask import Flask, render_template, url_for, request, flash, make_response, redirect, send_from_directory
|
|
||||||
from flask_moment import Moment
|
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
|
||||||
from flask_wtf import FlaskForm
|
|
||||||
from wtforms import StringField, SubmitField, BooleanField
|
|
||||||
from wtforms.validators import DataRequired
|
|
||||||
|
|
||||||
|
from flask_migrate import Migrate
|
||||||
|
|
||||||
|
from app import create_app, db
|
||||||
|
from app.models import User, Role, ComicMeta
|
||||||
from yoink.config import config
|
from yoink.config import config
|
||||||
from yoink.comic import Comic
|
from yoink.comic import Comic
|
||||||
|
|
||||||
|
|
||||||
class DownloadForm(FlaskForm):
|
app = create_app(os.environ.get('FLASK_CONFIG') or 'default')
|
||||||
url = StringField('Comic URL', validators=[DataRequired()])
|
migrate = Migrate(app, db)
|
||||||
series = BooleanField('Series? ')
|
|
||||||
download = SubmitField('Download')
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
@app.shell_context_processor
|
||||||
moment = Moment(app)
|
def make_shell_ctx(): return dict(db=db, User=User, Role=Role, ComicMeta=ComicMeta)
|
||||||
app.config['SECRET_KEY'] = 'snapekilleddumpledork'
|
|
||||||
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{os.path.join(config.app_root, "data.sqlite")}'
|
|
||||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
|
||||||
db = SQLAlchemy(app)
|
|
||||||
|
|
||||||
|
@app.cli.command()
|
||||||
|
def test():
|
||||||
class Role(db.Model):
|
''' run unit tests '''
|
||||||
__tablename__ = 'roles'
|
import unittest
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
tests = unittest.TestLoader().discover('tests')
|
||||||
name = db.Column(db.String(64), unique=True)
|
unittest.TextTestRunner(verbosity=2).run(tests)
|
||||||
users = db.relationship('User', backref='role', lazy='dynamic')
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return f'<Role {self.name!r}>'
|
|
||||||
|
|
||||||
|
|
||||||
class User(db.Model):
|
|
||||||
__tablename__ = 'users'
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
username = db.Column(db.String(64), unique=True, index=True)
|
|
||||||
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
|
|
||||||
|
|
||||||
def __repr__(self): return f'<User {self.username!r}>'
|
|
||||||
|
|
||||||
class ComicMeta(db.Model):
|
|
||||||
__tablename__ = 'comicmeta'
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
title = db.Column(db.String(256), unique=True, index=True)
|
|
||||||
issue = db.Column(db.Integer, nullable=True, index=True)
|
|
||||||
category = db.Column(db.String(128), index=True, nullable=True)
|
|
||||||
previous_issue = db.Column(db.String(256), nullable=True)
|
|
||||||
next_issue = db.Column(db.String(256), nullable=True)
|
|
||||||
cover_path = db.Column(db.String(256))
|
|
||||||
archive_path = db.Column(db.String(256))
|
|
||||||
|
|
||||||
|
|
||||||
@app.errorhandler(404)
|
|
||||||
def not_found(e):
|
|
||||||
return render_template('404.html'), 404
|
|
||||||
|
|
||||||
@app.errorhandler(500)
|
|
||||||
def server_error(e):
|
|
||||||
return render_template('500.html'), 500
|
|
||||||
|
|
||||||
@app.route('/uploads/<path:filename>')
|
|
||||||
def download_file(filename):
|
|
||||||
return send_from_directory(os.path.join(config.library_path, 'comics'), filename, as_attachment=True)
|
|
||||||
|
|
||||||
|
|
||||||
def get_cover_path(comic):
|
|
||||||
return [image for image in os.listdir(os.path.join(config.library_path, 'comics', comic.title)) if image.endswith('000.jpg')][0]
|
|
||||||
|
|
||||||
|
|
||||||
def get_archive_path(comic):
|
|
||||||
return [image for image in os.listdir(os.path.join(config.library_path, 'comics', comic.title)) if image.endswith('.cbr')][0]
|
|
||||||
|
|
||||||
|
|
||||||
def get_comic_library_meta():
|
|
||||||
comic_meta = []
|
|
||||||
|
|
||||||
for comic in ComicMeta.query.all():
|
|
||||||
comic_meta.append({
|
|
||||||
'cover': comic.cover_path,
|
|
||||||
'title': comic.title,
|
|
||||||
'archive': comic.archive_path
|
|
||||||
})
|
|
||||||
|
|
||||||
return comic_meta
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/', methods=['post','get'])
|
|
||||||
def index():
|
|
||||||
url = None
|
|
||||||
series = False
|
|
||||||
form = DownloadForm()
|
|
||||||
latest = get_comic_library_meta()
|
|
||||||
|
|
||||||
if form.validate_on_submit():
|
|
||||||
url = form.url.data.strip()
|
|
||||||
series = form.series.data
|
|
||||||
|
|
||||||
comic = Comic(url)
|
|
||||||
comic_meta = ComicMeta.query.filter_by(title=comic.title).first()
|
|
||||||
|
|
||||||
comic.archiver.download()
|
|
||||||
comic.archiver.generate_archive()
|
|
||||||
|
|
||||||
|
|
||||||
if comic_meta is None:
|
|
||||||
comic_meta = ComicMeta()
|
|
||||||
comic_meta.title = comic.title
|
|
||||||
comic_meta.category = comic.category
|
|
||||||
comic_meta.issue = comic.issue_number
|
|
||||||
comic_meta.next_issue = comic.next
|
|
||||||
comic_meta.previous_issue = comic.prev
|
|
||||||
comic_meta.cover_path = os.path.join(comic.title, get_cover_path(comic))
|
|
||||||
comic_meta.archive_path = os.path.join(comic.title, get_archive_path(comic))
|
|
||||||
|
|
||||||
db.session.add(comic_meta)
|
|
||||||
db.session.commit()
|
|
||||||
else:
|
|
||||||
flash(f'Comic {comic.title} exists')
|
|
||||||
|
|
||||||
latest = get_comic_library_meta()
|
|
||||||
form.url.data = ''
|
|
||||||
|
|
||||||
return render_template('index.html', form=form, url=url, series=series, latest=latest), 200
|
|
||||||
|
|
||||||
|
|
||||||
if form.series.data:
|
|
||||||
print('Download the whole damn lot')
|
|
||||||
|
|
||||||
flash(f'{comic.title} downloaded to {os.path.join(config.library_path, "comics/" + comic.title)}')
|
|
||||||
|
|
||||||
latest = get_comic_library_meta()
|
|
||||||
comic.archiver.cleanup_worktree()
|
|
||||||
form.url.data = ''
|
|
||||||
|
|
||||||
return render_template('index.html', form=form, url=url, series=series, latest=latest), 200
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user