Merge branch 'develop' into talker_settings_generator

# Conflicts:
#	comictaggerlib/settingswindow.py
#	comictalker/talkers/comicvine.py
This commit is contained in:
Mizaki 2023-02-21 00:50:06 +00:00
commit 33ea8da5bc
56 changed files with 342 additions and 134 deletions

43
.github/workflows/contributions.yaml vendored Normal file
View File

@ -0,0 +1,43 @@
name: Contributions
on:
push:
branches:
- 'develop'
tags-ignore:
- '**'
jobs:
contrib-readme-job:
permissions:
contents: write
runs-on: ubuntu-latest
env:
CI_COMMIT_AUTHOR: github-actions[bot]
CI_COMMIT_EMAIL: <41898282+github-actions[bot]@users.noreply.github.com>
CI_COMMIT_MESSAGE: Update AUTHORS
name: A job to automate contrib in readme
steps:
- name: Contribute List
uses: akhilmhdh/contributors-readme-action@v2.3.6
with:
use_username: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Update AUTHORS
run: |
git config --global log.mailmap true
git log --reverse '--format=%aN <%aE>' | cat -n | sort -uk2 | sort -n | cut -f2- >AUTHORS
- name: Commit and push AUTHORS
run: |
if ! git diff --exit-code; then
git pull
git config --global user.name "${{ env.CI_COMMIT_AUTHOR }}"
git config --global user.email "${{ env.CI_COMMIT_EMAIL }}"
git commit -a -m "${{ env.CI_COMMIT_MESSAGE }}"
git push
fi

9
.mailmap Normal file
View File

@ -0,0 +1,9 @@
Andrew W. Buchanan <buchanan@difference.com>
Davide Romanini <d.romanini@cineca.it> <davide.romanini@gmail.com>
Davide Romanini <d.romanini@cineca.it> <user159033@92-63-141-211.rdns.melbourne.co.uk>
Michael Fitzurka <MichaelFitzurka@users.noreply.github.com> <MichaelFitzurka@github.com>
Timmy Welch <timmy@narnian.us>
beville <beville@users.noreply.github.com> <(no author)@6c5673fe-1810-88d6-992b-cd32ca31540c>
beville <beville@users.noreply.github.com> <beville@6c5673fe-1810-88d6-992b-cd32ca31540c>
beville <beville@users.noreply.github.com> <beville@gmail.com@6c5673fe-1810-88d6-992b-cd32ca31540c>
beville <beville@users.noreply.github.com> <beville@users.noreply.github.com>

15
AUTHORS Normal file
View File

@ -0,0 +1,15 @@
beville <beville@users.noreply.github.com>
Davide Romanini <d.romanini@cineca.it>
fcanc <f.canc@icloud.com>
Alban Seurat <alkpone@alkpone.com>
tlc <tlc@users.noreply.github.com>
Marek Pawlak <francuz14@gmail.com>
Timmy Welch <timmy@narnian.us>
J.P. Cranford <philipcranford4@gmail.com>
thFrgttn <39759781+thFrgttn@users.noreply.github.com>
Andrew W. Buchanan <buchanan@difference.com>
Michael Fitzurka <MichaelFitzurka@users.noreply.github.com>
Richard Haussmann <richard.haussmann@gmail.com>
Mizaki <jinxybob@hotmail.com>
Xavier Jouvenot <x.jouvenot@gmail.com>
github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

109
README.md
View File

@ -61,3 +61,112 @@ choco install comictagger
2. Clone this repository `git clone https://github.com/comictagger/comictagger.git`
3. `pip3 install -r requirements_dev.txt`
7. `pip3 install .` or `pip3 install .[GUI]`
## Contributors
<!-- readme: beville,davide-romanini,collaborators,contributors -start -->
<table>
<tr>
<td align="center">
<a href="https://github.com/beville">
<img src="https://avatars.githubusercontent.com/u/7294848?v=4" width="100;" alt="beville"/>
<br />
<sub><b>beville</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/davide-romanini">
<img src="https://avatars.githubusercontent.com/u/731199?v=4" width="100;" alt="davide-romanini"/>
<br />
<sub><b>davide-romanini</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/mizaki">
<img src="https://avatars.githubusercontent.com/u/1141189?v=4" width="100;" alt="mizaki"/>
<br />
<sub><b>mizaki</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/lordwelch">
<img src="https://avatars.githubusercontent.com/u/7547075?v=4" width="100;" alt="lordwelch"/>
<br />
<sub><b>lordwelch</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/MichaelFitzurka">
<img src="https://avatars.githubusercontent.com/u/27830765?v=4" width="100;" alt="MichaelFitzurka"/>
<br />
<sub><b>MichaelFitzurka</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/fcanc">
<img src="https://avatars.githubusercontent.com/u/4999486?v=4" width="100;" alt="fcanc"/>
<br />
<sub><b>fcanc</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/abuchanan920">
<img src="https://avatars.githubusercontent.com/u/368793?v=4" width="100;" alt="abuchanan920"/>
<br />
<sub><b>abuchanan920</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/AlbanSeurat">
<img src="https://avatars.githubusercontent.com/u/500180?v=4" width="100;" alt="AlbanSeurat"/>
<br />
<sub><b>AlbanSeurat</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/rhaussmann">
<img src="https://avatars.githubusercontent.com/u/7084007?v=4" width="100;" alt="rhaussmann"/>
<br />
<sub><b>rhaussmann</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/jpcranford">
<img src="https://avatars.githubusercontent.com/u/21347202?v=4" width="100;" alt="jpcranford"/>
<br />
<sub><b>jpcranford</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/PawlakMarek">
<img src="https://avatars.githubusercontent.com/u/26022173?v=4" width="100;" alt="PawlakMarek"/>
<br />
<sub><b>PawlakMarek</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Xav83">
<img src="https://avatars.githubusercontent.com/u/6787157?v=4" width="100;" alt="Xav83"/>
<br />
<sub><b>Xav83</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/thFrgttn">
<img src="https://avatars.githubusercontent.com/u/39759781?v=4" width="100;" alt="thFrgttn"/>
<br />
<sub><b>thFrgttn</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/tlc">
<img src="https://avatars.githubusercontent.com/u/19436?v=4" width="100;" alt="tlc"/>
<br />
<sub><b>tlc</b></sub>
</a>
</td></tr>
</table>
<!-- readme: beville,davide-romanini,collaborators,contributors -end -->

View File

@ -1,6 +1,6 @@
"""A class to encapsulate CoMet data"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
"""A class to represent a single comic, be it file or folder of images"""
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
"""A class to encapsulate the ComicBookInfo data"""
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
"""A class to encapsulate ComicRack's ComicInfo.xml data"""
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -2,7 +2,7 @@
This should probably be re-written, but, well, it mostly works!
"""
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -5,7 +5,7 @@ tagging schemes and databases, such as ComicVine or GCD. This makes conversion
possible, however lossy it might be
"""
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -4,7 +4,7 @@ Class for handling the odd permutations of an 'issue number' that the
comics industry throws at us.
e.g.: "12", "12.1", "0", "-1", "5AU", "100-2"
"""
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
"""Some generic utilities"""
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,7 +1,7 @@
from __future__ import annotations
from PyInstaller.utils.hooks import collect_data_files
from PyInstaller.utils.hooks import collect_data_files, collect_entry_point
datas = []
datas, hiddenimports = collect_entry_point("comictagger.talker")
datas += collect_data_files("comictaggerlib.ui")
datas += collect_data_files("comictaggerlib.graphics")

View File

@ -1,6 +1,6 @@
"""A PyQT4 dialog to select from automated issue matches"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A PyQT4 dialog to show ID log and progress"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A PyQT4 dialog to confirm and set config for auto-tag"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A class to manage modifying metadata specifically for CBL/CBI"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,7 +1,7 @@
#!/usr/bin/python
"""ComicTagger CLI functions"""
#
# Copyright 2013 Anthony Beville
# Copyright 2013 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -4,7 +4,7 @@ Display cover images from either a local archive, or from Comic Vine.
TODO: This should be re-factored using subclasses!
"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A PyQT4 dialog to edit credits"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""CLI settings for ComicTagger"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -236,7 +236,7 @@ def register_commands(parser: settngs.Manager) -> None:
def register_commandline_settings(parser: settngs.Manager) -> None:
parser.add_group("commands", register_commands, True)
parser.add_group("runtime", register_settings)
parser.add_persistent_group("runtime", register_settings)
def validate_commandline_settings(

View File

@ -12,23 +12,39 @@ logger = logging.getLogger("comictagger")
def archiver(manager: settngs.Manager) -> None:
exe_registered: set[str] = set()
for archiver in comicapi.comicarchive.archivers:
if archiver.exe and archiver.exe not in exe_registered:
if archiver.exe:
# add_setting will overwrite anything with the same name.
# So we only end up with one option even if multiple archivers use the same exe.
manager.add_setting(
f"--{archiver.exe.replace(' ', '-').replace('_', '-').strip().strip('-')}",
f"--{settngs.sanitize_name(archiver.exe)}",
default=archiver.exe,
help="Path to the %(default)s executable\n\n",
)
exe_registered.add(archiver.exe)
def register_talker_settings(manager: settngs.Manager) -> None:
for talker_name, talker in comictaggerlib.ctsettings.talkers.items():
for talker_id, talker in comictaggerlib.ctsettings.talkers.items():
def api_options(manager: settngs.Manager) -> None:
manager.add_setting(
f"--{talker_id}-key",
default="",
display_name="API Key",
help=f"API Key for {talker.name} (default: {talker.default_api_key})",
)
manager.add_setting(
f"--{talker_id}-url",
default="",
display_name="URL",
help=f"URL for {talker.name} (default: {talker.default_api_url})",
)
try:
manager.add_persistent_group("talker_" + talker_name, talker.register_settings, False)
manager.add_persistent_group("talker_" + talker_id, api_options, False)
manager.add_persistent_group("talker_" + talker_id, talker.register_settings, False)
except Exception:
logger.exception("Failed to register settings for %s", talker_name)
logger.exception("Failed to register settings for %s", talker_id)
def validate_archive_settings(config: settngs.Config[settngs.Namespace]) -> settngs.Config[settngs.Namespace]:
@ -37,11 +53,7 @@ def validate_archive_settings(config: settngs.Config[settngs.Namespace]) -> sett
cfg = settngs.normalize_config(config, file=True, cmdline=True, defaults=False)
for archiver in comicapi.comicarchive.archivers:
exe_name = settngs.sanitize_name(archiver.exe)
if (
exe_name in cfg[0]["archiver"]
and cfg[0]["archiver"][exe_name]
and cfg[0]["archiver"][exe_name] != archiver.exe
):
if exe_name in cfg[0]["archiver"] and cfg[0]["archiver"][exe_name]:
if os.path.basename(cfg[0]["archiver"][exe_name]) == archiver.exe:
comicapi.utils.add_to_path(os.path.dirname(cfg[0]["archiver"][exe_name]))
else:
@ -53,15 +65,15 @@ def validate_archive_settings(config: settngs.Config[settngs.Namespace]) -> sett
def validate_talker_settings(config: settngs.Config[settngs.Namespace]) -> settngs.Config[settngs.Namespace]:
# Apply talker settings from config file
cfg = settngs.normalize_config(config, True, True)
for talker_name, talker in list(comictaggerlib.ctsettings.talkers.items()):
for talker_id, talker in list(comictaggerlib.ctsettings.talkers.items()):
try:
talker.parse_settings(cfg[0]["talker_" + talker_name])
cfg[0]["talker_" + talker_id] = talker.parse_settings(cfg[0]["talker_" + talker_id])
except Exception as e:
# Remove talker as we failed to apply the settings
del comictaggerlib.ctsettings.talkers[talker_name]
del comictaggerlib.ctsettings.talkers[talker_id]
logger.exception("Failed to initialize talker settings: %s", e)
return config
return settngs.get_namespace(cfg)
def validate_plugin_settings(config: settngs.Config[settngs.Namespace]) -> settngs.Config[settngs.Namespace]:

View File

@ -1,6 +1,6 @@
"""A PyQT4 dialog to confirm and set options for export to zip"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""Functions for renaming files based on metadata"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A PyQt5 widget for managing list of comic archive files"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A class to manage fetching and caching of images by URL"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A class to manage creating image content hashes, and calculate hamming distances"""
#
# Copyright 2013 Anthony Beville
# Copyright 2013 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A PyQT4 widget to display a popup image"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A class to automatically identify a comic archive"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A PyQT4 dialog to select specific issue from list"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A PyQT4 dialog to a text file or log"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A python app to (automatically) tag comic archives"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -119,6 +119,15 @@ class App:
# config already loaded
error = None
talkers = ctsettings.talkers
del ctsettings.talkers
if len(talkers) < 1:
error = error = (
f"Failed to load any talkers, please re-install and check the log located in '{self.config[0].runtime_config.user_log_dir}' for more details",
True,
)
signal.signal(signal.SIGINT, signal.SIG_DFL)
logger.debug("Installed Packages")
@ -134,7 +143,10 @@ class App:
# manage the CV API key
# None comparison is used so that the empty string can unset the value
if self.config[0].talker_comicvine_cv_api_key is not None or self.config[0].talker_comicvine_cv_url is not None:
if not error and (
self.config[0].talker_comicvine_comicvine_key is not None
or self.config[0].talker_comicvine_comicvine_url is not None
):
settings_path = self.config[0].runtime_config.user_config_dir / "settings.json"
if self.config_load_success:
self.manager.save_file(self.config[0], settings_path)
@ -150,9 +162,6 @@ class App:
True,
)
talkers = ctsettings.talkers
del ctsettings.talkers
if self.config[0].runtime_no_gui:
if error and error[1]:
print(f"A fatal error occurred please check the log for more information: {error[0]}") # noqa: T201

View File

@ -1,6 +1,6 @@
"""A PyQT4 dialog to select from automated issue matches"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -11,7 +11,7 @@ said_yes, checked = OptionalMessageDialog.question(self, "QtWidgets.Question",
)
"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A PyQT4 dialog to show pages of a comic archive"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A PyQt5 widget for editing the page list info"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A PyQT4 class to load a page image from a ComicArchive in a background thread"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A PyQt5 dialog to show ID log and progress"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A PyQT4 dialog to confirm rename"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A PyQT4 dialog to select specific series/volume from list"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""A PyQT4 dialog to enter app settings"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""The main window of the ComicTagger app"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
"""Version checker"""
#
# Copyright 2013 Anthony Beville
# Copyright 2013 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -2,8 +2,13 @@ from __future__ import annotations
import logging
import pathlib
import sys
if sys.version_info < (3, 10):
from importlib_metadata import entry_points
else:
from importlib.metadata import entry_points
import comictalker.talkers.comicvine
from comictalker.comictalker import ComicTalker, TalkerError
from comictalker.resulttypes import ComicIssue, ComicSeries
@ -21,11 +26,16 @@ def get_talkers(version: str, cache: pathlib.Path) -> dict[str, ComicTalker]:
"""Returns all comic talker instances"""
talkers: dict[str, ComicTalker] = {}
for talker in [comictalker.talkers.comicvine.ComicVineTalker]:
for talker in entry_points(group="comictagger.talker"):
try:
obj = talker(version, cache)
talkers[obj.id] = obj
talker_cls = talker.load()
obj = talker_cls(version, cache)
if obj.id != talker.name:
logger.error("Talker ID must be the same as the entry point name")
continue
talkers[talker.name] = obj
except Exception:
logger.exception("Failed to load talker: %s", "comicvine")
raise TalkerError(source="comicvine", code=4, desc="Failed to initialise talker")
logger.exception("Failed to load talker: %s", talker.name)
return talkers

View File

@ -1,6 +1,6 @@
"""A python class to manage caching of data from Comic Vine"""
#
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License;
# you may not use this file except in compliance with the License.
@ -378,7 +378,12 @@ class ComicCacher:
)
# now process the results
credits = []
try:
for credit in json.loads(row[13]):
credits.append(Credit(**credit))
except Exception:
logger.exception("credits failed")
record = ComicIssue(
id=row[1],
name=row[2],
@ -392,7 +397,7 @@ class ComicCacher:
alt_image_urls=row[10].strip().splitlines(),
characters=row[11].strip().splitlines(),
locations=row[12].strip().splitlines(),
credits=json.loads(row[13]),
credits=credits,
teams=row[14].strip().splitlines(),
story_arcs=row[15].strip().splitlines(),
complete=bool(row[16]),

View File

@ -1,4 +1,4 @@
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -21,6 +21,7 @@ import settngs
from comicapi.genericmetadata import GenericMetadata
from comictalker.resulttypes import ComicIssue, ComicSeries
from comictalker.talker_utils import fix_url
logger = logging.getLogger(__name__)
@ -107,15 +108,15 @@ class ComicTalker:
name: str = "Example"
id: str = "example"
logo_url: str = "https://example.com/logo.png"
website: str = "https://example.com/"
website: str = "https://example.com"
logo_url: str = f"{website}/logo.png"
attribution: str = f"Metadata provided by <a href='{website}'>{name}</a>"
def __init__(self, version: str, cache_folder: pathlib.Path) -> None:
self.cache_folder = cache_folder
self.version = version
self.api_key: str = ""
self.api_url: str = ""
self.api_key = self.default_api_key = ""
self.api_url = self.default_api_url = ""
def register_settings(self, parser: settngs.Manager) -> None:
"""
@ -129,6 +130,15 @@ class ComicTalker:
settings is a dictionary of settings defined in register_settings.
It is only guaranteed that the settings defined in register_settings will be present.
"""
if settings[f"{self.id}_key"]:
self.api_key = settings[f"{self.id}_key"]
if settings[f"{self.id}_url"]:
self.api_url = fix_url(settings[f"{self.id}_url"])
if self.api_key == "":
self.api_key = self.default_api_key
if self.api_url == "":
self.api_url = self.default_api_url
return settings
def check_api_key(self, key: str) -> bool:

View File

@ -1,4 +1,4 @@
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -15,6 +15,7 @@ from __future__ import annotations
import logging
import re
from urllib.parse import urlsplit
from bs4 import BeautifulSoup
@ -26,6 +27,14 @@ from comictalker.resulttypes import ComicIssue
logger = logging.getLogger(__name__)
def fix_url(url: str) -> str:
tmp_url = urlsplit(url)
# joinurl only works properly if there is a trailing slash
if tmp_url.path and tmp_url.path[-1] != "/":
tmp_url = tmp_url._replace(path=tmp_url.path + "/")
return tmp_url.geturl()
def map_comic_issue_to_metadata(
issue_results: ComicIssue, source: str, remove_html_tables: bool = False, use_year_volume: bool = False
) -> GenericMetadata:

View File

@ -1,7 +1,7 @@
"""
ComicVine information source
"""
# Copyright 2012-2014 Anthony Beville
# Copyright 2012-2014 ComicTagger Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -22,7 +22,7 @@ import logging
import pathlib
import time
from typing import Any, Callable, Generic, TypeVar
from urllib.parse import urljoin, urlsplit
from urllib.parse import urljoin
import requests
import settngs
@ -156,27 +156,19 @@ CV_STATUS_RATELIMIT = 107
class ComicVineTalker(ComicTalker):
name: str = "Comic Vine"
id: str = "comicvine"
logo_url: str = "https://comicvine.gamespot.com/a/bundles/comicvinesite/images/logo.png"
website: str = "https://comicvine.gamespot.com/"
website: str = "https://comicvine.gamespot.com"
logo_url: str = f"{website}/a/bundles/comicvinesite/images/logo.png"
attribution: str = f"Metadata provided by <a href='{website}'>{name}</a>"
def __init__(self, version: str, cache_folder: pathlib.Path):
super().__init__(version, cache_folder)
# Default settings
self.api_url: str = "https://comicvine.gamespot.com/api"
self.api_key: str = "27431e6787042105bd3e47e169a624521f89f3a4"
self.default_api_url = self.api_url = f"{self.website}/api/"
self.default_api_key = self.api_key = "27431e6787042105bd3e47e169a624521f89f3a4"
self.remove_html_tables: bool = False
self.use_series_start_as_volume: bool = False
self.wait_on_ratelimit: bool = False
tmp_url = urlsplit(self.api_url)
# joinurl only works properly if there is a trailing slash
if tmp_url.path and tmp_url.path[-1] != "/":
tmp_url = tmp_url._replace(path=tmp_url.path + "/")
self.api_url = tmp_url.geturl()
# NOTE: This was hardcoded before which is why it isn't in settings
self.wait_on_ratelimit_time: int = 20
@ -202,34 +194,39 @@ class ComicVineTalker(ComicTalker):
display_name="Remove HTML tables",
help="Removes html tables instead of converting them to text",
)
parser.add_setting("--cv-api-key", display_name="API Key", help="Use the given Comic Vine API Key")
parser.add_setting("--cv-url", display_name="URL", help="Use the given Comic Vine URL")
# The empty string being the default allows this setting to be unset, allowing the default to change
parser.add_setting(
f"--{self.id}-key",
default="",
display_name="API Key",
help=f"Use the given Comic Vine API Key. (default: {self.default_api_key})",
)
parser.add_setting(
f"--{self.id}-url",
default="",
display_name="API URL",
help=f"Use the given Comic Vine URL. (default: {self.default_api_url})",
)
def parse_settings(self, settings: dict[str, Any]) -> dict[str, Any]:
if settings["cv_api_key"]:
self.api_key = settings["cv_api_key"]
if settings["cv_url"]:
tmp_url = urlsplit(settings["cv_url"])
# joinurl only works properly if there is a trailing slash
if tmp_url.path and tmp_url.path[-1] != "/":
tmp_url = tmp_url._replace(path=tmp_url.path + "/")
self.api_url = tmp_url.geturl()
settings = super().parse_settings(settings)
self.use_series_start_as_volume = settings["cv_use_series_start_as_volume"]
self.wait_on_ratelimit = settings["cv_wait_on_ratelimit"]
self.remove_html_tables = settings["cv_remove_html_tables"]
return settngs
return settings
def check_api_key(self, key: str) -> bool:
url = self.api_url
def check_api_key(self, key: str, url: str) -> bool:
url = talker_utils.fix_url(url)
if not url:
url = self.default_api_url
try:
test_url = urljoin(url, "issue/1/")
cv_response: CVResult = requests.get(
test_url,
headers={"user-agent": "comictagger/" + self.version},
params={"api_key": key, "format": "json", "field_list": "name"},
params={"api_key": key or self.default_api_key, "format": "json", "field_list": "name"},
).json()
# Bogus request, but if the key is wrong, you get error 100: "Invalid API Key"
@ -237,27 +234,6 @@ class ComicVineTalker(ComicTalker):
except Exception:
return False
def check_api_url(self, url: str) -> bool:
if not url:
url = self.api_url
try:
tmp_url = urlsplit(url)
if tmp_url.path and tmp_url.path[-1] != "/":
tmp_url = tmp_url._replace(path=tmp_url.path + "/")
url = tmp_url.geturl()
test_url = urljoin(url, "issue/1/")
cv_response: CVResult = requests.get(
test_url,
headers={"user-agent": "comictagger/" + self.version},
params={"api_key": self.api_key, "format": "json", "field_list": "name"},
).json()
# Bogus request, but if the url is correct, you get error 102: "Error in URL Format"
return cv_response["status_code"] == 102
except Exception:
return False
def search_for_series(
self,
series_name: str,

View File

@ -1,7 +1,7 @@
#!/usr/bin/python
"""Print out a line-by-line list of basic tag info from all comics"""
# Copyright 2012 Anthony Beville
# Copyright 2012 ComicTagger Authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -4,7 +4,7 @@ Make some tree structures and symbolic links to comic files based on metadata
organizing by date and series, in different trees
"""
# Copyright 2012 Anthony Beville
# Copyright 2012 ComicTagger Authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,9 +1,7 @@
#!/usr/bin/python
"""Moves comic files based on metadata organizing in a tree by Publisher/Series (Volume)"""
# This script is based on make_links.py by Anthony Beville
# Copyright 2015 Fabio Cancedda, Anthony Beville
# Copyright 2015 ComicTagger Authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,7 +1,7 @@
#!/usr/bin/python
"""Fix the comic file names using a list of transforms"""
# Copyright 2013 Anthony Beville
# Copyright 2013 ComicTagger Authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -5,7 +5,7 @@ and deleted. Walks recursively through the given folders. Originals
are kept in a sub-folder at the level of the original
"""
# Copyright 2013 Anthony Beville
# Copyright 2013 ComicTagger Authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,7 +1,7 @@
#!/usr/bin/python
"""Reduce the image size of pages in the comic archive"""
# Copyright 2013 Anthony Beville
# Copyright 2013 ComicTagger Authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -2,7 +2,7 @@
"""Test archive cover against Comic Vine for a given issue ID
"""
# Copyright 2013 Anthony Beville
# Copyright 2013 ComicTagger Authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -66,6 +66,9 @@ setup(
"rar = comicapi.archivers.rar:RarArchiver",
"folder = comicapi.archivers.folder:FolderArchiver",
],
"comictagger.talker": [
"comicvine = comictalker.talkers.comicvine:ComicVineTalker",
],
},
classifiers=[
"Development Status :: 4 - Beta",