...
 
Commits (2)
......@@ -153,12 +153,23 @@ class Directory:
)
return checker.check()
def update(self, args: Dict[str, Any]):
def update(self, cli_args: Optional[Dict[str, Any]] = None):
"""
Performs an Update Action
:param args: Command line arguments used to configure the update
:param cli_args: Command line arguments used to configure the update
:return: None
"""
args = {
"dry_run": False,
"create": False,
"throttle": -1,
"timeout": 120,
"no_check_newest_chapter_length": False,
"skip_special": False
}
if cli_args is not None:
args.update(cli_args)
applicable_updaters = [
x for x in updaters
if self.metadata.media_type() in x.applicable_media_types()
......
......@@ -16,29 +16,3 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with toktokkie. If not, see <http://www.gnu.org/licenses/>.
LICENSE"""
import os
import json
from typing import List, Dict
from flask import render_template, Response, request, redirect, url_for
from puffotter.os import get_ext
from toktokkie.web import app, db
from toktokkie.Directory import Directory
from toktokkie.web.models.MediaLocation import MediaLocation
from toktokkie.web.models.CachedDirectory import CachedDirectory
from toktokkie.metadata.MediaType import MediaType
from toktokkie.metadata.functions import get_metadata_class
"""LICENSE
Copyright 2015 Hermann Krumrey <hermann@krumreyh.com>
This file is part of toktokkie.
toktokkie is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
toktokkie is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with toktokkie. If not, see <http://www.gnu.org/licenses/>.
LICENSE"""
import tvdb_api
from typing import Dict, Union, List, Tuple
def load_tvdb_series_info(tvdb_id: Union[str, int]) \
-> Dict[str, Union[str, List[Tuple[str, str]]]]:
"""
Loads TVDB data.
:return: None
"""
tvdb_data = tvdb_api.Tvdb()[int(tvdb_id)]
episodes = 0
for season_number in tvdb_data:
episodes += len(tvdb_data[season_number])
return {
"seasons": str(len(tvdb_data)),
"episodes": str(episodes),
"status": tvdb_data.data["status"],
"first_aired": tvdb_data.data["firstAired"],
"network": tvdb_data.data["network"],
"runtime": tvdb_data.data["runtime"],
"genres": ", ".join(tvdb_data.data["genre"]),
"rating": tvdb_data.data["rating"],
"synopsys": tvdb_data.data["overview"],
"order": [
("seasons", "Seasons"),
("episodes", "Episodes"),
("status", "Status"),
("first_aired", "First Aired"),
("network", "Network"),
("runtime", "Runtime"),
("genres", "Genres"),
("rating", "Rating")
]
}
......@@ -101,8 +101,8 @@ def load_tvdb_episode_name(
info = tvdb[int(tvdb_id)]
return info[season_number][episode_number]["episodeName"]
except (tvdb_episodenotfound, tvdb_seasonnotfound,
tvdb_shownotfound, ConnectionError, KeyError) as e:
except (tvdb_episodenotfound, tvdb_seasonnotfound, tvdb_shownotfound,
ConnectionError, KeyError, AttributeError) as e:
# If not found, or other error, just return generic name
if str(e) == "cache_location": # pragma: no cover
logging.getLogger(__name__).warning("TheTVDB.com is down!")
......
......@@ -20,9 +20,10 @@ LICENSE"""
import os
import argparse
import requests
from typing import List
from toktokkie.Directory import Directory
from puffotter.graphql import GraphQlClient
from puffotter.os import makedirs
from puffotter.os import makedirs, replace_illegal_ntfs_chars
from puffotter.prompt import prompt
from subprocess import Popen
from toktokkie.metadata.types.Manga import Manga
......@@ -60,6 +61,7 @@ class MangaCreateCommand(Command):
Executes the commands
:return: None
"""
titles = [] # type: List[str]
for anilist_id in self.args.anilist_ids:
client = GraphQlClient("https://graphql.anilist.co")
......@@ -83,6 +85,9 @@ class MangaCreateCommand(Command):
if title is None:
title = data["Media"]["title"]["romaji"]
title = replace_illegal_ntfs_chars(title)
titles.append(title)
makedirs(title)
makedirs(os.path.join(title, "Main"))
makedirs(os.path.join(title, ".meta/icons"))
......@@ -159,3 +164,7 @@ class MangaCreateCommand(Command):
"type": "manga"
})
metadata.write()
for title in titles:
directory = Directory(title)
directory.update()
......@@ -92,11 +92,11 @@ class MusicMergeCommand(Command):
target_map = {x.metadata.name: x for x in target_artists}
for source_artist in source_artists:
source_metadata = source_artist.metadata # type: MusicArtist
source_metadata = cast(MusicArtist, source_artist.metadata)
if source_metadata.name not in target_map:
new_path = os.path.join(
self.args.dest, source_metadata.name
self.args.target, source_metadata.name
)
shutil.copytree(source_artist.path, new_path)
if not self.args.keep:
......
......@@ -22,7 +22,7 @@ from toktokkie.web.run import run_web
from toktokkie.scripts.Command import Command
class WebStartCommand(Command):
class WebCommand(Command):
"""
Class that encapsulates behaviour of the web command
"""
......@@ -41,11 +41,12 @@ class WebStartCommand(Command):
:param parser: The parser to prepare
:return: None
"""
pass
parser.add_argument("--port", type=int, default=1234,
help="The port on which to run the web app")
def execute(self):
"""
Executes the commands
:return: None
"""
run_web()
run_web(port=self.args.port)
......@@ -34,7 +34,7 @@ from toktokkie.scripts.AlbumArtFetchCommand import AlbumArtFetchCommand
from toktokkie.scripts.MusicTagCommand import MusicTagCommand
from toktokkie.scripts.PlaylistCreateCommand import PlaylistCreateCommand
from toktokkie.scripts.MusicMergeCommand import MusicMergeCommand
from toktokkie.scripts.WebStartCommand import WebStartCommand
from toktokkie.scripts.WebCommand import WebCommand
toktokkie_commands = [
PrintCommand,
......@@ -54,7 +54,7 @@ toktokkie_commands = [
MusicTagCommand,
MusicMergeCommand,
PlaylistCreateCommand,
WebStartCommand
WebCommand
]
"""
A list of commands for the toktokkie script
......
......@@ -21,6 +21,8 @@ import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from puffotter.os import makedirs
from toktokkie.info.tvdb import load_tvdb_series_info
from toktokkie.metadata.ids.IdType import IdType
root_path = os.path.join(os.path.dirname(os.path.abspath(__file__)))
config_path = os.path.join(os.path.expanduser("~"), ".config/toktokkie")
......@@ -34,6 +36,11 @@ app.config["SQLALCHEMY_DATABASE_URI"] = sqlite_uri
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db.init_app(app)
app.jinja_env.globals.update(
load_tvdb_series_info=load_tvdb_series_info,
IdType=IdType
)
# noinspection PyUnresolvedReferences
def init_db():
......@@ -44,6 +51,7 @@ def init_db():
with app.app_context():
from toktokkie.web.models.MediaLocation import MediaLocation
from toktokkie.web.models.CachedDirectory import CachedDirectory
from toktokkie.web.models.CachedMedia import CachedMedia
db.create_all()
......
"""LICENSE
Copyright 2015 Hermann Krumrey <hermann@krumreyh.com>
This file is part of toktokkie.
toktokkie is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
toktokkie is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with toktokkie. If not, see <http://www.gnu.org/licenses/>.
LICENSE"""
from toktokkie.web import db
class CachedMedia(db.Model):
"""
Database table that stores a cached version of a media file
"""
__tablename__ = "cached_media"
"""
The table name
"""
id = db.Column(
db.Integer,
primary_key=True,
autoincrement=True,
nullable=False
)
"""
The ID of the cached media
"""
path = db.Column(
db.String(255),
unique=True,
nullable=False
)
"""
The path to the cached media file
"""
data = db.Column(db.BLOB, nullable=False)
"""
The media data
"""
format = db.Column(db.String(255), nullable=False)
"""
The media format
"""
media_type = db.Column(db.String(255), nullable=False)
"""
The type of media (video, image etc)
"""
@property
def mimetype(self) -> str:
"""
:return: The media mimetype
"""
return self.media_type + "/" + self.format
......@@ -18,9 +18,10 @@ along with toktokkie. If not, see <http://www.gnu.org/licenses/>.
LICENSE"""
import os
from flask import Response, request
from flask import Response, request, abort
from puffotter.os import get_ext
from toktokkie.web import app
from toktokkie.web import app, db
from toktokkie.web.models.CachedMedia import CachedMedia
@app.route("/image/<image_format>")
......@@ -29,11 +30,24 @@ def image(image_format: str) -> Response:
Sends an image file from the local file system
:return: A PNG image read from a local file
"""
path = request.args.get("path")
path = os.path.normpath(request.args.get("path"))
ext = get_ext(path)
cached = CachedMedia.query.filter_by(path=path).first()
if path is None or not os.path.isfile(path) or ext != image_format:
return Response(status=404)
abort(404)
else:
with open(path, "rb") as f:
return Response(f.read(), mimetype="image/" + image_format)
if cached is None:
with open(path, "rb") as f:
image_data = f.read()
cached = CachedMedia(
path=path,
data=image_data,
format=image_format,
media_type="image"
)
db.session.add(cached)
db.session.commit()
return Response(cached.data, mimetype=cached.mimetype)
......@@ -20,11 +20,12 @@ LICENSE"""
from toktokkie.web import app, init_routes, init_db
def run_web():
def run_web(port: int = 1234):
"""
Starts the web app using flask's built-in server
:param port: The port on which to run the server
:return: None
"""
init_db()
init_routes()
app.run(host="0.0.0.0", port=1234)
app.run(host="0.0.0.0", port=port)
body{
/*
Copyright 2015 Hermann Krumrey <hermann@krumreyh.com>
This file is part of toktokkie.
toktokkie is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
toktokkie is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with bundesliga-tippspiel. If not, see <http://www.gnu.org/licenses/>.
*/
body {
background: #EEEEEE;
line-height:1.6;
font-size:18px;
color:#444444;
}
h1,h2,h3{
h1, h2, h3 {
line-height:1.2
}
......
......@@ -26,27 +26,7 @@ along with bundesliga-tippspiel. If not, see <http://www.gnu.org/licenses/>.
{% if metadata.media_type().value == "tv" %}
<table class="alternating_table">
{% for season in metadata.seasons %}
{% set season_cover = "{}".format(metadata.get_icon_file(season.name)) %}
{% set season_cover_url = "{}?path={}".format(url_for("image", image_format="png"), season_cover) %}
<tr>
<td>
<img class="season_image" src="{{ season_cover_url }}" alt="{{ season.name }}">
</td>
<td>
<button type="button" class="collapsible"> ⮞ {{ season.name }}</button>
<table class="collapsible_content alternating_table">
{% for episode_name in season.episode_names %}
<tr>
<td>{{ episode_name }}</td>
</tr>
{% endfor %}
</table>
</td>
</tr>
{% endfor %}
</table>
{% include "directory_parts/tv.html" %}
{% endif %}
<table>
......
{#
Copyright 2015 Hermann Krumrey <hermann@krumreyh.com>
This file is part of toktokkie.
toktokkie is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
toktokkie is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with bundesliga-tippspiel. If not, see <http://www.gnu.org/licenses/>.
#}
<table>
{% if metadata.ids[IdType.TVDB]|length > 0 %}
{% set tvdb_info = load_tvdb_series_info(metadata.ids[IdType.TVDB][0]) %}
{% for key, label in tvdb_info["order"] %}
<tr>
<td>{{ label }}</td>
<td>{{ tvdb_info[key] }}</td>
</tr>
{% endfor %}
{% endif %}
</table>
{% if tvdb_info is defined %}
<p>{{ tvdb_info["synopsys"] }}</p>
{% endif %}
<table class="alternating_table">
{% for season in metadata.seasons %}
{% set season_cover = "{}".format(metadata.get_icon_file(season.name)) %}
{% set season_cover_url = "{}?path={}".format(url_for("image", image_format="png"), season_cover) %}
<tr>
<td>
<img class="season_image" src="{{ season_cover_url }}" alt="{{ season.name }}">
</td>
<td>
<button type="button" class="collapsible"> ⮞ {{ season.name }}</button>
<table class="collapsible_content alternating_table">
{% for episode_name in season.episode_names %}
<tr>
<td>{{ episode_name }}</td>
</tr>
{% endfor %}
</table>
</td>
</tr>
{% endfor %}
</table>
\ No newline at end of file