Page list management work

git-svn-id: http://comictagger.googlecode.com/svn/trunk@238 6c5673fe-1810-88d6-992b-cd32ca31540c
This commit is contained in:
beville@gmail.com 2012-12-08 19:57:51 +00:00
parent 5b8f73528b
commit 487c8a5bf4
13 changed files with 306 additions and 42 deletions

View File

@ -101,8 +101,8 @@ class CoMet:
if md.characters is not None:
char_list = [ c.strip() for c in md.characters.split(',') ]
for c in char_list:
assign( 'character', c )
for c in char_list:
assign( 'character', c )
if md.manga is not None and md.manga == "YesAndRightToLeft":
assign( 'readingDirection', "rtl")
@ -114,7 +114,7 @@ class CoMet:
date_str += "-" + str(md.month).zfill(2)
assign( 'date', date_str )
#assign( 'coverImage', md.??? ) #TODO Need to use pages list, eventually...
assign( 'coverImage', md.coverImage )
# need to specially process the credits, since they are structured differently than CIX
credit_writer_list = list()
@ -202,7 +202,7 @@ class CoMet:
if len( parts) > 1:
md.month = parts[1]
coverImage = xlate( 'coverImage' ) # TODO - do something with this!
md.coverImage = xlate( 'coverImage' )
readingDirection = xlate( 'readingDirection' )
if readingDirection is not None and readingDirection == "rtl":

View File

@ -29,6 +29,13 @@ if platform.system() == "Windows":
import _subprocess
import time
import StringIO
try:
import Image
pil_available = True
except ImportError:
pil_available = False
sys.path.insert(0, os.path.abspath(".") )
import UnRAR2
from UnRAR2.rar_exceptions import *
@ -37,7 +44,7 @@ from options import Options, MetaDataStyle
from comicinfoxml import ComicInfoXml
from comicbookinfo import ComicBookInfo
from comet import CoMet
from genericmetadata import GenericMetadata
from genericmetadata import GenericMetadata, PageType
from filenameparser import FileNameParser
@ -524,11 +531,6 @@ class ComicArchive:
return self.removeCBI()
elif style == MetaDataStyle.COMET:
return self.removeCoMet()
def getCoverPage(self):
# assume first page is the cover (for now)
return self.getPage( 0 )
def getPage( self, index ):
@ -575,9 +577,13 @@ class ComicArchive:
def readCBI( self ):
raw_cbi = self.readRawCBI()
if raw_cbi is None:
return GenericMetadata()
md =GenericMetadata()
else:
md = ComicBookInfo().metadataFromString( raw_cbi )
return ComicBookInfo().metadataFromString( raw_cbi )
md.setDefaultPageList( self.getNumberOfPages() )
return md
def readRawCBI( self ):
if ( not self.hasCBI() ):
@ -594,6 +600,7 @@ class ComicArchive:
return ComicBookInfo().validateString( comment )
def writeCBI( self, metadata ):
self.applyArchiveInfoToMetadata( metadata )
cbi_string = ComicBookInfo().stringFromMetadata( metadata )
return self.archiver.setArchiveComment( cbi_string )
@ -603,9 +610,20 @@ class ComicArchive:
def readCIX( self ):
raw_cix = self.readRawCIX()
if raw_cix is None:
return GenericMetadata()
md = GenericMetadata()
else:
md = ComicInfoXml().metadataFromString( raw_cix )
#validate the existing page list (make sure count is correct)
if len ( md.pages ) != 0 :
if len ( md.pages ) != self.getNumberOfPages():
# pages array doesn't match the actual number of images we're seeing
# in the archive, so discard the data
md.pages = []
return ComicInfoXml().metadataFromString( raw_cix )
if len( md.pages ) == 0:
md.setDefaultPageList( self.getNumberOfPages() )
return md
def readRawCIX( self ):
if not self.hasCIX():
@ -617,7 +635,7 @@ class ComicArchive:
def writeCIX(self, metadata):
if metadata is not None:
metadata.pageCount = self.getNumberOfPages()
self.applyArchiveInfoToMetadata( metadata, calc_page_sizes=True )
cix_string = ComicInfoXml().stringFromMetadata( metadata )
return self.archiver.writeArchiveFile( self.ci_xml_filename, cix_string )
else:
@ -639,9 +657,26 @@ class ComicArchive:
def readCoMet( self ):
raw_comet = self.readRawCoMet()
if raw_comet is None:
return GenericMetadata()
return CoMet().metadataFromString( raw_comet )
md = GenericMetadata()
else:
md = CoMet().metadataFromString( raw_comet )
md.setDefaultPageList( self.getNumberOfPages() )
#use the coverImage value from the comet_data to mark the cover in this struct
# walk through list of images in file, and find the matching one for md.coverImage
# need to remove the existing one in the default
if md.coverImage is not None:
cover_idx = 0
for idx,f in enumerate(self.getPageNameList()):
if md.coverImage == f:
cover_idx = idx
break
if cover_idx != 0:
del (md.pages[0]['Type'] )
md.pages[ cover_idx ]['Type'] = PageType.FrontCover
return md
def readRawCoMet( self ):
if not self.hasCoMet():
@ -656,7 +691,12 @@ class ComicArchive:
if not self.hasCoMet():
self.comet_filename = self.comet_default_filename
metadata.pageCount = self.getNumberOfPages()
self.applyArchiveInfoToMetadata( metadata )
# Set the coverImage value, if it's not the first page
cover_idx = int(metadata.getCoverPageIndexList()[0])
if cover_idx != 0:
metadata.coverImage = self.getPageName( cover_idx )
comet_string = CoMet().stringFromMetadata( metadata )
return self.archiver.writeArchiveFile( self.comet_filename, comet_string )
else:
@ -691,7 +731,29 @@ class ComicArchive:
else:
return True
def applyArchiveInfoToMetadata( self, md, calc_page_sizes=False):
md.pageCount = self.getNumberOfPages()
if calc_page_sizes:
for p in md.pages:
idx = int( p['Image'] )
if pil_available:
if 'ImageSize' not in p or 'ImageHeight' not in p or 'ImageWidth' not in p:
data = self.getPage( idx )
im = Image.open(StringIO.StringIO(data))
w,h = im.size
p['ImageSize'] = str(len(data))
p['ImageHeight'] = str(h)
p['ImageWidth'] = str(w)
else:
if 'ImageSize' not in p:
data = self.getPage( idx )
p['ImageSize'] = str(len(data))
def metadataFromFilename( self ):
metadata = GenericMetadata()

View File

@ -270,6 +270,7 @@ class ComicInfoXml:
if pages_node is not None:
for page in pages_node:
metadata.pages.append( page.attrib )
print page.attrib
metadata.isEmpty = False

View File

@ -162,7 +162,8 @@ def cli_mode( opts, settings ):
def create_local_metadata( opts, ca, has_desired_tags ):
md = GenericMetadata()
md.setDefaultPageList( ca.getNumberOfPages() )
if has_desired_tags:
md = ca.readMetadata( opts.data_style )
@ -235,7 +236,7 @@ def process_file_cli( filename, opts, settings, match_results ):
if has[ MetaDataStyle.CIX ]:
print "------ComicRack tags--------"
if opts.raw:
print u"{0}".format(ca.readRawCIX())
print u"{0}".format(unicode(ca.readRawCIX(), errors='ignore'))
else:
print u"{0}".format(ca.readCIX())
@ -307,7 +308,7 @@ def process_file_cli( filename, opts, settings, match_results ):
if opts.search_online:
ii = IssueIdentifier( ca, settings )
if md is None or md.isEmpty:
print "No metadata given to search online with!"
return
@ -320,6 +321,7 @@ def process_file_cli( filename, opts, settings, match_results ):
ii.setAdditionalMetadata( md )
ii.onlyUseAdditionalMetaData = True
ii.setOutputFunction( myoutput )
ii.cover_page_index = md.getCoverPageIndexList()[0]
matches = ii.search()
result = ii.search_result

View File

@ -104,7 +104,7 @@ class GenericMetadata:
self.rights = None
self.identifier = None
self.lastMark = None
self.coverImage = None
def overlay( self, new_md ):
# Overlay a metadata object on this one
@ -167,7 +167,9 @@ class GenericMetadata:
# For now, go the easy route, where any overlay
# value wipes out the whole list
if len(new_md.tags) > 0:
assign( "tags", new_md.tags )
assign( "tags", new_md.tags )
print "MD overlay len of old pages = {0} len of new pages = {1}".format(len(self.pages), len(new_md.pages))
if len(new_md.pages) > 0:
assign( "pages", new_md.pages )
@ -187,7 +189,35 @@ class GenericMetadata:
# otherwise, add it!
else:
self.addCredit( c['person'], c['role'], primary )
def setDefaultPageList( self, count ):
# generate a default page list, with the first page marked as the cover
for i in range(count):
page_dict = dict()
page_dict['Image'] = str(i)
if i == 0:
page_dict['Type'] = PageType.FrontCover
self.pages.append( page_dict )
def getArchivePageIndex( self, pagenum ):
# convert the displayed page number to the page index of the file in the archive
if pagenum < len( self.pages ):
return int( self.pages[pagenum]['Image'] )
else:
return 0
def getCoverPageIndexList( self ):
# return a list of archive page indices of cover pages
coverlist = []
for p in self.pages:
if 'Type' in p and p['Type'] == PageType.FrontCover:
coverlist.append( int(p['Image']))
if len(coverlist) == 0:
coverlist.append( 0 )
return coverlist
def addCredit( self, person, role, primary = False ):
credit = dict()

View File

@ -73,7 +73,8 @@ class IssueIdentifier:
self.output_function = IssueIdentifier.defaultWriteOutput
self.callback = None
self.search_result = self.ResultNoMatches
self.cover_page_index = 0
def setScoreMinThreshold( self, thresh ):
self.min_score_thresh = thresh
@ -218,7 +219,7 @@ class IssueIdentifier:
self.log_msg( "Sorry, but "+ opts.filename + " is not a comic archive!")
return self.match_list
cover_image_data = ca.getCoverPage()
cover_image_data = ca.getPage( self.cover_page_index )
cover_hash = self.calculateHash( cover_image_data )
#check the apect ratio

View File

@ -23,6 +23,7 @@ import getopt
import platform
import os
import ctversion
from genericmetadata import GenericMetadata
class Enum(set):
@ -55,7 +56,7 @@ If no options are given, {0} will run in windowed mode
specified via via -t (potentially lossy operation)
-s, --save Save out tags as specified type (via -t)
Must specify also at least -o, -p, or -m
--nooverwrite Don't modify tag block if it already exists ( relevent for -s or -c )
--nooverwrite Don't modify tag block if it already exists ( relevent for -s or -c )
-n, --dryrun Don't actually modify file (only relevent for -d, -s, or -r)
-t, --type=TYPE Specify TYPE as either "CR", "CBL", or "COMET" (as either
ComicRack, ComicBookLover, or CoMet style tags, respectivly)
@ -79,6 +80,7 @@ If no options are given, {0} will run in windowed mode
--noabort Don't abort save operation when online match is of low confidence
-v, --verbose Be noisy when doing what it does
--terse Don't say much (for print mode)
--version Display version
-h, --help Display this message
"""
@ -175,7 +177,7 @@ If no options are given, {0} will run in windowed mode
"hpdt:fm:vonsrc:i",
[ "help", "print", "delete", "type=", "copy=", "parsefilename", "metadata=", "verbose",
"online", "dryrun", "save", "rename" , "raw", "noabort", "terse", "nooverwrite",
"interactive", "nosummary" ])
"interactive", "nosummary", "version" ])
except getopt.GetoptError as err:
self.display_help_and_quit( str(err), 2 )
@ -224,6 +226,9 @@ If no options are given, {0} will run in windowed mode
self.show_save_summary = False
if o == "--nooverwrite":
self.no_overwrite = True
if o == "--version":
print "ComicTagger version: ", ctversion.version
quit()
if o in ("-t", "--type"):
if a.lower() == "cr":
self.data_style = MetaDataStyle.CIX

View File

@ -26,7 +26,7 @@ from settings import ComicTaggerSettings
class PageBrowserWindow(QtGui.QDialog):
def __init__(self, parent):
def __init__(self, parent, metadata):
super(PageBrowserWindow, self).__init__(parent)
uic.loadUi(os.path.join(ComicTaggerSettings.baseDir(), 'pagebrowser.ui' ), self)
@ -37,6 +37,7 @@ class PageBrowserWindow(QtGui.QDialog):
self.current_pixmap = None
self.page_count = 0
self.current_page_num = 0
self.metadata = metadata
self.btnNext.clicked.connect( self.nextPage )
self.btnPrev.clicked.connect( self.prevPage )
@ -66,7 +67,8 @@ class PageBrowserWindow(QtGui.QDialog):
self.setPage()
def setPage( self ):
image_data = self.comic_archive.getPage( self.current_page_num )
archive_page_index = self.metadata.getArchivePageIndex( self.current_page_num )
image_data = self.comic_archive.getPage( archive_page_index )
if image_data is not None:
self.setCurrentPixmap( image_data )

36
pagelisteditor.py Normal file
View File

@ -0,0 +1,36 @@
"""
A PyQt4 widget for editing the page list info
"""
"""
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 os
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4 import uic
from settings import ComicTaggerSettings
class PageListEditor(QWidget):
def __init__(self, parent ):
super(PageListEditor, self).__init__(parent)
uic.loadUi(os.path.join(ComicTaggerSettings.baseDir(), 'pagelisteditor.ui' ), self )

103
pagelisteditor.ui Normal file
View File

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>pageListEditor</class>
<widget class="QWidget" name="pageListEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>514</width>
<height>328</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QListWidget" name="listWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="pushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>^</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>v</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::Panel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox"/>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -43,6 +43,7 @@ from pagebrowser import PageBrowserWindow
from filenameparser import FileNameParser
from logwindow import LogWindow
from optionalmsgdialog import OptionalMessageDialog
from pagelisteditor import PageListEditor
import utils
import ctversion
@ -88,6 +89,11 @@ class TaggerWindow( QtGui.QMainWindow):
#signal.signal(signal.SIGINT, self.sigint_handler)
uic.loadUi(os.path.join(ComicTaggerSettings.baseDir(), 'taggerwindow.ui' ), self)
self.pageListEditor = PageListEditor( self.tabPages )
gridlayout = QtGui.QGridLayout( self.tabPages )
gridlayout.addWidget( self.pageListEditor )
self.setWindowIcon(QtGui.QIcon(os.path.join(ComicTaggerSettings.baseDir(), 'graphics/app.png' )))
self.lblCover.setPixmap(QtGui.QPixmap(os.path.join(ComicTaggerSettings.baseDir(), 'graphics/nocover.png' )))
@ -339,8 +345,6 @@ class TaggerWindow( QtGui.QMainWindow):
msgBox.exec_()
def dragEnterEvent(self, event):
self.droppedFile=None
if event.mimeData().hasUrls():
@ -382,6 +386,7 @@ class TaggerWindow( QtGui.QMainWindow):
# no style indicated, so try to choose
if hasNeither:
self.metadata = self.comic_archive.metadataFromFilename( )
self.metadata.setDefaultPageList( self.comic_archive.getNumberOfPages() )
else:
if hasCBI and not hasCIX:
self.data_style = MetaDataStyle.CBI
@ -410,8 +415,10 @@ class TaggerWindow( QtGui.QMainWindow):
if self.metadata.isEmpty:
self.metadata = self.comic_archive.metadataFromFilename( )
image_data = self.comic_archive.getCoverPage()
self.metadata.setDefaultPageList( self.comic_archive.getNumberOfPages() )
cover_idx = self.metadata.getCoverPageIndexList()[0]
image_data = self.comic_archive.getPage( cover_idx )
if not image_data is None:
img = QtGui.QImage()
img.loadFromData( image_data )
@ -420,6 +427,7 @@ class TaggerWindow( QtGui.QMainWindow):
if self.page_browser is not None:
self.page_browser.setComicArchive( self.comic_archive )
self.page_browser.metadata = self.metadata
self.metadataToForm()
self.clearDirtyFlag() # also updates the app title
@ -574,6 +582,8 @@ class TaggerWindow( QtGui.QMainWindow):
# get a minty fresh metadata object
self.metadata = GenericMetadata()
if self.comic_archive is not None:
self.metadata.setDefaultPageList( self.comic_archive.getNumberOfPages() )
# recursivly clear the tab form
self.clearChildren( self.tabWidget )
@ -789,11 +799,14 @@ class TaggerWindow( QtGui.QMainWindow):
md.addCredit( name, role, bool(primary_flag) )
row += 1
def useFilename( self ):
if self.comic_archive is not None:
self.metadata = self.comic_archive.metadataFromFilename( )
self.metadataToForm()
#copy the form onto metadata object
self.formToMetadata()
new_metadata = self.comic_archive.metadataFromFilename( )
if new_metadata is not None:
self.metadata.overlay( new_metadata )
self.metadataToForm()
def selectFile( self ):
@ -850,7 +863,8 @@ class TaggerWindow( QtGui.QMainWindow):
if year == "":
year = None
selector = VolumeSelectionWindow( self, series_name, issue_number, year, self.comic_archive, self.settings, autoselect )
cover_index_list = self.metadata.getCoverPageIndexList()
selector = VolumeSelectionWindow( self, series_name, issue_number, year, cover_index_list, self.comic_archive, self.settings, autoselect )
title = "Search: '" + series_name + "' - "
selector.setWindowTitle( title + "Select Series")
@ -1318,7 +1332,7 @@ class TaggerWindow( QtGui.QMainWindow):
def showPageBrowser( self ):
if self.page_browser is None:
self.page_browser = PageBrowserWindow( self )
self.page_browser = PageBrowserWindow( self, self.metadata )
if self.comic_archive is not None:
self.page_browser.setComicArchive( self.comic_archive )
self.page_browser.finished.connect(self.pageBrowserClosed)

View File

@ -1028,6 +1028,11 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tabPages">
<attribute name="title">
<string>Pages</string>
</attribute>
</widget>
</widget>
</item>
</layout>

View File

@ -85,7 +85,7 @@ class IdentifyThread( QtCore.QThread):
class VolumeSelectionWindow(QtGui.QDialog):
def __init__(self, parent, series_name, issue_number, year, comic_archive, settings, autoselect=False):
def __init__(self, parent, series_name, issue_number, year, cover_index_list, comic_archive, settings, autoselect=False):
super(VolumeSelectionWindow, self).__init__(parent)
uic.loadUi(os.path.join(ComicTaggerSettings.baseDir(), 'volumeselectionwindow.ui' ), self)
@ -97,7 +97,8 @@ class VolumeSelectionWindow(QtGui.QDialog):
self.volume_id = 0
self.comic_archive = comic_archive
self.immediate_autoselect = autoselect
self.cover_index_list = cover_index_list
self.twList.resizeColumnsToContents()
self.twList.currentItemChanged.connect(self.currentItemChanged)
self.twList.cellDoubleClicked.connect(self.cellDoubleClicked)
@ -136,6 +137,8 @@ class VolumeSelectionWindow(QtGui.QDialog):
self.ii.setAdditionalMetadata( md )
self.ii.onlyUseAdditionalMetaData = True
print self.cover_index_list
self.ii.cover_page_index = int(self.cover_index_list[0])
self.id_thread = IdentifyThread( self.ii )
self.id_thread.identifyComplete.connect( self.identifyComplete )