...
 
Commits (3)

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

......@@ -139,13 +139,14 @@ class Checker:
print("{}{}{}{}".format(Back.RED, Fore.BLACK, text, Style.RESET_ALL))
return False
def warn(self, text: str):
def warn(self, text: str) -> bool:
"""
Prints a black-on-yellow warning message
:param text: The text to print
:return: None
:return: True if not showing warnings, else False
"""
if self.show_warnings:
print("{}{}{}{}".format(
Back.YELLOW, Fore.BLACK, text, Style.RESET_ALL
))
return not self.show_warnings
......@@ -43,6 +43,24 @@ class VisualNovelChecker(Checker):
return valid
def _check_icons(self) -> bool:
"""
Only checks for a main.png icon file.
:return: The result of the check
"""
valid = True
if not os.path.isdir(self.metadata.icon_directory):
valid = self.error("Missing icon directory")
main_icon = os.path.join(self.metadata.icon_directory, "main.png")
if not os.path.isfile(main_icon):
valid = self.error("Missing main icon file for {}".format(
self.metadata.name
))
return valid
def _check_gamefiles(self) -> bool:
"""
Checks if the visual novel has a runscript and game files
......
......@@ -50,6 +50,9 @@ class Manga(Metadata):
json_data["special_chapters"] = []
series = Manga(directory_path, json_data)
if not os.path.isdir(series.main_path):
os.makedirs(series.main_path)
if os.path.isdir(series.special_path):
print("Please enter identifiers for special chapters:")
for _file in sorted(os.listdir(series.special_path)):
......
......@@ -19,6 +19,8 @@ LICENSE"""
import os
import json
import logging
import tvdb_api
from typing import List, Dict, Any, Optional
from toktokkie.exceptions import InvalidMetadata, MissingMetadata
from toktokkie.metadata.components.enums import MediaType, IdType
......@@ -36,7 +38,8 @@ class Metadata:
def __init__(
self,
directory_path: str,
json_data: Optional[Dict[str, Any]] = None
json_data: Optional[Dict[str, Any]] = None,
no_validation: bool = False
):
"""
Inititalizes the metadata object using JSON data
......@@ -45,12 +48,14 @@ class Metadata:
:param json_data: Optional metadata JSON.
Will be used instead of info.json metadata
if provided
:param no_validation: Skips JSON validation if True
:raises InvalidMetadataException: if the metadata could not be
parsed correctly
"""
self.directory_path = directory_path
self.metadata_file = os.path.join(directory_path, ".meta/info.json")
self.icon_directory = os.path.join(directory_path, ".meta/icons")
self.logger = logging.getLogger(self.__class__.__name__)
if json_data is None:
with open(self.metadata_file, "r") as info:
......@@ -58,7 +63,8 @@ class Metadata:
else:
self.json = json_data
self.validate_json()
if not no_validation:
self.validate_json()
def __str__(self) -> str:
"""
......@@ -301,8 +307,19 @@ class Metadata:
json_data = {
"type": cls.media_type().value,
"tags": prompt_comma_list("Tags: "),
"ids": cls.prompt_for_ids()
}
defaults = {} # type: Dict[str, List[str]]
if IdType.TVDB in cls.valid_id_types():
try:
name = os.path.basename(os.path.abspath(directory_path))
probable_tvdb_id = str(tvdb_api.Tvdb()[name].data["id"])
defaults[IdType.TVDB.value] = [probable_tvdb_id]
except (tvdb_api.tvdb_shownotfound, TypeError):
pass
json_data["ids"] = cls.prompt_for_ids(defaults=defaults)
json_data.update(cls._prompt(directory_path, json_data))
return cls(directory_path, json_data)
......@@ -402,7 +419,7 @@ class Metadata:
min_count = 1 if id_type in cls.required_ids() else 0
if id_type in [IdType.ISBN, IdType.IMDB]:
if id_type in [IdType.ISBN, IdType.IMDB, IdType.VNDB]:
prompted = prompt_comma_list(
"{} IDs: ".format(id_type.value),
min_count=min_count,
......
......@@ -18,8 +18,8 @@ along with toktokkie. If not, see <http://www.gnu.org/licenses/>.
LICENSE"""
import os
import tvdb_api
from typing import List, Dict, Any, Optional
from typing import List, Dict, Any, Tuple
from puffotter.os import listdir
from toktokkie.metadata.Metadata import Metadata
from toktokkie.metadata.components.TvSeason import TvSeason
from toktokkie.metadata.components.enums import IdType, MediaType
......@@ -51,36 +51,35 @@ class TvSeries(Metadata):
:param json_data: Previously generated JSON data
:return: The generated metadata JSON data
"""
name = os.path.basename(directory_path)
json_data["seasons"] = []
series = cls(directory_path, json_data, no_validation=True)
probable_defaults = None # type: Optional[Dict[str, List[str]]]
try:
probable_tvdb_id = str(tvdb_api.Tvdb()[name].data["id"])
probable_defaults = {IdType.TVDB.value: [probable_tvdb_id]}
except (tvdb_api.tvdb_shownotfound, TypeError):
pass
seasons = []
series_ids = cls.prompt_for_ids(
defaults=probable_defaults
)
series = cls(directory_path, {
"seasons": [],
"ids": series_ids,
"type": cls.media_type().value
})
# Make sure that regular Seasons are prompted first and in order
season_folders = [] # type: List[Tuple[str, str]]
special_folders = [] # type: List[Tuple[str, str]]
unsorted_folders = listdir(directory_path, no_files=True)
seasons = []
for season_name in sorted(os.listdir(directory_path)):
for folder, folder_path in unsorted_folders:
if folder.startswith("Season "):
try:
int(folder.split("Season ")[1])
season_folders.append((folder, folder_path))
except (ValueError, IndexError):
special_folders.append((folder, folder_path))
else:
special_folders.append((folder, folder_path))
season_path = os.path.join(directory_path, season_name)
if season_name.startswith(".") or not os.path.isdir(season_path):
continue
season_folders.sort(key=lambda x: int(x[0].split("Season ")[1]))
for season_name, season_path in season_folders + special_folders:
print("\n{}:".format(season_name))
ids = cls.prompt_for_ids(series_ids)
ids = cls.prompt_for_ids(json_data["ids"])
# Remove double entries
for id_type, id_value in series_ids.items():
for id_type, id_value in json_data["ids"].items():
if id_value == ids.get(id_type, None):
ids.pop(id_type)
......@@ -90,6 +89,7 @@ class TvSeries(Metadata):
}))
series.seasons = seasons
series.validate_json()
return series.json
@property
......@@ -272,6 +272,12 @@ class TvSeries(Metadata):
"""
self._assert_true("seasons" in self.json)
self._assert_true(len(self.seasons) == len(self.json["seasons"]))
foldercount = len(listdir(self.directory_path, no_files=True))
print(foldercount)
print(self.seasons)
self._assert_true(len(self.seasons) == foldercount)
self._assert_true(
len(self.excludes) ==
len(self.json.get("excludes", []))
......
......@@ -53,6 +53,8 @@ class MetadataPart:
for _, ids in self.ids.items():
for _id in ids:
if not type(_id) == str:
print(type(_id))
print("AAAAAAAAAAAAAAAAAA")
raise InvalidMetadata()
@property
......
......@@ -78,26 +78,34 @@ class ArchiveCommand(Command):
:param dest: The destination directory
:return: None
"""
for child in os.listdir(source):
child_path = os.path.join(source, child)
dest_child_path = os.path.join(dest, child)
self.logger.info("{} -> {}".format(source, dest))
if os.path.isfile(child_path):
if os.path.basename(source) == ".wine": # Ignore .wine directories
return
if child_path.endswith(".json"):
shutil.copyfile(child_path, dest_child_path)
elif child_path.endswith(".png"):
if self.args.remove_icons:
try:
for child in os.listdir(source):
child_path = os.path.join(source, child)
dest_child_path = os.path.join(dest, child)
if os.path.isfile(child_path):
if child_path.endswith(".json"):
shutil.copyfile(child_path, dest_child_path)
elif child_path.endswith(".png"):
if self.args.remove_icons:
with open(dest_child_path, "w") as f:
f.write("")
else:
shutil.copyfile(child_path, dest_child_path)
else:
with open(dest_child_path, "w") as f:
f.write("")
else:
shutil.copyfile(child_path, dest_child_path)
else:
with open(dest_child_path, "w") as f:
f.write("")
elif os.path.isdir(child_path):
if not os.path.isdir(dest_child_path):
os.makedirs(dest_child_path)
elif os.path.isdir(child_path):
if not os.path.isdir(dest_child_path):
os.makedirs(dest_child_path)
self.archive(child_path, dest_child_path)
self.archive(child_path, dest_child_path)
except PermissionError:
pass
......@@ -94,8 +94,10 @@ class TestManga(_TestMetadata):
"""
showa = self.get("Shouwa Otome Otogibanashi")
os.makedirs(showa)
os.makedirs(os.path.join(showa, "Special"))
create_file(os.path.join(showa, "Special/Chap 5.5.cbz"))
with mock.patch("builtins.input", side_effect=[
"shouwa, romance, sequel", "", "", "106988", "", ""
"shouwa, romance, sequel", "", "", "106988", "", "", "5.5"
]):
metadata = Manga.prompt(showa)
metadata.write()
......@@ -110,6 +112,7 @@ class TestManga(_TestMetadata):
self.assertEqual(metadata.ids[IdType.KITSU], [])
self.assertEqual(metadata.ids[IdType.MANGADEX], [])
self.assertEqual(metadata.ids[IdType.ISBN], [])
self.assertEqual(metadata.special_chapters, ["5.5"])
for invalid in [IdType.VNDB, IdType.IMDB, IdType.TVDB]:
self.assertFalse(invalid in metadata.ids)
......@@ -117,6 +120,13 @@ class TestManga(_TestMetadata):
for tag in ["shouwa", "romance", "sequel"]:
self.assertTrue(tag in metadata.tags)
special_file = os.path.join(
showa, "Special/Shouwa Otome Otogibanashi - Chapter 5.5.cbz"
)
self.assertFalse(os.path.isfile(special_file))
directory.rename(noconfirm=True)
self.assertTrue(os.path.isfile(special_file))
def test_validation(self):
"""
Tests if the validation of metadata works correctly
......
......@@ -18,10 +18,12 @@ along with toktokkie. If not, see <http://www.gnu.org/licenses/>.
LICENSE"""
import os
import tvdb_api
from typing import List, Dict, Any
from unittest import mock
from puffotter.os import listdir
from toktokkie.Directory import Directory
from toktokkie.exceptions import InvalidMetadata
from toktokkie.metadata.TvSeries import TvSeries
from toktokkie.metadata.components.enums import IdType
from toktokkie.test.metadata.TestMetadata import _TestMetadata
......@@ -35,25 +37,123 @@ class TestTvSeries(_TestMetadata):
Tests renaming files associated with the metadata type
:return: None
"""
pass
otgw = self.get("Over the Garden Wall")
otgw_dir = Directory(otgw)
otgw_dir.rename(noconfirm=True)
correct = []
wrong = []
for _, season_dir in listdir(otgw):
for episode, episode_file in listdir(season_dir):
new_file = os.path.join(season_dir, "A" + episode)
os.rename(episode_file, new_file)
correct.append(episode_file)
wrong.append(new_file)
for _file in correct:
self.assertFalse(os.path.isfile(_file))
for _file in wrong:
self.assertTrue(os.path.isfile(_file))
otgw_dir.rename(noconfirm=True)
for _file in correct:
self.assertTrue(os.path.isfile(_file))
for _file in wrong:
self.assertFalse(os.path.isfile(_file))
otgw_dir.metadata.set_ids(IdType.ANILIST, ["19815"])
otgw_dir.rename(noconfirm=True)
self.assertEqual(otgw_dir.metadata.name, "No Game No Life")
for _file in correct:
self.assertFalse(os.path.isfile(_file))
def test_prompt(self):
"""
Tests generating a new metadata object using user prompts
:return: None
"""
pass
ngnl = self.get("No Game No Life")
os.makedirs(ngnl)
os.makedirs(os.path.join(ngnl, "Season 1"))
os.makedirs(os.path.join(ngnl, "Movie"))
with mock.patch("builtins.input", side_effect=[
"anime, no_second_season", "278155", "19815", "", "",
"", "", "", "",
"", "33674", "", ""
]):
metadata = TvSeries.prompt(ngnl)
metadata.write()
directory = Directory(ngnl)
self.assertTrue(os.path.isdir(directory.meta_dir))
self.assertTrue(os.path.isfile(metadata.metadata_file))
self.assertEqual(metadata, directory.metadata)
self.assertEqual(metadata.ids[IdType.TVDB], ["278155"])
self.assertEqual(metadata.ids[IdType.ANILIST], ["19815"])
self.assertEqual(metadata.ids[IdType.MYANIMELIST], ["19815"])
self.assertEqual(metadata.ids[IdType.KITSU], [])
season_one = metadata.get_season("Season 1")
movie = metadata.get_season("Movie")
self.assertEqual(season_one.ids[IdType.TVDB], ["278155"])
self.assertEqual(season_one.ids[IdType.ANILIST], ["19815"])
self.assertEqual(season_one.ids[IdType.MYANIMELIST], ["19815"])
self.assertEqual(season_one.ids[IdType.KITSU], [])
self.assertEqual(movie.ids[IdType.TVDB], ["278155"])
self.assertEqual(movie.ids[IdType.ANILIST], ["21875"])
self.assertEqual(movie.ids[IdType.MYANIMELIST], ["33674"])
self.assertEqual(movie.ids[IdType.KITSU], [])
for invalid in [
IdType.VNDB, IdType.MANGADEX, IdType.IMDB, IdType.ISBN
]:
self.assertFalse(invalid in metadata.ids)
for tag in ["anime", "no_second_season"]:
self.assertTrue(tag in metadata.tags)
def test_validation(self):
"""
Tests if the validation of metadata works correctly
:return: None
"""
pass
valid_data = [
{"type": "tv", "ids": {"tvdb": ["281643"]},
"seasons": [{"name": "Season 1", "ids": {}}]},
{"type": "tv", "ids": {"tvdb": "281643"},
"seasons": [{"name": "Season 1", "ids": {}}]},
]
invalid_data = [
{},
{"type": "tv", "ids": {"tvdb": ["281643"]},
"seasons": [{"name": "Season 2", "ids": {}}]},
{"type": "tv", "ids": {"tvdb": ["281643"]},
"seasons": []},
{"type": "tv", "ids": {"tvdb": ["281643"]}},
{"type": "tv", "seasons": [{"name": "Season 1", "ids": {}}]},
{"type": "movie", "ids": {"tvdb": ["281643"]},
"seasons": [{"name": "Season 1", "ids": {}}]},
{"type": "tv", "ids": {"tvdb": 281643},
"seasons": [{"name": "Season 1", "ids": {}}]},
{"type": "tv", "ids": {"tvdb": [281643]},
"seasons": [{"name": "Season 1", "ids": {}}]},
{"type": "tv", "ids": {"isbn": ["281643"]},
"seasons": [{"name": "Season 1", "ids": {}}]},
]
otgw = self.get("Over the Garden Wall")
self.check_validation(valid_data, invalid_data, TvSeries, otgw)
def test_checking(self):
"""
Tests if the checking mechanisms work correctly
:return: None
"""
pass
otgw = Directory(self.get("Over the Garden Wall"))
self.assertTrue(otgw.check(False, False, {}))
os.remove(os.path.join(otgw.meta_dir, "icons/main.png"))
self.assertFalse(otgw.check(False, False, {}))
......@@ -35,25 +35,63 @@ class TestVisualNovel(_TestMetadata):
Tests renaming files associated with the metadata type
:return: None
"""
pass
pass # Currently no renaming functionality implemented
def test_prompt(self):
"""
Tests generating a new metadata object using user prompts
:return: None
"""
pass
evangile = self.get("Princess Evangile")
os.makedirs(evangile)
with mock.patch("builtins.input", side_effect=[
"moege, school", "v6710"
]):
metadata = VisualNovel.prompt(evangile)
metadata.write()
directory = Directory(evangile)
self.assertTrue(os.path.isdir(directory.meta_dir))
self.assertTrue(os.path.isfile(metadata.metadata_file))
self.assertEqual(metadata, directory.metadata)
self.assertEqual(metadata.ids[IdType.VNDB], ["v6710"])
for id_type in IdType:
if id_type not in [IdType.VNDB]:
self.assertFalse(id_type in metadata.ids)