Repos / pytaku / 48becd10fe
commit 48becd10fe783ae937cfcda772f38e88659a6ffb
Author: Bùi Thành Nhân <hi@imnhan.com>
Date: Tue Aug 25 21:15:15 2020 +0700
remove old stuff before SPA
diff --git a/src/pytaku/decorators.py b/src/pytaku/decorators.py
index 599dd36..22015e7 100644
--- a/src/pytaku/decorators.py
+++ b/src/pytaku/decorators.py
@@ -1,18 +1,8 @@
from functools import wraps
-from flask import jsonify, redirect, request, session, url_for
+from flask import jsonify, request
-from .persistence import read, unread, verify_token
-
-
-def require_login(f):
- @wraps(f)
- def decorated_function(*args, **kwargs):
- if session.get("user") is None:
- return redirect(url_for("auth_view", next=request.url))
- return f(*args, **kwargs)
-
- return decorated_function
+from .persistence import verify_token
def process_token(required=True):
@@ -48,39 +38,3 @@ def decorated_function(*args, **kwargs):
return decorated_function
return decorator
-
-
-def toggle_has_read(f):
- """
- Augments a view with the ability to toggle a chapter's read status if there's a
- `?has_read=<chapter_id>` url param.
- """
-
- @wraps(f)
- def decorated_function(*args, **kwargs):
- assert "site" in kwargs
- assert "title_id" in kwargs
- has_read_chapter_id = request.args.get("has_read")
- unread_chapter_id = request.args.get("unread")
- assert not (has_read_chapter_id and unread_chapter_id) # can't do both
-
- if session.get("user"):
- if has_read_chapter_id:
- read(
- session["user"]["id"],
- kwargs["site"],
- kwargs["title_id"],
- has_read_chapter_id,
- )
- return redirect(request.url[: request.url.rfind("?")])
- elif unread_chapter_id:
- unread(
- session["user"]["id"],
- kwargs["site"],
- kwargs["title_id"],
- unread_chapter_id,
- )
- return redirect(request.url[: request.url.rfind("?")])
- return f(*args, **kwargs)
-
- return decorated_function
diff --git a/src/pytaku/main.py b/src/pytaku/main.py
index 747f23e..09970cf 100644
--- a/src/pytaku/main.py
+++ b/src/pytaku/main.py
@@ -6,20 +6,10 @@
from typing import List, Tuple
import requests
-from flask import (
- Flask,
- flash,
- jsonify,
- make_response,
- redirect,
- render_template,
- request,
- session,
- url_for,
-)
+from flask import Flask, jsonify, make_response, render_template, request, url_for
from .conf import config
-from .decorators import process_token, require_login
+from .decorators import process_token
from .persistence import (
create_token,
delete_token,
@@ -71,136 +61,6 @@ def _chapter_name(chapter: dict):
return result
-@app.route("/following", methods=["GET"])
-@require_login
-def follows_view():
- titles = get_followed_titles(session["user"]["id"])
- for title in titles:
- thumbnail = title_thumbnail(title["site"], title["id"])
- if title["site"] == "mangadex":
- thumbnail = url_for("proxy_view", b64_url=_encode_proxy_url(thumbnail))
- title["thumbnail"] = thumbnail
- return render_template("old/follows.html", titles=titles)
-
-
-@app.route("/follow/<site>/<title_id>", methods=["POST"])
-@require_login
-def follow_view(site, title_id):
- follow(session["user"]["id"], site, title_id)
- return redirect(url_for("spa_title_view", site=site, title_id=title_id))
-
-
-@app.route("/unfollow/<site>/<title_id>", methods=["POST"])
-@require_login
-def unfollow_view(site, title_id):
- unfollow(session["user"]["id"], site, title_id)
- return redirect(url_for("spa_title_view", site=site, title_id=title_id))
-
-
-@app.route("/logout", methods=["POST"])
-def logout_view():
- session.pop("user")
- return redirect("/")
-
-
-@app.route("/auth", methods=["GET", "POST"])
-def auth_view():
- if session.get("user"):
- return redirect(url_for("home_view"))
-
- if request.method == "POST":
-
- if request.form["action"] == "register":
- username = request.form["username"].strip()
- password = request.form["password"]
- confirm_password = request.form["confirm-password"]
- message = None
- if password != confirm_password:
- message = "Password confirmation didn't match."
- status_code = 400
- elif not (username and password and confirm_password):
- message = "Empty field(s) spotted. Protip: spaces don't count."
- status_code = 400
- elif (
- len(username) < 2
- or len(username) > 15
- or len(password) < 5
- or len(password) > 50
- ):
- message = "Invalid username/password length. Username length should be 2~15, password 5~50."
- status_code = 400
- else: # success!
- err = register_user(username, password)
- if err:
- message = err
- status_code = 400
- else:
- username = ""
- password = ""
- confirm_password = ""
- message = "Registration successful! You can login now."
- status_code = 200
- return (
- render_template(
- "old/auth.html",
- register_username=username,
- register_password=password,
- register_confirm_password=confirm_password,
- register_message=message,
- register_has_error=status_code != 200,
- ),
- status_code,
- )
-
- else: # action == 'login'
- username = request.form["username"].strip()
- password = request.form["password"]
- remember = request.form.get("remember") == "on"
- if not (username and password):
- message = "Empty field(s) spotted. Protip: spaces don't count."
- status_code = 400
- else:
- user_id = verify_username_password(username, password)
- if user_id is None:
- message = "Wrong username/password combination."
- status_code = 400
- else: # success!
- resp = redirect(request.args.get("next", url_for("home_view")))
- session.permanent = remember
- session["user"] = {"username": username, "id": user_id}
- return resp
-
- return (
- render_template(
- "old/auth.html",
- login_username=username,
- login_password=password,
- login_remember=remember,
- login_message=message,
- login_has_error=status_code != 200,
- ),
- status_code,
- )
-
- # Just a plain ol' GET request:
- return render_template("old/auth.html")
-
-
-@app.route("/search")
-def search_view():
- query = request.args.get("q", "").strip()
- results = {}
- if query:
- results = search_title_all_sites(query)
-
- if "mangadex" in results:
- for title in results["mangadex"]:
- title["thumbnail"] = url_for(
- "proxy_view", b64_url=_encode_proxy_url(title["thumbnail"])
- )
- return render_template("old/search.html", results=results, query=query)
-
-
@app.route("/proxy/<b64_url>")
def proxy_view(b64_url):
"""Fine I'll do it"""
@@ -231,41 +91,6 @@ def _is_manga_img_url(
return pattern.match(url)
-@app.route("/import", methods=["GET", "POST"])
-@require_login
-def import_view():
- if request.method == "POST":
-
- # check if the post request has the file part
- if "tachiyomi" not in request.files:
- flash("No file part")
- return redirect(request.url)
- file = request.files["tachiyomi"]
-
- # if user does not select file, browser also
- # submits an empty part without filename
- if file.filename == "":
- flash("No selected file")
- return redirect(request.url)
-
- if file:
- text = file.read()
- site_title_pairs = read_tachiyomi_follows(text)
- if site_title_pairs is None:
- flash("Malformed input file.")
- return redirect(request.url)
-
- # First fetch & save titles if they're not already in db
- ensure_titles(site_title_pairs)
-
- # Then follow them all
- import_follows(session["user"]["id"], site_title_pairs)
-
- flash(f"Added {len(site_title_pairs)} follows.")
-
- return render_template("old/import.html")
-
-
def read_tachiyomi_follows(text: str) -> List[Tuple[str, str]]:
try:
data = json.loads(text)
@@ -331,11 +156,6 @@ def ensure_titles(site_title_pairs: List[Tuple[str, str]]):
return title_dicts
-"""
-New Mithril-based SPA views follow
-"""
-
-
@app.route("/")
@app.route("/h")
@app.route("/a")
diff --git a/src/pytaku/static/base.css b/src/pytaku/static/base.css
deleted file mode 100644
index babcfd1..0000000
--- a/src/pytaku/static/base.css
+++ /dev/null
@@ -1,214 +0,0 @@
-/* Look & feel */
-:root {
- --btn-red: #ef4f39;
- --btn-red-bottom: #b94434;
- --btn-green: #3ba60a;
- --btn-green-bottom: #338a0d;
- --btn-blue: #009ee8;
- --btn-blue-bottom: #26789f;
- --btn-gray: #444;
- --btn-gray-bottom: #555;
- --bg-black: #231f20;
- --border-radius: 3px;
- --body-padding: 0.5rem;
-
- font-size: 100%;
- font-family: sans-serif;
- overflow-y: scroll;
-}
-
-html {
- touch-action: manipulation;
-}
-
-h1 {
- margin-top: 1rem;
- margin-bottom: 0.5rem;
- font-size: 2rem;
- font-weight: bold;
-}
-
-table {
- border-collapse: collapse;
-}
-td,
-th {
- border: 1px solid black;
- padding: 0.5em;
-}
-tr:nth-child(even) {
- background-color: #eee;
-}
-th {
- background-color: #777;
- color: white;
-}
-
-input {
- padding: 0.3rem;
-}
-
-p {
- line-height: 1.5rem;
-}
-
-.button {
- display: inline-block;
- user-select: none;
- margin: 0;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- vertical-align: bottom;
-
- cursor: pointer;
- border: 0;
- padding: 0.5rem 1rem 0.3rem 1rem;
- border-radius: var(--border-radius);
- color: white;
- text-decoration: none;
-}
-.button > * {
- margin-right: 0.3rem;
-}
-.button > *:last-child {
- margin-right: 0;
-}
-.button:hover {
- filter: brightness(110%);
-}
-.button:active {
- filter: brightness(90%);
-}
-.button:focus {
- box-shadow: 0 0 2px black;
-}
-.button.red {
- background-color: var(--btn-red);
- border-bottom: 4px solid var(--btn-red-bottom);
-}
-.button.green {
- background-color: var(--btn-green);
- border-bottom: 4px solid var(--btn-green-bottom);
-}
-.button.blue {
- background-color: var(--btn-blue);
- border-bottom: 4px solid var(--btn-blue-bottom);
-}
-.button.gray {
- background-color: var(--btn-gray);
- border-bottom: 4px solid var(--btn-gray-bottom);
-}
-.button.disabled,
-.button.disabled:hover,
-.button.disabled:active {
- background-color: #aaa;
- border-bottom: 4px solid #aaa;
- filter: none;
- cursor: default;
- opacity: 0.5;
-}
-.button > img {
- height: 1rem;
-}
-
-/* Grid layout */
-
-nav {
- display: flex;
- flex-wrap: wrap;
- padding: var(--body-padding);
-}
-nav > * {
- margin-right: 1rem;
- margin-top: 0.2rem;
- margin-bottom: 0.2rem;
-}
-nav > *:last-child {
- margin-right: 0;
-}
-
-.logo {
- width: 150px;
-}
-.logo img {
- max-width: 100%;
- display: block;
-}
-
-.search {
- display: flex;
-}
-
-.links {
- margin-left: auto; /* to pull to the right */
- display: inline-flex;
- justify-content: center;
- align-items: center;
- color: white;
-}
-.links > * {
- margin-right: 1rem;
-}
-.links > *:last-child {
- margin-right: 0;
-}
-.links a * {
- vertical-align: middle;
-}
-
-/* Component-specific styling */
-
-nav {
- background-color: var(--bg-black);
-}
-
-.search input {
- border: 0;
- border-radius: var(--border-radius) 0 0 var(--border-radius);
-}
-.search button {
- border-radius: 0 var(--border-radius) var(--border-radius) 0;
-}
-
-.links a {
- color: white;
- text-decoration: none;
-}
-.links a:hover {
- text-decoration: underline;
-}
-
-.content {
- padding: var(--body-padding);
-}
-.content > * {
- display: block;
- margin-top: 0.5rem;
- margin-bottom: 0.5rem;
-}
-
-footer {
- padding: 1rem var(--body-padding) var(--body-padding) var(--body-padding);
- line-height: 1.5em;
- opacity: 0.7;
-}
-footer a {
- color: inherit;
-}
-
-/* sticky footer */
-html,
-body {
- height: 100%;
-}
-body {
- display: flex;
- flex-direction: column;
-}
-.content {
- flex: 1 0 auto;
-}
-footer {
- flex-shrink: 0;
-}
diff --git a/src/pytaku/static/icons/LICENSE b/src/pytaku/static/icons/LICENSE
deleted file mode 100644
index 29e925b..0000000
--- a/src/pytaku/static/icons/LICENSE
+++ /dev/null
@@ -1,24 +0,0 @@
-Feather icon set by Cole Bemis:
-https://github.com/feathericons/feather
-
-The MIT License (MIT)
-
-Copyright (c) 2013-2017 Cole Bemis
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/src/pytaku/static/icons/arrow-up-right.svg b/src/pytaku/static/icons/arrow-up-right.svg
deleted file mode 100644
index b61b220..0000000
--- a/src/pytaku/static/icons/arrow-up-right.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-up-right"><line x1="7" y1="17" x2="17" y2="7"></line><polyline points="7 7 17 7 17 17"></polyline></svg>
\ No newline at end of file
diff --git a/src/pytaku/static/icons/bookmark.svg b/src/pytaku/static/icons/bookmark.svg
deleted file mode 100644
index ce23590..0000000
--- a/src/pytaku/static/icons/bookmark.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bookmark"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"></path></svg>
\ No newline at end of file
diff --git a/src/pytaku/static/icons/chevrons-left.svg b/src/pytaku/static/icons/chevrons-left.svg
deleted file mode 100644
index 3b96532..0000000
--- a/src/pytaku/static/icons/chevrons-left.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevrons-left"><polyline points="11 17 6 12 11 7"></polyline><polyline points="18 17 13 12 18 7"></polyline></svg>
\ No newline at end of file
diff --git a/src/pytaku/static/icons/chevrons-right.svg b/src/pytaku/static/icons/chevrons-right.svg
deleted file mode 100644
index 7071dfc..0000000
--- a/src/pytaku/static/icons/chevrons-right.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevrons-right"><polyline points="13 17 18 12 13 7"></polyline><polyline points="6 17 11 12 6 7"></polyline></svg>
\ No newline at end of file
diff --git a/src/pytaku/static/icons/eye.svg b/src/pytaku/static/icons/eye.svg
deleted file mode 100644
index 1835ad0..0000000
--- a/src/pytaku/static/icons/eye.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-eye"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg>
\ No newline at end of file
diff --git a/src/pytaku/static/icons/list.svg b/src/pytaku/static/icons/list.svg
deleted file mode 100644
index 1c2ecba..0000000
--- a/src/pytaku/static/icons/list.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-list"><line x1="8" y1="6" x2="21" y2="6"></line><line x1="8" y1="12" x2="21" y2="12"></line><line x1="8" y1="18" x2="21" y2="18"></line><line x1="3" y1="6" x2="3.01" y2="6"></line><line x1="3" y1="12" x2="3.01" y2="12"></line><line x1="3" y1="18" x2="3.01" y2="18"></line></svg>
\ No newline at end of file
diff --git a/src/pytaku/static/icons/log-in.svg b/src/pytaku/static/icons/log-in.svg
deleted file mode 100644
index 7bfc566..0000000
--- a/src/pytaku/static/icons/log-in.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-log-in"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path><polyline points="10 17 15 12 10 7"></polyline><line x1="15" y1="12" x2="3" y2="12"></line></svg>
\ No newline at end of file
diff --git a/src/pytaku/static/icons/log-out.svg b/src/pytaku/static/icons/log-out.svg
deleted file mode 100644
index 628a96d..0000000
--- a/src/pytaku/static/icons/log-out.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-log-out"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><polyline points="16 17 21 12 16 7"></polyline><line x1="21" y1="12" x2="9" y2="12"></line></svg>
\ No newline at end of file
diff --git a/src/pytaku/static/icons/search.svg b/src/pytaku/static/icons/search.svg
deleted file mode 100644
index c478d69..0000000
--- a/src/pytaku/static/icons/search.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
\ No newline at end of file
diff --git a/src/pytaku/static/icons/user.svg b/src/pytaku/static/icons/user.svg
deleted file mode 100644
index 40cd42f..0000000
--- a/src/pytaku/static/icons/user.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-user"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>
\ No newline at end of file
diff --git a/src/pytaku/templates/base.html b/src/pytaku/templates/base.html
deleted file mode 100644
index d671d3c..0000000
--- a/src/pytaku/templates/base.html
+++ /dev/null
@@ -1,83 +0,0 @@
-{# vim: ft=htmldjango
-#}
-
-{% macro ibutton(href='', left_icon='', right_icon='', text='', color='red', title='', disabled=False) -%}
-{% set element = 'a' if href else 'button' %}
-<{{ element }} class="{{ color }} button {% if disabled %}disabled{% endif %}" title="{{title}}"
- {% if href %}href="{{ href }}"{% endif %}
- {% if disabled %}disabled{% endif %} >
- {% if left_icon %}
- <img src="{{ url_for('static', filename='icons/' + left_icon + '.svg')}}" alt="{{ text }} icon" />
- {% endif %}
-
- {% if text %}
- <span>{{ text }}</span>
- {% endif %}
-
- {% if right_icon %}
- <img src="{{ url_for('static', filename='icons/' + right_icon + '.svg')}}" alt="{{ text }} icon" />
- {% endif %}
-</{{ element }}>
-{%- endmacro %}
-
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <title>
- {% block title %}
- {% endblock %}
- - Pytaku
- </title>
- <link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
- <link rel="alternate icon" type="image/png" href="/static/favicon.png" />
- <link rel="stylesheet" href="{{ url_for('static', filename='minireset.css') }}" />
- <link rel="stylesheet" href="{{ url_for('static', filename='base.css') }}" />
-
- {% block head %}
- {% endblock %}
- </head>
-
- <body>
- <nav>
- <a class="logo" href="/"><img src="{{ url_for('static', filename='pytaku.svg')}}" alt="home" /></a>
- <form class="search" action="{{ url_for('search_view') }}" method="GET">
- <input type="text" placeholder="search manga" name="q" value="{{ query }}" /><button class="red button">
- <img src="{{ url_for('static', filename='icons/search.svg')}}" alt="search">
- </button>
- </form>
- <span class="links">
- {% if session.get('user') %}
- <span>Hi there <strong>{{ session.user['username'] }}</strong>!</span>
- <form method="POST" action="{{ url_for('logout_view') }}">
- {{ ibutton(left_icon='log-out', text='Logout', color='gray') }}
- </form>
- {% else %}
- <a href="/auth">
- <img src="{{ url_for('static', filename='icons/log-in.svg')}}" alt="login/register" />
- <span>Login/Register</span>
- </a>
- {% endif %}
- </span>
- </ul>
- </nav>
-
- <div class="content">
- {% block content %}
- {% endblock %}
- </div>
-
- <footer>
- <p>Pytaku is <a href="https://git.sr.ht/~nhanb/pytaku">free and open source software</a>.</p>
- <p>
- <strong>This is a test instance.</strong>
- Database may be wiped. Bugs may be present.<br>
- Your favorite mangaka may never recover from his
- <a href="https://junk.imnhan.com/hunter_x_idol.jpg">idol addiction</a>
- and your favorite series may never finish.
- </p>
- </footer>
- </body>
-
-</html>
diff --git a/src/pytaku/templates/old/auth.html b/src/pytaku/templates/old/auth.html
deleted file mode 100644
index 96b042a..0000000
--- a/src/pytaku/templates/old/auth.html
+++ /dev/null
@@ -1,67 +0,0 @@
-{% extends 'base.html' %}
-
-{% block title %}
-Login / Register
-{% endblock %}
-
-{% block head %}
-<style>
-.content {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- margin: auto;
- max-width: 900px;
- padding: 0;
-}
-
-.content > form {
- display: flex;
- flex-direction: column;
- flex: 1;
- margin: 0 1rem;
-}
-
-.content input,
-.content button {
- margin: .5rem 0;
-}
-
-.success {
- color: inherit;
-}
-.error {
- color: red;
-}
-
-</style>
-{% endblock %}
-
-{% block content %}
-<form method="POST">
- <h1>Login</h1>
- <input type="hidden" name="action" value="login">
- <input name="username" placeholder="Username" required value="{{ login_username }}">
- <input name="password" type="password" placeholder="Password" required value="{{ login_password }}">
- <label for="remember">
- <input name="remember" id="remember" type="checkbox" {% if login_remember %}checked{% endif %}>
- Remember me
- </label>
- <button class="green button" type="submit">Login</button>
- <p class="{{ 'error' if login_has_error else 'success'}}">
- {{ login_message }}
- </p>
-</form>
-
-<form method="POST">
- <h1>Register</h1>
- <input type="hidden" name="action" value="register">
- <input name="username" placeholder="Username (2~15 chars)" required value="{{ register_username }}">
- <input name="password" type="password" placeholder="Password (5~50 chars)" required value="{{ register_password }}">
- <input name="confirm-password" type="password" placeholder="Confirm password" required value="{{ register_confirm_password }}">
- <button class="blue button" type="submit">Register</button>
- <p class="{{ 'error' if register_has_error else 'success'}}">
- {{ register_message }}
- </p>
-</form>
-{% endblock %}
diff --git a/src/pytaku/templates/old/chapter.html b/src/pytaku/templates/old/chapter.html
deleted file mode 100644
index 0ba18f8..0000000
--- a/src/pytaku/templates/old/chapter.html
+++ /dev/null
@@ -1,100 +0,0 @@
-{% extends 'base.html' %}
-
-{% block title %}
-Chapter {{ num_major }}{% if num_minor %}.{{ num_minor }}{% endif %}{% if name %} - {{ name }}{% endif %}
-{% endblock %}
-
-{% block head %}
-<meta property="og:title" content="{{ title['name'] }} {{ self.title() }}" />
-<meta property="og:image" content="{{ title['cover'] }}" />
-<meta property="og:description" content="{{ title['descriptions'] | join('\n') or '(no description)' }}" />
-
-{% if next_chapter %}
-<link rel="prefetch" href="{{ url_for('chapter_view', site=site, title_id=title_id, chapter_id=next_chapter['id'])}}">
-{% endif %}
-
-<style>
- html {
- background-color: #444;
- color: white;
- }
-
- .content {
- padding: var(--body-padding) 0;
- text-align: center;
- }
-
- .cover {
- width: 400px;
- border: 1px solid black;
- }
-
- .pages img {
- display: block;
- margin: 0 auto .7rem auto;
- }
- .pages.webtoon img {
- margin: 0 auto;
- }
-
- .buttons {
- display: flex;
- flex-direction: row;
- justify-content: center;
- flex-wrap: wrap;
- }
- .buttons > * {
- margin-right: .5rem;
- margin-top: .2rem;
- margin-bottom: .2rem;
- }
- .buttons > *:last-child {
- margin-right: 0;
- }
-</style>
-
-{% endblock %}
-
-{% block content %}
-
-<h1>{{ self.title() }}</h1>
-
-{# Put buttons in block to reuse later in this same template #}
-{% block buttons %}
-<div class="buttons">
- {% if prev_chapter %}
- {{ ibutton(href=url_for('chapter_view', site=site, title_id=title_id, chapter_id=prev_chapter['id']), left_icon='chevrons-left', text='Prev') }}
- {% else %}
- {{ ibutton(left_icon='chevrons-left', text='Prev', disabled=True) }}
- {% endif %}
-
- {{ ibutton(href=url_for('title_view', title_id=title_id, site=site), left_icon='list', text='Chapter list', color='blue') }}
-
- {% if next_chapter %}
-
- {% set next_url = url_for('chapter_view', site=site, title_id=title_id, chapter_id=next_chapter['id']) %}
- {% if session['user'] %}
- {% set next_url = next_url + '?has_read=' + id %}
- {% endif %}
- {{ ibutton(href=next_url, right_icon='chevrons-right', text='Next') }}
-
- {% else %}
- {% if session['user'] %}
- {{ ibutton(href=url_for('title_view', site=site, title_id=title_id) + '?has_read=' + id, text='✓ Finish reading', color='green') }}
- {% else %}
- {{ ibutton(right_icon='chevrons-right', text='Next', disabled=True) }}
- {% endif %}
- {% endif %}
-
-</div>
-{% endblock %}
-
-<div class="pages {% if is_webtoon %}webtoon{% endif %}">
- {% for page in pages %}
- <img src="{{ page }}" crossorigin="anonymous" referrerpolicy="no-referrer"/>
- {% endfor %}
-</div>
-
-{{ self.buttons() }}
-
-{% endblock %}
diff --git a/src/pytaku/templates/old/follows.html b/src/pytaku/templates/old/follows.html
deleted file mode 100644
index 957bb24..0000000
--- a/src/pytaku/templates/old/follows.html
+++ /dev/null
@@ -1,104 +0,0 @@
-{% extends 'base.html' %}
-
-{% block title %}
-Stuff I follow
-{% endblock %}
-
-{% block head %}
-<style>
-.title {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- margin-bottom: var(--body-padding);
- background-color: #efefef;
-}
-.title.empty {
- display: inline-flex;
-}
-.title.empty .chapters {
- display: none;
-}
-
-.cover {
- border: 1px solid #777;
- margin-right: .5rem;
- max-width: 150px;
-}
-.cover:hover {
- box-shadow: 0 0 3px black;
-}
-
-.chapters {
- padding: .5rem .5rem .5rem 0;
-}
-
-.chapter {
- display: block;
- margin-bottom: .5rem;
- background-color: white;
- border: 1px solid #999;
- padding: 6px;
- border-radius: 5px;
- text-decoration: none;
- color: black;
-}
-.chapter:hover {
- background-color: #eee;
-}
-.chapter:last-child::after {
- content: '← resume here';
- background-color: cornsilk;
- white-space: nowrap;
-}
-
-.group {
- font-size: .9em;
- background-color: #ddd;
- border-radius: 3px;
- white-space: nowrap;
- padding: 2px 5px;
-}
-
-.more {
- display: inline-block;
- font-style: italic;
-}
-</style>
-{% endblock %}
-
-{% block content %}
-
-{% for title in titles %}
-{% set title_url = url_for('title_view', site=title['site'], title_id=title['id']) %}
-<div class="title {% if title['chapters']|length == 0 %}empty{% endif %}">
- <div>
- <a href="{{ title_url }}">
- <img class="cover"
- src="{{ title['thumbnail'] }}"
- alt="{{ title['name'] }}" />
- </a>
- </div>
- <div class="chapters">
- {% if title['chapters']|length > 4 %}
- <a class="more chapter" href="{{ title_url }}">and {{ title['chapters']|length - 4 }} more...</a>
- {% endif %}
- {% for ch in title['chapters'][-4:] %}
- <a class="chapter" href="{{ url_for('chapter_view', site=title['site'], title_id=title['id'], chapter_id=ch['id']) }}">
- Chapter {{ ch['num_major'] }}{% if ch['num_minor'] %}.{{ ch['num_minor'] }}{% endif %}
- {% if ch['volume'] %}Volume {{ ch['volume'] }} {% endif %}
- {% if ch['name'] %} - {{ ch['name'] }}{% endif %}
- {% for group in ch['groups'] %}
- <span class="group">{{ group | truncate(20) }}</span>
- {% endfor %}
- </a>
- {% endfor %}
- </div>
-</div>
-{% endfor %}
-
-{% if not titles %}
-<p>You're not following any title yet. Try searching for some.</p>
-{% endif %}
-
-{% endblock %}
diff --git a/src/pytaku/templates/old/home.html b/src/pytaku/templates/old/home.html
deleted file mode 100644
index 92c7871..0000000
--- a/src/pytaku/templates/old/home.html
+++ /dev/null
@@ -1,10 +0,0 @@
-{% extends 'base.html' %}
-
-{% block title %}
-Home
-{% endblock %}
-
-{% block content %}
-<p>Try searching for some manga title using the box above.</p>
-<p>Logging in allows you to follow manga titles.</p>
-{% endblock %}
diff --git a/src/pytaku/templates/old/import.html b/src/pytaku/templates/old/import.html
deleted file mode 100644
index 8734d98..0000000
--- a/src/pytaku/templates/old/import.html
+++ /dev/null
@@ -1,36 +0,0 @@
-{% extends 'base.html' %}
-
-{% block title %}
-Import followed titles
-{% endblock %}
-
-{% block head %}
-<style>
-input[type=file] {
- border: 2px solid black;
- border-radius: var(--border-radius);
- margin: 1rem 0;
-}
-
-.message {
- color: red;
-}
-</style>
-{% endblock %}
-
-{% block content %}
-<h1>Importing from Tachiyomi</h1>
-
-<form method="POST" enctype="multipart/form-data" class="upload-form">
- <p>Go to <b>Settings > Backup > Create backup</b>, then upload the generated json file here:</p>
- <input type="file" name="tachiyomi"><br>
- {{ ibutton(text='Submit') }}
-</form>
-
-{% with messages = get_flashed_messages() %}
- {% for message in messages %}
- <p class="message">{{ message }}</p>
- {% endfor %}
-{% endwith %}
-
-{% endblock %}
diff --git a/src/pytaku/templates/old/search.html b/src/pytaku/templates/old/search.html
deleted file mode 100644
index 1e9b23a..0000000
--- a/src/pytaku/templates/old/search.html
+++ /dev/null
@@ -1,73 +0,0 @@
-{% extends 'base.html' %}
-
-{% block title %}
- {% if query %}
- "{{ query }}" search results
- {% else %}
- Search
- {% endif %}
-{% endblock %}
-
-{% block head %}
-<style>
- .site-heading {
- text-transform: capitalize;
- }
- .results {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- }
- .result {
- display: inline-flex;
- flex-direction: column;
- border: 1px solid var(--bg-black);
- margin: 0 1rem 1rem 0;
- background-color: var(--bg-black);
- color: white;
- text-decoration: none;
- max-width: 150px;
- }
- .result span {
- padding: .5rem;
- width: 0;
- min-width: 100%;
- }
-
- .result-text {
- margin-bottom: 1rem;
- }
-</style>
-{% endblock %}
-
-{% block content %}
-
-{% if not query %}
- <h1>Please enter a search query above.</h1>
-
-{% else %}
-{% for site, titles in results.items() %}
-<div>
- <h1 class="site-heading">{{ site }}</h1>
-
- {% if titles %}
- <h2 class="result-text">Showing <strong>{{ titles | length }}</strong> result(s) for "{{ query }}":</h2>
- {% else %}
- <h2 class="result-text">No results for "{{ query }}".</h2>
- {% endif %}
-
- <div class="results">
- {% for title in titles %}
- <a class="result" href="{{ url_for('title_view', title_id=title['id'], site=title['site']) }}"
- title="{{ title['name'] }}">
- <img src="{{ title['thumbnail'] }}" alt="{{ title['name'] }}">
- <span>{{ title['name'] | truncate(50) }}</span>
- </a>
- {% endfor %}
- </div>
-</div>
-{% endfor %}
-{% endif %}
-
-
-{% endblock %}
diff --git a/src/pytaku/templates/old/title.html b/src/pytaku/templates/old/title.html
deleted file mode 100644
index d751de7..0000000
--- a/src/pytaku/templates/old/title.html
+++ /dev/null
@@ -1,83 +0,0 @@
-{% extends 'base.html' %}
-
-{% block head %}
-<meta property="og:title" content="{{ name }}" />
-<meta property="og:image" content="{{ cover }}" />
-<meta property="og:description" content="{{ descriptions | join('\n') or '(no description)' }}" />
-
-<style>
- .cover {
- width: 400px;
- border: 1px solid black;
- }
-
- .details > form {
- display: inline-block;
- }
-</style>
-{% endblock %}
-
-{% block title %}
-{{ name }}
-{% endblock %}
-
-{% block content %}
-
-<div class="details">
- <h1>{{ name }}</h1>
- {% if session['user'] %}
- {% if is_following %}
- {% set fview = 'unfollow_view' %}
- {% set ftext = 'Following' %}
- {% set fcolor = 'red' %}
- {% set ftitle = 'Click to unfollow' %}
- {% else %}
- {% set fview = 'follow_view' %}
- {% set ftext = 'Follow' %}
- {% set fcolor = 'green' %}
- {% set ftitle = 'Click to follow' %}
- {% endif %}
- <form action="{{ url_for(fview, site=site, title_id=id) }}" method="POST">
- {{ ibutton(left_icon='bookmark', text=ftext, color=fcolor, title=ftitle) }}
- </form>
- {% endif %}
- {{ ibutton(href=source_url, right_icon='arrow-up-right', text=site|capitalize, color='blue', title='Go to source site') }}
-</div>
-
-<img class="cover" src="{{ cover }}" alt="cover" />
-{% for desc in descriptions %}
-<p class="description">{{ desc }}</p>
-{% endfor %}
-
-{% if chapters %}
-<table>
- <tr>
- {% if session['user'] %}<th>Done</th>{% endif %}
- <th>Name</th>
- <th>Group</th>
- </tr>
- {% for chapter in chapters %}
- <tr>
- {% if session['user'] %}
- <td>
- {% if chapter['is_read'] %}
- {{ ibutton(href='?unread=' + chapter['id'], text='✓', color='green', title='Click to unread') }}
- {% endif %}
- </td>
- {% endif %}
- <td>
- <a href="{{ url_for('chapter_view', chapter_id=chapter['id'], title_id=id, site=site) }}">
- Chapter {{ chapter['number'] }}
- {% if chapter['volume'] %}Volume {{ chapter['volume'] }} {% endif %}
- {% if chapter['name'] %}- {{ chapter['name'] }} {% endif %}
- </a>
- </td>
- <td>{{ ', '.join(chapter['groups']) }}</td>
- </tr>
- {% endfor %}
-</table>
-{% else %}
-<p>This one has no chapters.</p>
-{% endif %}
-
-{% endblock %}