Compare commits
21 Commits
untagged-0
...
1.2.2
Author | SHA1 | Date | |
---|---|---|---|
d93cb50896 | |||
3316cab775 | |||
c01f00f6c3 | |||
06ff25550e | |||
1f7ef44556 | |||
fabf2b4df6 | |||
0fbaeb861e | |||
3dcc04a318 | |||
933e053df3 | |||
5f22a583e8 | |||
3174b49d94 | |||
93ce311359 | |||
bc43c5e329 | |||
9bf7aa20fb | |||
5416bb15c3 | |||
562a659195 | |||
1d3d6e2741 | |||
c9724527b5 | |||
2891209b4e | |||
5b87e19d3e | |||
674e24fc41 |
8
.gitignore
vendored
8
.gitignore
vendored
@ -3,4 +3,10 @@
|
||||
/dist
|
||||
*.pyc
|
||||
/.vscode
|
||||
venv
|
||||
venv
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
build/
|
||||
ctversion.py
|
||||
.eggs
|
42
.travis.yml
Normal file
42
.travis.yml
Normal file
@ -0,0 +1,42 @@
|
||||
language: python
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- /^\d+\.\d+\.\d+$/
|
||||
env:
|
||||
global:
|
||||
- PYTHON=python
|
||||
- PIP=pip
|
||||
- SETUPTOOLS_SCM_PRETEND_VERSION=$TRAVIS_TAG
|
||||
- MAKE=make
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
- os: osx
|
||||
language: generic
|
||||
osx_image: xcode8.3
|
||||
env: PYTHON=python3 PIP=pip3 MACOSX_DEPLOYMENT_TARGET=10.11
|
||||
- os: windows
|
||||
language: bash
|
||||
env: PATH=/C/Python37:/C/Python37/Scripts:$PATH MAKE=mingw32-make
|
||||
before_install:
|
||||
- if [ "$TRAVIS_OS_NAME" = "windows" ]; then choco install -y python mingw zip; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew upgrade python3 ; fi
|
||||
install:
|
||||
- $PIP install --upgrade setuptools
|
||||
- $PIP install -r requirements.txt
|
||||
script:
|
||||
- $MAKE dist
|
||||
|
||||
deploy:
|
||||
name: $TRAVIS_TAG
|
||||
body: Released ComicTagger $TRAVIS_TAG
|
||||
provider: releases
|
||||
skip_cleanup: true
|
||||
api_key:
|
||||
secure: RgohcOJOfLhXXT12bMWaLwOqhe+ClSCYXjYuUJuWK4/E1fdd1xu1ebdQU+MI/R8cZ0Efz3sr2n3NkO/Aa8gN68xEfuF7RVRMm64P9oPrfZgGdsD6H43rU/6kN8bgaDRmCYpLTfXaJ+/gq0x1QDkhWJuceF2BYEGGvL0BvS/TUsLyjVxs8ujTplLyguXHNEv4/7Yz7SBNZZmUHjBuq/y+l8ds3ra9rSgAVAN1tMXoFKJPv+SNNkpTo5WUNMPzBnN041F1rzqHwYDLog2V7Krp9JkXzheRFdAr51/tJBYzEd8AtYVdYvaIvoO6A4PiTZ7MpsmcZZPAWqLQU00UTm/PhT/LVR+7+f8lOBG07RgNNHB+edjDRz3TAuqyuZl9wURWTZKTPuO49TkZMz7Wm0DRNZHvBm1IXLeSG7Tll2YL1+WpZNZg+Dhro2J1QD3vxDXafhMdTCB4z0q5aKpG93IT0p6oXOO0oEGOPZYbA2c5R3SXWSyqd1E1gdhbVjIZr59h++TEf1zz07tvWHqPuAF/Ly/j+dIcY2wj0EzRWaSASWgUpTnMljAkHtWhqDw4GXGDRkRUWRJl1d0/JyVqCeIdRzDQNl8/q7BcO3F1zqr1PgnYdz0lfwWxL1/ekw2vHOJE/GOdkyvX0aJrnaOV338mjJbfGHYv4ESc9ow1kdtIbiU=
|
||||
file_glob: true
|
||||
file: dist/*.zip
|
||||
draft: true
|
||||
on:
|
||||
tags: true
|
13
Makefile
13
Makefile
@ -1,11 +1,14 @@
|
||||
VERSION_STR := $(shell python -c 'import comictaggerlib.ctversion; print( comictaggerlib.ctversion.version)')
|
||||
PIP ?= pip
|
||||
VERSION_STR := $(shell python setup.py --version)
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
OS_VERSION=win-$(PROCESSOR_ARCHITECTURE)
|
||||
APP_NAME=comictagger.exe
|
||||
FINAL_NAME=ComicTagger-$(VERSION_STR).exe
|
||||
FINAL_NAME=ComicTagger-$(VERSION_STR)-$(OS_VERSION).exe
|
||||
else ifeq ($(shell uname -s),Darwin)
|
||||
OS_VERSION=osx-$(shell defaults read loginwindow SystemVersionStampAsString)-$(shell uname -m)
|
||||
APP_NAME=ComicTagger.app
|
||||
FINAL_NAME=ComicTagger-$(VERSION_STR).app
|
||||
FINAL_NAME=ComicTagger-$(VERSION_STR)-$(OS_VERSION).app
|
||||
else
|
||||
APP_NAME=comictagger
|
||||
FINAL_NAME=ComicTagger-$(VERSION_STR)
|
||||
@ -28,6 +31,7 @@ clean:
|
||||
rm -f unrar/libunrar.so unrar/libunrar.a unrar/unrar
|
||||
rm -f comictaggerlib/libunrar.so
|
||||
rm -rf comictaggerlib/ui/__pycache__
|
||||
rm comitaggerlib/ctversion.py
|
||||
|
||||
pydist:
|
||||
make clean
|
||||
@ -51,5 +55,6 @@ else
|
||||
endif
|
||||
|
||||
dist: unrar
|
||||
$(PIP) install .
|
||||
pyinstaller -y comictagger.spec
|
||||
mv dist/$(APP_NAME) dist/$(FINAL_NAME)
|
||||
cd dist && zip -r $(FINAL_NAME).zip $(APP_NAME)
|
||||
|
16
README.md
16
README.md
@ -1,6 +1,18 @@
|
||||
A fork from the primary dev branch at https://github.com/davide-romanini/comictagger
|
||||
|
||||
Changes:
|
||||
ComicTagger is a multi-platform app for writing metadata to digital comics, written in Python and PyQt.
|
||||
|
||||
Features:
|
||||
|
||||
* Runs on Mac OSX, Microsoft Windows, and Linux systems
|
||||
* Communicates with an online database (Comic Vine) for acquiring metadata
|
||||
* Uses image processing to automatically match a given archive with the correct issue data
|
||||
* Batch processing in the GUI for tagging hundreds or more comics at a time
|
||||
* Reads and writes multiple tagging schemes (ComicBookLover and ComicRack).
|
||||
* Reads and writes RAR and Zip archives (external tools needed for writing RAR)
|
||||
* Can run without PyQt5 installed
|
||||
|
||||
|
||||
Recent changes:
|
||||
- Ported to Python 3
|
||||
- Ported to PyQt5
|
||||
- Added more application and GUI awareness of the unrar library, and removed references to the old scheme that used the unrar executable.
|
||||
|
@ -1,6 +0,0 @@
|
||||
version: 1.0.{build}
|
||||
build_script:
|
||||
- cmd: powershell -exec bypass -File windows\fullbuild.ps1
|
||||
artifacts:
|
||||
- path: dist\*.exe
|
||||
name: ComicTagger
|
@ -153,6 +153,7 @@ class ZipArchiver:
|
||||
zf = zipfile.ZipFile(
|
||||
self.path,
|
||||
mode='a',
|
||||
allowZip64=True,
|
||||
compression=zipfile.ZIP_DEFLATED)
|
||||
zf.writestr(archive_file, data)
|
||||
zf.close()
|
||||
@ -185,7 +186,7 @@ class ZipArchiver:
|
||||
os.close(tmp_fd)
|
||||
|
||||
zin = zipfile.ZipFile(self.path, 'r')
|
||||
zout = zipfile.ZipFile(tmp_name, 'w')
|
||||
zout = zipfile.ZipFile(tmp_name, 'w', allowZip64=True)
|
||||
for item in zin.infolist():
|
||||
buffer = zin.read(item.filename)
|
||||
if (item.filename not in exclude_list):
|
||||
@ -270,7 +271,7 @@ class ZipArchiver:
|
||||
"""Replace the current zip with one copied from another archive"""
|
||||
|
||||
try:
|
||||
zout = zipfile.ZipFile(self.path, 'w')
|
||||
zout = zipfile.ZipFile(self.path, 'w', allowZip64=True)
|
||||
for fname in otherArchive.getArchiveFilenameList():
|
||||
data = otherArchive.readArchiveFile(fname)
|
||||
if data is not None:
|
||||
|
@ -123,7 +123,7 @@ def which(program):
|
||||
|
||||
def removearticles(text):
|
||||
text = text.lower()
|
||||
articles = ['and', 'a', '&', 'issue']
|
||||
articles = ['and', 'a', '&', 'issue', 'the']
|
||||
newText = ''
|
||||
for word in text.split(' '):
|
||||
if word not in articles:
|
||||
|
@ -1,6 +1,7 @@
|
||||
# -*- mode: python -*-
|
||||
|
||||
import platform
|
||||
from comictaggerlib import ctversion
|
||||
|
||||
block_cipher = None
|
||||
|
||||
@ -9,10 +10,12 @@ binaries = [
|
||||
]
|
||||
|
||||
if platform.system() == "Windows":
|
||||
from site import getsitepackages
|
||||
sitepackages = getsitepackages()[1]
|
||||
# add ssl qt libraries not discovered automatically
|
||||
binaries.extend([
|
||||
('./venv/Lib/site-packages/PyQt5/Qt/bin/libeay32.dll', './PyQt5/Qt/bin'),
|
||||
('./venv/Lib/site-packages/PyQt5/Qt/bin/ssleay32.dll', './PyQt5/Qt/bin')
|
||||
('%s/PyQt5/Qt/bin/libeay32.dll' % sitepackages, './PyQt5/Qt/bin'),
|
||||
('%s/PyQt5/Qt/bin/ssleay32.dll' % sitepackages, './PyQt5/Qt/bin')
|
||||
])
|
||||
|
||||
a = Analysis(['comictagger.py'],
|
||||
@ -45,6 +48,9 @@ app = BUNDLE(exe,
|
||||
name='ComicTagger.app',
|
||||
icon='mac/app.icns',
|
||||
info_plist={
|
||||
'NSHighResolutionCapable': 'True'
|
||||
'NSHighResolutionCapable': 'True',
|
||||
'CFBundleDisplayName': 'ComicTagger',
|
||||
'CFBundleShortVersionString': ctversion.version,
|
||||
'CFBundleVersion': ctversion.version
|
||||
},
|
||||
bundle_identifier=None)
|
@ -105,7 +105,7 @@ class ComicVineTalker(QObject):
|
||||
self.log_func = None
|
||||
|
||||
# always use a tls context for urlopen
|
||||
self.ssl = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
|
||||
self.ssl = ssl.SSLContext(ssl.PROTOCOL_TLS)
|
||||
|
||||
def setLogFunc(self, log_func):
|
||||
self.log_func = log_func
|
||||
@ -188,7 +188,7 @@ class ComicVineTalker(QObject):
|
||||
# connect to server:
|
||||
# if there is a 500 error, try a few more times before giving up
|
||||
# any other error, just bail
|
||||
# print "ATB---", url
|
||||
#print("---", url)
|
||||
for tries in range(3):
|
||||
try:
|
||||
resp = urllib.request.urlopen(url, context=self.ssl)
|
||||
@ -226,10 +226,10 @@ class ComicVineTalker(QObject):
|
||||
|
||||
original_series_name = series_name
|
||||
|
||||
# Split and rejoin to remove extra internal spaces
|
||||
# Split and rejoin to remove extra internal spaces
|
||||
query_word_list = series_name.split()
|
||||
query_string = " ".join( query_word_list ).strip()
|
||||
#print "Query string = ", query_string
|
||||
#print ("Query string = ", query_string)
|
||||
|
||||
query_string = urllib.parse.quote_plus(query_string.encode("utf-8"))
|
||||
|
||||
@ -246,6 +246,19 @@ class ComicVineTalker(QObject):
|
||||
current_result_count = cv_response['number_of_page_results']
|
||||
total_result_count = cv_response['number_of_total_results']
|
||||
|
||||
# 8 Dec 2018 - Comic Vine changed query results again. Terms are now
|
||||
# ORed together, and we get thousands of results. Good news is the
|
||||
# results are sorted by relevance, so we can be smart about halting
|
||||
# the search.
|
||||
# 1. Don't fetch more than some sane amount of pages.
|
||||
max_results = 500
|
||||
# 2. Halt when not all of our search terms are present in a result
|
||||
# 3. Halt when the results contain more (plus threshold) words than
|
||||
# our search
|
||||
result_word_count_max = len(query_word_list) + 3
|
||||
|
||||
total_result_count = min(total_result_count, max_results)
|
||||
|
||||
if callback is None:
|
||||
self.writeLog(
|
||||
"Found {0} of {1} results\n".format(
|
||||
@ -258,7 +271,29 @@ class ComicVineTalker(QObject):
|
||||
callback(current_result_count, total_result_count)
|
||||
|
||||
# see if we need to keep asking for more pages...
|
||||
stop_searching = False
|
||||
while (current_result_count < total_result_count):
|
||||
|
||||
last_result = search_results[-1]['name']
|
||||
|
||||
# See if the last result's name has all the of the search terms.
|
||||
# if not, break out of this, loop, we're done.
|
||||
#print("Searching for {} in '{}'".format(query_word_list, last_result))
|
||||
for term in query_word_list:
|
||||
if term not in last_result.lower():
|
||||
#print("Term '{}' not in last result. Halting search result fetching".format(term))
|
||||
stop_searching = True
|
||||
break
|
||||
|
||||
# Also, stop searching when the word count of last results is too much longer
|
||||
# than our search terms list
|
||||
if len(utils.removearticles(last_result).split()) > result_word_count_max:
|
||||
#print("Last result '{}' is too long. Halting search result fetching".format(last_result))
|
||||
stop_searching = True
|
||||
|
||||
if stop_searching:
|
||||
break
|
||||
|
||||
if callback is None:
|
||||
self.writeLog(
|
||||
"getting another page of results {0} of {1}...\n".format(
|
||||
@ -274,6 +309,15 @@ class ComicVineTalker(QObject):
|
||||
if callback is not None:
|
||||
callback(current_result_count, total_result_count)
|
||||
|
||||
# Remove any search results that don't contain all the search terms
|
||||
# (iterate backwards for easy removal)
|
||||
for i in range(len(search_results) - 1, -1, -1):
|
||||
record = search_results[i]
|
||||
for term in query_word_list:
|
||||
if term not in record['name'].lower():
|
||||
del search_results[i]
|
||||
break
|
||||
|
||||
# for record in search_results:
|
||||
#print(u"{0}: {1} ({2})".format(record['id'], record['name'] , record['start_year']))
|
||||
# print(record)
|
||||
@ -328,16 +372,16 @@ class ComicVineTalker(QObject):
|
||||
limit = cv_response['limit']
|
||||
current_result_count = cv_response['number_of_page_results']
|
||||
total_result_count = cv_response['number_of_total_results']
|
||||
# print "ATB total_result_count", total_result_count
|
||||
#print("total_result_count", total_result_count)
|
||||
|
||||
#print("ATB Found {0} of {1} results".format(cv_response['number_of_page_results'], cv_response['number_of_total_results']))
|
||||
#print("Found {0} of {1} results".format(cv_response['number_of_page_results'], cv_response['number_of_total_results']))
|
||||
volume_issues_result = cv_response['results']
|
||||
page = 1
|
||||
offset = 0
|
||||
|
||||
# see if we need to keep asking for more pages...
|
||||
while (current_result_count < total_result_count):
|
||||
#print("ATB getting another page of issue results {0} of {1}...".format(current_result_count, total_result_count))
|
||||
#print("getting another page of issue results {0} of {1}...".format(current_result_count, total_result_count))
|
||||
page += 1
|
||||
offset += cv_response['number_of_page_results']
|
||||
|
||||
@ -380,16 +424,16 @@ class ComicVineTalker(QObject):
|
||||
limit = cv_response['limit']
|
||||
current_result_count = cv_response['number_of_page_results']
|
||||
total_result_count = cv_response['number_of_total_results']
|
||||
# print "ATB total_result_count", total_result_count
|
||||
#print("total_result_count", total_result_count)
|
||||
|
||||
#print("ATB Found {0} of {1} results\n".format(cv_response['number_of_page_results'], cv_response['number_of_total_results']))
|
||||
#print("Found {0} of {1} results\n".format(cv_response['number_of_page_results'], cv_response['number_of_total_results']))
|
||||
filtered_issues_result = cv_response['results']
|
||||
page = 1
|
||||
offset = 0
|
||||
|
||||
# see if we need to keep asking for more pages...
|
||||
while (current_result_count < total_result_count):
|
||||
#print("ATB getting another page of issue results {0} of {1}...\n".format(current_result_count, total_result_count))
|
||||
#print("getting another page of issue results {0} of {1}...\n".format(current_result_count, total_result_count))
|
||||
page += 1
|
||||
offset += cv_response['number_of_page_results']
|
||||
|
||||
|
@ -1,3 +0,0 @@
|
||||
# This file should contain only these comments, and the line below.
|
||||
# Used by packaging makefiles and app
|
||||
version = "1.1.30-rc1"
|
@ -67,7 +67,7 @@ class ImageFetcher(QObject):
|
||||
self.create_image_db()
|
||||
|
||||
# always use a tls context for urlopen
|
||||
self.ssl = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
|
||||
self.ssl = ssl.SSLContext(ssl.PROTOCOL_TLS)
|
||||
|
||||
def clearCache(self):
|
||||
os.unlink(self.db_file)
|
||||
|
@ -1 +0,0 @@
|
||||
1.1.16-beta-rc
|
@ -5,7 +5,7 @@ TAGGER_BASE ?= ../
|
||||
TAGGER_SRC := $(TAGGER_BASE)/comictaggerlib
|
||||
|
||||
APP_NAME := ComicTagger
|
||||
VERSION_STR := $(shell grep version $(TAGGER_SRC)/ctversion.py| cut -d= -f2 | sed 's/\"//g')
|
||||
VERSION_STR := $(shell python setup.py --version)
|
||||
|
||||
MAC_BASE := $(TAGGER_BASE)/mac
|
||||
DIST_DIR := $(MAC_BASE)/dist
|
||||
|
@ -5,4 +5,4 @@ natsort==3.5.2
|
||||
PyPDF2==1.24
|
||||
pillow>=4.3.0
|
||||
PyQt5>=5.10.1
|
||||
git+https://github.com/pyinstaller/pyinstaller@develop
|
||||
pyinstaller>=3.5
|
11
setup.py
11
setup.py
@ -23,7 +23,6 @@ import sys
|
||||
import shutil
|
||||
import platform
|
||||
import tempfile
|
||||
import comictaggerlib.ctversion
|
||||
|
||||
python_requires='>=3',
|
||||
|
||||
@ -193,18 +192,22 @@ setup(name="comictagger",
|
||||
'build_py': BuildPyCommand,
|
||||
'install': customInstall,
|
||||
},
|
||||
version=comictaggerlib.ctversion.version,
|
||||
description="A cross-platform GUI/CLI app for writing metadata to comic archives",
|
||||
author="ComicTagger team",
|
||||
author_email="comictagger@gmail.com",
|
||||
url="https://github.com/davide-romanini/comictagger",
|
||||
download_url="https://pypi.python.org/packages/source/c/comictagger/comictagger-{0}.zip".format(comictaggerlib.ctversion.version),
|
||||
url="https://github.com/davide-romanini/comictagger",
|
||||
packages=["comictaggerlib", "comicapi"],
|
||||
package_data={
|
||||
'comictaggerlib': ['ui/*', 'graphics/*', '*.so'],
|
||||
},
|
||||
entry_points=dict(console_scripts=['comictagger=comictaggerlib.main:ctmain']),
|
||||
data_files=platform_data_files,
|
||||
setup_requires=[
|
||||
"setuptools_scm"
|
||||
],
|
||||
use_scm_version={
|
||||
'write_to': 'comictaggerlib/ctversion.py'
|
||||
},
|
||||
classifiers=[
|
||||
"Development Status :: 4 - Beta",
|
||||
"Environment :: Console",
|
||||
|
@ -1,5 +0,0 @@
|
||||
# to be run inside comictagger folder
|
||||
# installs conda and pip dependencies
|
||||
activate comictagger
|
||||
conda install -y pyqt=4
|
||||
pip install -r .\requirements.txt
|
@ -1,3 +0,0 @@
|
||||
$env:PATH+=";C:\ProgramData\Miniconda2\Scripts;C:\ProgramData\Miniconda2"
|
||||
$env:PATH+=";C:\tools\mingw64\bin"
|
||||
Set-Alias make mingw32-make.exe -scope Global
|
@ -1,8 +0,0 @@
|
||||
# Script to be run inside appveyor for a full build
|
||||
choco install -y mingw
|
||||
refreshenv
|
||||
$env:PATH="C:\Python36-x64;$env:path"
|
||||
python -m venv venv
|
||||
.\venv\Scripts\Activate.ps1
|
||||
pip install -r .\requirements.txt
|
||||
mingw32-make dist
|
@ -1,11 +0,0 @@
|
||||
# This script should be run into an admin PowerShell to install all required
|
||||
# packages needed for building comictagger on windows
|
||||
#
|
||||
# NOTE: this script has not been fully tested on a fresh windows VM.
|
||||
#
|
||||
# install chocolatey
|
||||
Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
|
||||
choco install -y git mingw miniconda
|
||||
$env:PATH+=";C:\ProgramData\Miniconda2\Scripts;C:\ProgramData\Miniconda2"
|
||||
$env:PATH+=";C:\tools\mingw64\bin"
|
||||
conda create -y --name comictagger python=2
|
Reference in New Issue
Block a user