A slew of enhancements

git-svn-id: http://comictagger.googlecode.com/svn/trunk@56 6c5673fe-1810-88d6-992b-cd32ca31540c
This commit is contained in:
beville@gmail.com 2012-11-18 00:32:01 +00:00
parent 47a61885d9
commit 263598ef4a
13 changed files with 484 additions and 119 deletions

View File

@ -397,16 +397,11 @@ class ComicArchive:
def seemsToBeAComicArchive( self ):
ext = os.path.splitext(self.path)[1].lower()
if (
( ( ( self.isZip() ) and
( ext.lower() in [ '.zip', '.cbz' ] ))
or
(( self.isRar() ) and
( ext.lower() in [ '.rar', '.cbr' ] ))
or
( self.isFolder() ) )
# Do we even care about extensions??
ext = os.path.splitext(self.path)[1].lower()
if (
( self.isZip() or self.isRar() or self.isFolder() )
and
( self.getNumberOfPages() > 3)

View File

@ -55,7 +55,7 @@ class ComicVineCacher:
"count_of_issues INT," +
"image_url TEXT," +
"description TEXT," +
"timestamp TEXT)"
"timestamp DATE DEFAULT (datetime('now','localtime')) ) "
)
cur.execute("CREATE TABLE Volumes(" +
@ -63,7 +63,7 @@ class ComicVineCacher:
"name TEXT," +
"publisher TEXT," +
"count_of_issues INT," +
"timestamp TEXT," +
"timestamp DATE DEFAULT (datetime('now','localtime')), " +
"PRIMARY KEY (id) )"
)
@ -78,7 +78,7 @@ class ComicVineCacher:
"thumb_image_hash TEXT," +
"publish_month TEXT," +
"publish_year TEXT," +
"timestamp TEXT," +
"timestamp DATE DEFAULT (datetime('now','localtime')), " +
"PRIMARY KEY (id ) )"
)
@ -107,7 +107,9 @@ class ComicVineCacher:
else:
url = record['image']['super_url']
cur.execute("INSERT INTO VolumeSearchCache VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ? )" ,
cur.execute("INSERT INTO VolumeSearchCache " +
"(search_term, id, name, start_year, publisher, count_of_issues, image_url, description ) " +
"VALUES( ?, ?, ?, ?, ?, ?, ?, ? )" ,
( search_term.lower(),
record['id'],
record['name'],
@ -115,8 +117,7 @@ class ComicVineCacher:
pub_name,
record['count_of_issues'],
url,
record['description'],
timestamp )
record['description'])
)
def get_search_results( self, search_term ):
@ -126,7 +127,10 @@ class ComicVineCacher:
with con:
cur = con.cursor()
# TODO purge stale search results ( older than a day, maybe??)
# purge stale search results
a_day_ago = datetime.datetime.today()-datetime.timedelta(days=1)
cur.execute( "DELETE FROM VolumeSearchCache WHERE timestamp < ?", [ str(a_day_ago) ] )
# fetch
cur.execute("SELECT * FROM VolumeSearchCache WHERE search_term=?", [ search_term.lower() ] )
@ -194,7 +198,13 @@ class ComicVineCacher:
with con:
cur = con.cursor()
# TODO purge stale volume records ( older than a week, maybe??)
# purge stale volume info
a_week_ago = datetime.datetime.today()-datetime.timedelta(days=7)
cur.execute( "DELETE FROM Volumes WHERE timestamp < ?", [ str(a_week_ago) ] )
# purge stale issue info - probably issue data won't change much....
a_month_ago = datetime.datetime.today()-datetime.timedelta(days=30)
cur.execute( "DELETE FROM Issues WHERE timestamp < ?", [ str(a_month_ago) ] )
# fetch
cur.execute("SELECT id,name,publisher,count_of_issues FROM Volumes WHERE id = ?", [ volume_id ] )

View File

@ -83,12 +83,21 @@ class FileNameParser:
# use the issue number string to split the filename string
# assume first element of list is the series name, plus cruft
#!!! this could fail in the case of small numerics in the series name!!!
# TODO: we really should pass in the *INDEX* of the issue, that makes
# finding it easier
tmpstr = self.fixSpaces(filename)
if issue != "":
series = tmpstr.split(issue)[0]
#remove pound signs. this might mess up the series name if there is a# in it.
tmpstr = tmpstr.replace("#", " ")
if issue != "":
# assume that issue substr has at least on space before it
issue_str = " " + str(issue)
series = tmpstr.split(issue_str)[0]
else:
# no issue to work off of
#!!! TODO we should look for the year, and split from that

View File

@ -103,7 +103,7 @@ class ImageFetcher(QObject):
# wipe any existing image cache folder too
if os.path.isdir( self.cache_folder ):
shutil.rmtree(path)
shutil.rmtree( self.cache_folder )
os.makedirs( self.cache_folder )
con = lite.connect( self.db_file )

View File

@ -52,13 +52,16 @@ class IssueIdentifier:
self.min_score_thresh = 20
# the min distance a hamming score must be to separate itself from closest neighbor
self.min_score_distance = 2
self.min_score_distance = 4
# a very strong hamming score, almost certainly the same image
self.strong_score_thresh = 8
# used to eliminate series names that are too long based on our search string
self.length_delta_thresh = 3
self.length_delta_thresh = 5
# used to eliminate unlikely publishers
self.publisher_blacklist = [ 'panini comics', 'abril', 'scholastic book services' ]
self.additional_metadata = GenericMetadata()
self.cv_api_key = cv_api_key
@ -75,6 +78,12 @@ class IssueIdentifier:
def setAdditionalMetadata( self, md ):
self.additional_metadata = md
def setNameLengthDeltaThreshold( self, delta ):
self.length_delta_thresh = md
def setPublisherBlackList( self, blacklist ):
self.publisher_blacklist = blacklist
def setHasherAlgorithm( self, algo ):
self.image_hasher = algo
pass
@ -244,12 +253,31 @@ class IssueIdentifier:
series_shortlist = []
#self.log_msg( "Removing results with too long names" )
#self.log_msg( "Removing results with too long names, banned publishers, or future start dates" )
for item in cv_search_results:
length_approved = False
publisher_approved = True
date_approved = True
# remove any series that starts after the issue year
if keys['year'] is not None and keys['year'].isdigit():
print "ATB", keys['year'] , item['start_year']
if int(keys['year']) < item['start_year']:
date_approved = False
#assume that our search name is close to the actual name, say within ,e.g. 5 chars
shortened_key = utils.removearticles(keys['series'])
shortened_item_name = utils.removearticles(item['name'])
if len( shortened_item_name ) < ( len( shortened_key ) + self.length_delta_thresh) :
length_approved = True
# remove any series from publishers on the blacklist
if item['publisher'] is not None:
publisher = item['publisher']['name']
if publisher is not None and publisher.lower() in self.publisher_blacklist:
publisher_approved = False
if length_approved and publisher_approved and date_approved:
series_shortlist.append(item)
# if we don't think it's an issue number 1, remove any series' that are one-shots
@ -325,11 +353,15 @@ class IssueIdentifier:
match['issue_number'] = num_s
match['url_image_hash'] = url_image_hash
match['issue_title'] = issue['name']
match['img_url'] = thumb_url
match['img_url'] = img_url
match['issue_id'] = issue['id']
match['volume_id'] = series['id']
match['month'] = month
match['year'] = year
match['publisher'] = None
if series['publisher'] is not None:
match['publisher'] = series['publisher']['name']
self.match_list.append(match)
self.log_msg( " --> {0}".format(match['distance']), newline=False )
@ -370,18 +402,18 @@ class IssueIdentifier:
if best_score > self.min_score_thresh:
self.log_msg( "!!!! Very weak score for the cover. Maybe it's not the cover?" )
self.log_msg( "Comparing other archive pages now..." )
self.log_msg( "Comparing to some other archive pages now..." )
found = False
for i in range(ca.getNumberOfPages()):
for i in range( min(5, ca.getNumberOfPages())):
image_data = ca.getPage(i)
page_hash = self.calculateHash( image_data )
distance = ImageHasher.hamming_distance(page_hash, self.match_list[0]['url_image_hash'])
if distance <= self.strong_score_thresh:
print "Found a great match d={0} on page {1}!".format(distance, i+1)
self.log_msg( "Found a great match d={0} on page {1}!".format(distance, i+1) )
found = True
break
elif distance < self.min_score_thresh:
print "Found a good match d={0} on page {1}".format(distance, i)
self.log_msg( "Found a good match d={0} on page {1}".format(distance, i) )
found = True
self.log_msg( ".", newline=False )
self.log_msg( "" )

118
matchselectionwindow.py Normal file
View File

@ -0,0 +1,118 @@
"""
A PyQT4 dialog to select from automated issue matches
"""
"""
Copyright 2012 Anthony Beville
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import sys
import os
from PyQt4 import QtCore, QtGui, uic
from PyQt4.QtCore import QUrl, pyqtSignal, QByteArray
from comicvinetalker import ComicVineTalker
from imagefetcher import ImageFetcher
from settings import ComicTaggerSettings
class MatchSelectionWindow(QtGui.QDialog):
volume_id = 0
def __init__(self, parent, matches):
super(MatchSelectionWindow, self).__init__(parent)
uic.loadUi(os.path.join(ComicTaggerSettings.baseDir(), 'matchselectionwindow.ui' ), self)
self.matches = matches
self.populateTable( )
self.twList.resizeColumnsToContents()
self.twList.currentItemChanged.connect(self.currentItemChanged)
self.twList.cellDoubleClicked.connect(self.cellDoubleClicked)
self.current_row = 0
self.twList.selectRow( 0 )
def populateTable( self ):
while self.twList.rowCount() > 0:
self.twList.removeRow(0)
self.twList.setSortingEnabled(False)
row = 0
for match in self.matches:
self.twList.insertRow(row)
item_text = match['series']
item = QtGui.QTableWidgetItem(item_text)
item.setFlags(QtCore.Qt.ItemIsSelectable| QtCore.Qt.ItemIsEnabled)
self.twList.setItem(row, 0, item)
"""
item_text = u"{0}".format(match['issue_number'])
item = QtGui.QTableWidgetItem(item_text)
item.setFlags(QtCore.Qt.ItemIsSelectable| QtCore.Qt.ItemIsEnabled)
self.twList.setItem(row, 1, item)
"""
if match['publisher'] is not None:
item_text = u"{0}".format(match['publisher'])
else:
item_text = u"Unknown"
item = QtGui.QTableWidgetItem(item_text)
item.setFlags(QtCore.Qt.ItemIsSelectable| QtCore.Qt.ItemIsEnabled)
self.twList.setItem(row, 1, item)
item_text = ""
if match['month'] is not None:
item_text = u"{0}/".format(match['month'])
if match['year'] is not None:
item_text += u"{0}".format(match['year'])
else:
item_text += u"????"
item = QtGui.QTableWidgetItem(item_text)
item.setFlags(QtCore.Qt.ItemIsSelectable| QtCore.Qt.ItemIsEnabled)
self.twList.setItem(row, 2, item)
row += 1
def cellDoubleClicked( self, r, c ):
self.accept()
def currentItemChanged( self, curr, prev ):
if curr is None:
return
if prev is not None and prev.row() == curr.row():
return
self.current_row = curr.row()
# list selection was changed, update the the issue cover
self.labelThumbnail.setPixmap(QtGui.QPixmap(os.path.join(ComicTaggerSettings.baseDir(), 'graphics/nocover.png' )))
self.cover_fetcher = ImageFetcher( )
self.cover_fetcher.fetchComplete.connect(self.coverFetchComplete)
self.cover_fetcher.fetch( self.matches[self.current_row]['img_url'] )
# called when the image is done loading
def coverFetchComplete( self, image_data, issue_id ):
img = QtGui.QImage()
img.loadFromData( image_data )
self.labelThumbnail.setPixmap(QtGui.QPixmap(img))

142
matchselectionwindow.ui Normal file
View File

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>dialogMatchSelect</class>
<widget class="QDialog" name="dialogMatchSelect">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>831</width>
<height>506</height>
</rect>
</property>
<property name="windowTitle">
<string>Select Match</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTableWidget" name="twList">
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="rowCount">
<number>0</number>
</property>
<property name="columnCount">
<number>3</number>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>Series</string>
</property>
</column>
<column>
<property name="text">
<string>Publisher</string>
</property>
</column>
<column>
<property name="text">
<string>Date</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QLabel" name="labelThumbnail">
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>300</width>
<height>450</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::Panel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="text">
<string/>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>dialogMatchSelect</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>dialogMatchSelect</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -252,6 +252,7 @@ class TaggerWindow( QtGui.QMainWindow):
self.statusBar()
self.updateAppTitle()
self.setAcceptDrops(True)
self.updateSaveMenu()
self.droppedFile=None
self.page_browser = None
@ -292,7 +293,7 @@ class TaggerWindow( QtGui.QMainWindow):
mod_str = " [modified]"
if not self.comic_archive.isWritable():
ro_str = " [read only ]"
ro_str = " [read only]"
self.setWindowTitle( self.appName + " - " + self.comic_archive.path + mod_str + ro_str)
@ -484,12 +485,24 @@ class TaggerWindow( QtGui.QMainWindow):
self.metadataToForm()
self.clearDirtyFlag() # also updates the app title
self.updateInfoBox()
self.updateInfoBox()
self.updateSaveMenu()
#self.updatePagesInfo()
else:
QtGui.QMessageBox.information(self, self.tr("Whoops!"), self.tr("That file doesn't appear to be a comic archive!"))
def updateSaveMenu( self ):
if ( self.comic_archive is not None and
self.comic_archive.isWritable() and
not ( self.data_style == MetaDataStyle.CBI and self.comic_archive.isRar() )
):
self.actionWrite_Tags.setEnabled( True )
else:
self.actionWrite_Tags.setEnabled( False )
def updateInfoBox( self ):
ca = self.comic_archive
@ -800,17 +813,23 @@ class TaggerWindow( QtGui.QMainWindow):
def useFilename( self ):
self.metadata = self.comic_archive.metadataFromFilename( )
self.metadataToForm()
if self.comic_archive is not None:
self.metadata = self.comic_archive.metadataFromFilename( )
self.metadataToForm()
def selectFile( self ):
dialog = QtGui.QFileDialog(self)
dialog.setFileMode(QtGui.QFileDialog.ExistingFile)
#dialog.setFileMode(QtGui.QFileDialog.Directory )
if platform.system() != "Windows" and utils.which("unrar") is None:
archive_filter = "Comic archive files (*.cbz *.zip)"
else:
archive_filter = "Comic archive files (*.cbz *.zip *.cbr *.rar)"
filters = [
"Comic archive files (*.cbz *.zip *.cbr *.rar)",
archive_filter,
"Any files (*)"
]
@ -826,7 +845,7 @@ class TaggerWindow( QtGui.QMainWindow):
def autoSelectSearch(self):
if self.comic_archive is None:
QtGui.QMessageBox.warning(self, self.tr("Automatic Search"),
QtGui.QMessageBox.warning(self, self.tr("Automatic Online Search"),
self.tr("You need to load a comic first!"))
return
@ -834,20 +853,25 @@ class TaggerWindow( QtGui.QMainWindow):
def queryOnline(self, autoselect=False):
if self.settings.cv_api_key == "":
QtGui.QMessageBox.warning(self, self.tr("Online Search"),
self.tr("You need an API key from ComicVine to search online. " +
"Go to settings and enter it."))
return
#if self.settings.cv_api_key == "":
# QtGui.QMessageBox.warning(self, self.tr("Online Search"),
# self.tr("You need an API key from ComicVine to search online. " +
# "Go to settings and enter it."))
# return
issue_number = str(self.leIssueNum.text()).strip()
if autoselect and issue_number == "":
QtGui.QMessageBox.information(self,"Automatic Online Search", "Can't auto-select without an issue number (yet!)")
return
if str(self.leSeries.text()).strip() != "":
series_name = str(self.leSeries.text()).strip()
else:
QtGui.QMessageBox.information(self, self.tr("Whoops"), self.tr("Need to enter a series name to query."))
QtGui.QMessageBox.information(self, self.tr("Online Search"), self.tr("Need to enter a series name to search."))
return
issue_number = str(self.leIssueNum.text()).strip()
year = str(self.lePubYear.text()).strip()
if year == "":
@ -877,14 +901,21 @@ class TaggerWindow( QtGui.QMainWindow):
def commitMetadata(self):
if ( self.metadata is not None and self.comic_archive is not None):
QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
self.formToMetadata()
self.comic_archive.writeMetadata( self.metadata, self.data_style )
self.clearDirtyFlag()
self.updateInfoBox()
QtGui.QApplication.restoreOverrideCursor()
QtGui.QMessageBox.information(self, self.tr("Yeah!"), self.tr("File written."))
reply = QtGui.QMessageBox.question(self,
self.tr("Save Tags"),
self.tr("Are you sure you wish to save " + MetaDataStyle.name[self.data_style] + " tags to this archive?"),
QtGui.QMessageBox.Yes, QtGui.QMessageBox.No )
if reply == QtGui.QMessageBox.Yes:
QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
self.formToMetadata()
self.comic_archive.writeMetadata( self.metadata, self.data_style )
self.clearDirtyFlag()
self.updateInfoBox()
QtGui.QApplication.restoreOverrideCursor()
QtGui.QMessageBox.information(self, self.tr("Yeah!"), self.tr("File written."))
else:
@ -894,6 +925,7 @@ class TaggerWindow( QtGui.QMainWindow):
def setDataStyle(self, s):
self.data_style, b = self.cbDataStyle.itemData(s).toInt()
self.updateStyleTweaks()
self.updateSaveMenu()
def updateCreditColors( self ):
inactive_color = QtGui.QColor(255, 170, 150)

View File

@ -260,7 +260,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>680</width>
<width>685</width>
<height>380</height>
</rect>
</property>
@ -1013,7 +1013,7 @@
<x>0</x>
<y>0</y>
<width>975</width>
<height>25</height>
<height>28</height>
</rect>
</property>
<widget class="QMenu" name="menuComicTagger">
@ -1080,7 +1080,7 @@
<set>Qt::NoToolBarArea</set>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonFollowStyle</enum>
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="floatable">
<bool>false</bool>

View File

@ -1,53 +1,52 @@
-----------------
Features
----------------
Auto-select:
Multi-match dialog
Check aspect ratio, and maybe break cover into two parts for hashing?
Stand-alone CLI
Info dump
optionless args
remove tags
copy tags
Settings/Preferences Dialog
Remove API Key
Add clear cache
Add reset settings
Tab w/Identifier Settings
Add publisher blacklist
Add class for warning/info messages with "Don't show again" checkbox.
Add list of these flags to settings
TaggerWindow entry fields
Special tabbed Dialog needed for:
Pages Info - maybe a custom painted widget
At minimum, preserve the page data
Verify/warn on save (maybe just on over-write?)
Style sheets for windows/mac/linux
Add class for warning/info messages with "Don't show again" checkbox.
Add list of these flag to settings
Version 2 - GUI to handle mutliple files or folders
-----------
Style sheets for windows/mac/linux
-----------------
Bugs
----------------
Disable CBL for RAR
SQLite chokes on "Batman\ Li'l Gotham 001.cbr" name -- Doesn't like single quote '
SERIOUS BUG: rebuilding zips!
http://stackoverflow.com/questions/11578443/trigger-io-errno-18-cross-device-link
http://stackoverflow.com/questions/11578443/trigger-io-errno-18-cross-device-link
OSX:
toolbar
weird unrar complaints
Page browser sizing
Override curson is not beachball
Disable save when read-only
Be more tolerant of mis-labled extensions i.e. cbr when it's a cbz
Other settings possibilities:
Last tag style
Last "Open" folder (include dragged)
Clear caches
Filename parsing:
Rework how series name is separated from issue
Form type validation Ints vs strings for month, year. etc
@ -55,45 +54,26 @@ Check all HTTP responses for errors
Lots of error checking
Other settings possibilities:
Last tag style
Last "Open" folder (include dragged)
Clear caches
Image Hashes:
Failures of image hash:
Thor 600 Wrap-around w/ different aspect ratio
Bone 3 - Variant Cover,
Avengers #1, #13, #81
Filename parsing:
Concatenation of Name and Issue??
"1602"
App option to covert RAR to ZIP
-------------
Future
------------
Add warning message to allow writing CBI to RAR, and ask them to contact CBL ! :-)
If no unrar in path, then filter out CBR/RAR from open dialog
Scrape alternate Covers from ComicVine issue pages
GCD scraper or DB reader
GUI to handle mutliple files or folders
Auto search:
Searching w/o issue #?
Content Hashes!!
Wizard for converting between tag styles
Remove stale data from cache DB
SQLite chokes on "Batman\ Li'l Gotham 001.cbr" name
Auto search:
Choosing with pub year
Lexical analysis
Searching w/o issue #?
Determine alternate covers from CV somehow
-------------
Other
------------
Content Hashes!!
App option to covert RAR to ZIP
Archive function to detect tag blocks out of sync

View File

@ -53,9 +53,27 @@ def addtopath( dir ):
if dir is not None and dir != "":
os.environ['PATH'] = dir + os.pathsep + os.environ['PATH']
# returns executable path, if it exists
def which(program):
import os
def is_exe(fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
fpath, fname = os.path.split(program)
if fpath:
if is_exe(program):
return program
else:
for path in os.environ["PATH"].split(os.pathsep):
exe_file = os.path.join(path, program)
if is_exe(exe_file):
return exe_file
return None
def removearticles( text ):
text = text.lower()
articles = ['and', 'the', 'a', '&' ]
articles = ['and', 'the', 'a', '&', 'issue' ]
newText = ''
for word in text.split(' '):
if word not in articles:

View File

@ -33,7 +33,7 @@ from genericmetadata import GenericMetadata
from imagefetcher import ImageFetcher
from progresswindow import IDProgressWindow
from settings import ComicTaggerSettings
from matchselectionwindow import MatchSelectionWindow
class SearchThread( QtCore.QThread):
@ -111,6 +111,14 @@ class VolumeSelectionWindow(QtGui.QDialog):
def autoSelect( self ):
if self.comic_archive is None:
QtGui.QMessageBox.information(self,"Auto-Select", "You need to load a comic first!")
return
if self.issue_number is None or self.issue_number == "":
QtGui.QMessageBox.information(self,"Auto-Select", "Can't auto-select without an issue number (yet!)")
return
self.iddialog = IDProgressWindow( self)
self.iddialog.setModal(True)
self.iddialog.rejected.connect( self.identifyCancel )
@ -118,6 +126,7 @@ class VolumeSelectionWindow(QtGui.QDialog):
self.ii = IssueIdentifier( self.comic_archive, self.cv_api_key )
md = GenericMetadata()
md.series = self.series_name
md.issueNumber = self.issue_number
@ -151,29 +160,49 @@ class VolumeSelectionWindow(QtGui.QDialog):
matches = self.ii.match_list
result = self.ii.search_result
match_index = 0
found_match = False
choices = False
if result == self.ii.ResultNoMatches:
QtGui.QMessageBox.information(self,"Auto-Select Result", " No matches found :-(")
elif result == self.ii.ResultFoundMatchButBadCoverScore:
QtGui.QMessageBox.information(self,"Auto-Select Result", " Found a match, but cover doesn't seem to match. Verify before commiting!")
QtGui.QMessageBox.information(self,"Auto-Select Result", " Found a match, but cover doesn't seem the same. Verify before commiting!")
found_match = True
elif result == self.ii.ResultFoundMatchButNotFirstPage :
QtGui.QMessageBox.information(self,"Auto-Select Result", " Found a match, but not with the first page of the archive.")
found_match = True
elif result == self.ii.ResultMultipleMatchesWithBadImageScores:
QtGui.QMessageBox.information(self,"Auto-Select Result", " Found some possibilities, but no confidence. Proceed manually.")
choices = True
elif result == self.ii.ResultOneGoodMatch:
found_match = True
elif result == self.ii.ResultMultipleGoodMatches:
QtGui.QMessageBox.information(self,"Auto-Select Result", " Found multiple likely matches! Selection DIALOG TBD.")
QtGui.QMessageBox.information(self,"Auto-Select Result", " Found multiple likely matches. Please select.")
choices = True
if choices:
selector = MatchSelectionWindow( self, matches )
selector.setModal(True)
title = self.series_name
title += " #" + self.issue_number
if self.year is not None:
title += " (" + str(self.year) + ")"
title += " - "
selector.setWindowTitle( title + "Select Match")
selector.exec_()
if selector.result():
#we should now have a list index
found_match = True
match_index = selector.current_row
if found_match:
self.iddialog.accept()
print "VolumeSelectionWindow found a match!!", matches[0]['volume_id'], matches[0]['issue_number']
self.volume_id = matches[0]['volume_id']
self.issue_number = matches[0]['issue_number']
self.volume_id = matches[match_index]['volume_id']
self.issue_number = matches[match_index]['issue_number']
self.selectByID()
self.showIssues()

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>796</width>
<height>454</height>
<width>801</width>
<height>470</height>
</rect>
</property>
<property name="windowTitle">
@ -156,7 +156,7 @@
<item>
<widget class="QPushButton" name="btnRequery">
<property name="text">
<string>Re-Query</string>
<string>Re-Search</string>
</property>
</widget>
</item>