コード例 #1
0
    def __init__(self, parent, mode, expand_on_click=True):
        super(CoverImageWidget, self).__init__(parent)

        uic.loadUi(ComicTaggerSettings.getUIFile('coverimagewidget.ui'), self)

        reduceWidgetFontSize(self.label)

        self.mode = mode
        self.comicVine = ComicVineTalker()
        self.page_loader = None
        self.showControls = True

        self.btnLeft.setIcon(QIcon(ComicTaggerSettings.getGraphic('left.png')))
        self.btnRight.setIcon(
            QIcon(ComicTaggerSettings.getGraphic('right.png')))

        self.btnLeft.clicked.connect(self.decrementImage)
        self.btnRight.clicked.connect(self.incrementImage)
        self.resetWidget()
        if expand_on_click:
            clickable(self.lblImage).connect(self.showPopup)
        else:
            self.lblImage.setToolTip("")

        self.updateContent()
コード例 #2
0
	def performQuery( self ):

		QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))

		try:
			comicVine = ComicVineTalker( )
			volume_data = comicVine.fetchVolumeData( self.series_id )
			self.issue_list = comicVine.fetchIssuesByVolume( self.series_id )
		except ComicVineTalkerException:
			QtGui.QApplication.restoreOverrideCursor()		
			QtGui.QMessageBox.critical(self, self.tr("Network Issue"), self.tr("Could not connect to ComicVine to list issues!"))
			return

		while self.twList.rowCount() > 0:
			self.twList.removeRow(0)

		self.twList.setSortingEnabled(False)

		row = 0
		for record in self.issue_list: 
			self.twList.insertRow(row)
			
			item_text = record['issue_number']  
			item = IssueNumberTableWidgetItem(item_text)			
			item.setData( QtCore.Qt.ToolTipRole, item_text )
			item.setData( QtCore.Qt.UserRole ,record['id'])
			item.setData(QtCore.Qt.DisplayRole, item_text)
			item.setFlags(QtCore.Qt.ItemIsSelectable| QtCore.Qt.ItemIsEnabled)
			self.twList.setItem(row, 0, item)
			
			item_text = record['cover_date']
			if item_text is None:
				item_text = ""
			#remove the day of "YYYY-MM-DD"
			parts = item_text.split("-")
			if len(parts) > 1:
				item_text = parts[0] + "-" + parts[1]
				
			item = QtGui.QTableWidgetItem(item_text)			
			item.setData( QtCore.Qt.ToolTipRole, item_text )
			item.setFlags(QtCore.Qt.ItemIsSelectable| QtCore.Qt.ItemIsEnabled)
			self.twList.setItem(row, 1, item)

			item_text = record['name']
			if item_text is None:
				item_text = ""				
			item = QtGui.QTableWidgetItem(item_text)			
			item.setData( QtCore.Qt.ToolTipRole, item_text )
			item.setFlags(QtCore.Qt.ItemIsSelectable| QtCore.Qt.ItemIsEnabled)
			self.twList.setItem(row, 2, item)
			
			if IssueString(record['issue_number']).asString().lower() == IssueString(self.issue_number).asString().lower():
				self.initial_id = record['id']
			
			row += 1
			
		self.twList.setSortingEnabled(True)
		self.twList.sortItems( 0 , QtCore.Qt.AscendingOrder )

		QtGui.QApplication.restoreOverrideCursor()		
コード例 #3
0
	def run(self):
		comicVine = ComicVineTalker( )
		try:
			self.cv_error = False
			self.cv_search_results = comicVine.searchForSeries( self.series_name, callback=self.prog_callback, refresh_cache=self.refresh )
		except ComicVineTalkerException:
			self.cv_search_results = []
			self.cv_error = True
		finally:
			self.searchComplete.emit()
コード例 #4
0
    def setIssueID(self, issue_id):
        if self.mode == CoverImageWidget.AltCoverMode:
            self.resetWidget()
            self.updateContent()

            self.issue_id = issue_id

            self.comicVine = ComicVineTalker()
            self.comicVine.urlFetchComplete.connect(
                self.primaryUrlFetchComplete)
            self.comicVine.asyncFetchIssueCoverURLs(int(self.issue_id))
コード例 #5
0
    def startAltCoverSearch(self):

        # now we need to get the list of alt cover URLs
        self.label.setText("Searching for alt. covers...")

        # page URL should already be cached, so no need to defer
        self.comicVine = ComicVineTalker()
        issue_page_url = self.comicVine.fetchIssuePageURL(self.issue_id)
        self.comicVine.altUrlListFetchComplete.connect(
            self.altCoverUrlListFetchComplete)
        self.comicVine.asyncFetchAlternateCoverURLs(int(self.issue_id),
                                                    issue_page_url)
コード例 #6
0
	def run(self):
		comicVine = ComicVineTalker()
		try:
			self.cv_error = False
			self.cv_search_results = comicVine.searchForSeries( self.series_name, callback=self.prog_callback, refresh_cache=self.refresh )
		except ComicVineTalkerException as e:
			self.cv_search_results = []
			self.cv_error = True
			self.error_code = e.code

		finally:
			self.searchComplete.emit()
コード例 #7
0
ファイル: cli.py プロジェクト: 2mny/mylar
def actual_issue_data_fetch( match, settings, opts ):

	# now get the particular issue data
	try:
		comicVine = ComicVineTalker()
		comicVine.wait_for_rate_limit = opts.wait_and_retry_on_rate_limit
		cv_md = comicVine.fetchIssueData( match['volume_id'],  match['issue_number'], settings )
	except ComicVineTalkerException:
		print "Network error while getting issue details.  Save aborted"
		return None

	if settings.apply_cbl_transform_on_cv_import:
		cv_md = CBLTransformer( cv_md, settings ).apply()
		
	return cv_md
コード例 #8
0
def actual_issue_data_fetch( match, settings, opts ):

	# now get the particular issue data
	try:
		comicVine = ComicVineTalker()
		comicVine.wait_for_rate_limit = opts.wait_and_retry_on_rate_limit
		cv_md = comicVine.fetchIssueData( match['volume_id'],  match['issue_number'], settings )
	except ComicVineTalkerException:
		print >> sys.stderr, "Network error while getting issue details.  Save aborted"
		return None

	if settings.apply_cbl_transform_on_cv_import:
		cv_md = CBLTransformer( cv_md, settings ).apply()
		
	return cv_md
コード例 #9
0
    def __init__(self, parent, mode, expand_on_click=True):
        super(CoverImageWidget, self).__init__(parent)

        uic.loadUi(ComicTaggerSettings.getUIFile('coverimagewidget.ui'), self)

        reduceWidgetFontSize(self.label)

        self.mode = mode
        self.comicVine = ComicVineTalker()
        self.page_loader = None
        self.showControls = True

        self.btnLeft.setIcon(QIcon(ComicTaggerSettings.getGraphic('left.png')))
        self.btnRight.setIcon(
            QIcon(ComicTaggerSettings.getGraphic('right.png')))

        self.btnLeft.clicked.connect(self.decrementImage)
        self.btnRight.clicked.connect(self.incrementImage)
        self.resetWidget()
        if expand_on_click:
            clickable(self.lblImage).connect(self.showPopup)
        else:
            self.lblImage.setToolTip("")

        self.updateContent()
コード例 #10
0
 def testAPIKey(self):
     if ComicVineTalker().testKey(unicode(self.leKey.text())):
         QtGui.QMessageBox.information(self, "API Key Test",
                                       "Key is valid!")
     else:
         QtGui.QMessageBox.warning(self, "API Key Test",
                                   "Key is NOT valid.")
コード例 #11
0
	def startAltCoverSearch( self ):

		# now we need to get the list of alt cover URLs
		self.label.setText("Searching for alt. covers...")
		
		# page URL should already be cached, so no need to defer
		self.comicVine = ComicVineTalker()
		issue_page_url = self.comicVine.fetchIssuePageURL( self.issue_id )
		self.comicVine.altUrlListFetchComplete.connect( self.altCoverUrlListFetchComplete )	
		self.comicVine.asyncFetchAlternateCoverURLs( int(self.issue_id),  issue_page_url)
コード例 #12
0
	def setIssueID( self, issue_id ):
		if self.mode == CoverImageWidget.AltCoverMode:
			self.resetWidget()
			self.updateContent()
			
			self.issue_id = issue_id

			self.comicVine = ComicVineTalker()
			self.comicVine.urlFetchComplete.connect( self.primaryUrlFetchComplete )	
			self.comicVine.asyncFetchIssueCoverURLs( int(self.issue_id) )
コード例 #13
0
class CoverImageWidget(QWidget):

    ArchiveMode = 0
    AltCoverMode = 1
    URLMode = 1
    DataMode = 3

    def __init__(self, parent, mode, expand_on_click=True):
        super(CoverImageWidget, self).__init__(parent)

        uic.loadUi(ComicTaggerSettings.getUIFile('coverimagewidget.ui'), self)

        reduceWidgetFontSize(self.label)

        self.mode = mode
        self.comicVine = ComicVineTalker()
        self.page_loader = None
        self.showControls = True

        self.btnLeft.setIcon(QIcon(ComicTaggerSettings.getGraphic('left.png')))
        self.btnRight.setIcon(
            QIcon(ComicTaggerSettings.getGraphic('right.png')))

        self.btnLeft.clicked.connect(self.decrementImage)
        self.btnRight.clicked.connect(self.incrementImage)
        self.resetWidget()
        if expand_on_click:
            clickable(self.lblImage).connect(self.showPopup)
        else:
            self.lblImage.setToolTip("")

        self.updateContent()

    def resetWidget(self):
        self.comic_archive = None
        self.issue_id = None
        self.comicVine = None
        self.cover_fetcher = None
        self.url_list = []
        if self.page_loader is not None:
            self.page_loader.abandoned = True
        self.page_loader = None
        self.imageIndex = -1
        self.imageCount = 1
        self.imageData = None

    def clear(self):
        self.resetWidget()
        self.updateContent()

    def incrementImage(self):
        self.imageIndex += 1
        if self.imageIndex == self.imageCount:
            self.imageIndex = 0
        self.updateContent()

    def decrementImage(self):
        self.imageIndex -= 1
        if self.imageIndex == -1:
            self.imageIndex = self.imageCount - 1
        self.updateContent()

    def setArchive(self, ca, page=0):
        if self.mode == CoverImageWidget.ArchiveMode:
            self.resetWidget()
            self.comic_archive = ca
            self.imageIndex = page
            self.imageCount = ca.getNumberOfPages()
            self.updateContent()

    def setURL(self, url):
        if self.mode == CoverImageWidget.URLMode:
            self.resetWidget()
            self.updateContent()

            self.url_list = [url]
            self.imageIndex = 0
            self.imageCount = 1
            self.updateContent()

    def setIssueID(self, issue_id):
        if self.mode == CoverImageWidget.AltCoverMode:
            self.resetWidget()
            self.updateContent()

            self.issue_id = issue_id

            self.comicVine = ComicVineTalker()
            self.comicVine.urlFetchComplete.connect(
                self.primaryUrlFetchComplete)
            self.comicVine.asyncFetchIssueCoverURLs(int(self.issue_id))

    def setImageData(self, image_data):
        if self.mode == CoverImageWidget.DataMode:
            self.resetWidget()

            if image_data is None:
                self.imageIndex = -1
            else:
                self.imageIndex = 0
                self.imageData = image_data

            self.updateContent()

    def primaryUrlFetchComplete(self, primary_url, thumb_url, issue_id):
        self.url_list.append(str(primary_url))
        self.imageIndex = 0
        self.imageCount = len(self.url_list)
        self.updateContent()

        # defer the alt cover search
        QTimer.singleShot(1, self.startAltCoverSearch)

    def startAltCoverSearch(self):

        # now we need to get the list of alt cover URLs
        self.label.setText("Searching for alt. covers...")

        # page URL should already be cached, so no need to defer
        self.comicVine = ComicVineTalker()
        issue_page_url = self.comicVine.fetchIssuePageURL(self.issue_id)
        self.comicVine.altUrlListFetchComplete.connect(
            self.altCoverUrlListFetchComplete)
        self.comicVine.asyncFetchAlternateCoverURLs(int(self.issue_id),
                                                    issue_page_url)

    def altCoverUrlListFetchComplete(self, url_list, issue_id):
        if len(url_list) > 0:
            self.url_list.extend(url_list)
            self.imageCount = len(self.url_list)
        self.updateControls()

    def setPage(self, pagenum):
        if self.mode == CoverImageWidget.ArchiveMode:
            self.imageIndex = pagenum
            self.updateContent()

    def updateContent(self):
        self.updateImage()
        self.updateControls()

    def updateImage(self):
        if self.imageIndex == -1:
            self.loadDefault()
        elif self.mode in [
                CoverImageWidget.AltCoverMode, CoverImageWidget.URLMode
        ]:
            self.loadURL()
        elif self.mode == CoverImageWidget.DataMode:
            self.coverRemoteFetchComplete(self.imageData, 0)
        else:
            self.loadPage()

    def updateControls(self):
        if not self.showControls or self.mode == CoverImageWidget.DataMode:
            self.btnLeft.hide()
            self.btnRight.hide()
            self.label.hide()
            return

        if self.imageIndex == -1 or self.imageCount == 1:
            self.btnLeft.setEnabled(False)
            self.btnRight.setEnabled(False)
            self.btnLeft.hide()
            self.btnRight.hide()
        else:
            self.btnLeft.setEnabled(True)
            self.btnRight.setEnabled(True)
            self.btnLeft.show()
            self.btnRight.show()

        if self.imageIndex == -1 or self.imageCount == 1:
            self.label.setText("")
        elif self.mode == CoverImageWidget.AltCoverMode:
            self.label.setText("Cover {0} (of {1})".format(
                self.imageIndex + 1, self.imageCount))
        else:
            self.label.setText("Page {0} (of {1})".format(
                self.imageIndex + 1, self.imageCount))

    def loadURL(self):
        self.loadDefault()
        self.cover_fetcher = ImageFetcher()
        self.cover_fetcher.fetchComplete.connect(self.coverRemoteFetchComplete)
        self.cover_fetcher.fetch(self.url_list[self.imageIndex])
        #print("ATB cover fetch started...")

    # called when the image is done loading from internet
    def coverRemoteFetchComplete(self, image_data, issue_id):
        img = getQImageFromData(image_data)
        self.current_pixmap = QPixmap(img)
        self.setDisplayPixmap(0, 0)
        #print("ATB cover fetch complete!")

    def loadPage(self):
        if self.comic_archive is not None:
            if self.page_loader is not None:
                self.page_loader.abandoned = True
            self.page_loader = PageLoader(self.comic_archive, self.imageIndex)
            self.page_loader.loadComplete.connect(self.pageLoadComplete)
            self.page_loader.start()

    def pageLoadComplete(self, img):
        self.current_pixmap = QPixmap(img)
        self.setDisplayPixmap(0, 0)
        self.page_loader = None

    def loadDefault(self):
        self.current_pixmap = QPixmap(
            ComicTaggerSettings.getGraphic('nocover.png'))
        #print("loadDefault called")
        self.setDisplayPixmap(0, 0)

    def resizeEvent(self, resize_event):
        if self.current_pixmap is not None:
            delta_w = resize_event.size().width() - \
                resize_event.oldSize().width()
            delta_h = resize_event.size().height() - \
                resize_event.oldSize().height()
            # print "ATB resizeEvent deltas", resize_event.size().width(),
            # resize_event.size().height()
            self.setDisplayPixmap(delta_w, delta_h)

    def setDisplayPixmap(self, delta_w, delta_h):
        """The deltas let us know what the new width and height of the label will be"""

        #new_h = self.frame.height() + delta_h
        #new_w = self.frame.width() + delta_w
        # print "ATB setDisplayPixmap deltas", delta_w , delta_h
        # print "ATB self.frame", self.frame.width(), self.frame.height()
        # print "ATB self.", self.width(), self.height()

        #frame_w = new_w
        #frame_h = new_h

        new_h = self.frame.height()
        new_w = self.frame.width()
        frame_w = self.frame.width()
        frame_h = self.frame.height()

        new_h -= 4
        new_w -= 4

        if new_h < 0:
            new_h = 0
        if new_w < 0:
            new_w = 0

        # print "ATB setDisplayPixmap deltas", delta_w , delta_h
        # print "ATB self.frame", frame_w, frame_h
        # print "ATB new size", new_w, new_h

        # scale the pixmap to fit in the frame
        scaled_pixmap = self.current_pixmap.scaled(new_w, new_h,
                                                   Qt.KeepAspectRatio)
        self.lblImage.setPixmap(scaled_pixmap)

        # move and resize the label to be centered in the fame
        img_w = scaled_pixmap.width()
        img_h = scaled_pixmap.height()
        self.lblImage.resize(img_w, img_h)
        self.lblImage.move((frame_w - img_w) / 2, (frame_h - img_h) / 2)

    def showPopup(self):
        self.popup = ImagePopup(self, self.current_pixmap)
コード例 #14
0
ファイル: cli.py プロジェクト: 2mny/mylar
def process_file_cli( filename, opts, settings, match_results ):

	batch_mode = len( opts.file_list ) > 1
		
	ca = ComicArchive(filename, settings.rar_exe_path)
	
	if not os.path.lexists( filename ):
		print "Cannot find "+ filename
		return
		
	if not ca.seemsToBeAComicArchive():
		print "Sorry, but "+ filename + "  is not a comic archive!"
		return
	
	#if not ca.isWritableForStyle( opts.data_style ) and ( opts.delete_tags or opts.save_tags or opts.rename_file ):
	if not ca.isWritable(  ) and ( opts.delete_tags or opts.copy_tags or opts.save_tags or opts.rename_file ):
		print "This archive is not writable for that tag type"
		return

	has = [ False, False, False ]
	if ca.hasCIX(): has[ MetaDataStyle.CIX ] = True
	if ca.hasCBI(): has[ MetaDataStyle.CBI ] = True
	if ca.hasCoMet(): has[ MetaDataStyle.COMET ] = True

	if opts.print_tags:


		if opts.data_style is None:
			page_count = ca.getNumberOfPages()

			brief = ""

			if batch_mode:
				brief = u"{0}: ".format(filename)

			if ca.isZip():      brief += "ZIP archive    "
			elif ca.isRar():    brief += "RAR archive    "
			elif ca.isFolder(): brief += "Folder archive "
				
			brief += "({0: >3} pages)".format(page_count)			
			brief += "  tags:[ "

			if not ( has[ MetaDataStyle.CBI ] or has[ MetaDataStyle.CIX ] or has[ MetaDataStyle.COMET ] ):
				brief += "none "
			else:
				if has[ MetaDataStyle.CBI ]: brief += "CBL "
				if has[ MetaDataStyle.CIX ]: brief += "CR "
				if has[ MetaDataStyle.COMET ]: brief += "CoMet "
			brief += "]"
				
			print brief

		if opts.terse:
			return

		print
		
		if opts.data_style is None or opts.data_style == MetaDataStyle.CIX:
			if has[ MetaDataStyle.CIX ]:
				print "------ComicRack tags--------"
				if opts.raw:
					print u"{0}".format(unicode(ca.readRawCIX(), errors='ignore'))
				else:
					print u"{0}".format(ca.readCIX())
				
		if opts.data_style is None or opts.data_style == MetaDataStyle.CBI:
			if has[ MetaDataStyle.CBI ]:
				print "------ComicBookLover tags--------"
				if opts.raw:
					pprint(json.loads(ca.readRawCBI()))
				else:
					print u"{0}".format(ca.readCBI())
					
		if opts.data_style is None or opts.data_style == MetaDataStyle.COMET:
			if has[ MetaDataStyle.COMET ]:
				print "------CoMet tags--------"
				if opts.raw:
					print u"{0}".format(ca.readRawCoMet())
				else:
					print u"{0}".format(ca.readCoMet())
			
			
	elif opts.delete_tags:
		style_name = MetaDataStyle.name[ opts.data_style ]
		if has[ opts.data_style ]:
			if not opts.dryrun:
				if not ca.removeMetadata( opts.data_style ):
					print u"{0}: Tag removal seemed to fail!".format( filename )
				else:
					print u"{0}: Removed {1} tags.".format( filename, style_name )
			else:
				print u"{0}: dry-run.  {1} tags not removed".format( filename, style_name )		
		else:
			print u"{0}: This archive doesn't have {1} tags to remove.".format( filename, style_name )

	elif opts.copy_tags:
		dst_style_name = MetaDataStyle.name[ opts.data_style ]
		if opts.no_overwrite and has[ opts.data_style ]:
			print u"{0}: Already has {1} tags.  Not overwriting.".format(filename, dst_style_name)
			return
		if opts.copy_source == opts.data_style:
			print u"{0}: Destination and source are same: {1}.  Nothing to do.".format(filename, dst_style_name)
			return
			
		src_style_name = MetaDataStyle.name[ opts.copy_source ]
		if has[ opts.copy_source ]:
			if not opts.dryrun:
				md = ca.readMetadata( opts.copy_source )
				
				if settings.apply_cbl_transform_on_bulk_operation and opts.data_style == MetaDataStyle.CBI:
					md = CBLTransformer( md, settings ).apply()
				
				if not ca.writeMetadata( md, opts.data_style ):
					print u"{0}: Tag copy seemed to fail!".format( filename )
				else:
					print u"{0}: Copied {1} tags to {2} .".format( filename, src_style_name, dst_style_name )
			else:
				print u"{0}: dry-run.  {1} tags not copied".format( filename, src_style_name )		
		else:
			print u"{0}: This archive doesn't have {1} tags to copy.".format( filename, src_style_name )

		
	elif opts.save_tags:

		if opts.no_overwrite and has[ opts.data_style ]:
			print u"{0}: Already has {1} tags.  Not overwriting.".format(filename, MetaDataStyle.name[ opts.data_style ])
			return
		
		if batch_mode:
			print u"Processing {0}...".format(filename)
			
		md = create_local_metadata( opts, ca, has[ opts.data_style ] )
		if md.issue is None or md.issue == "":
			if opts.assume_issue_is_one_if_not_set:
				md.issue = "1"
		
		# now, search online
		if opts.search_online:
			if opts.issue_id is not None:
				# we were given the actual ID to search with
				try:
					comicVine = ComicVineTalker()
					comicVine.wait_for_rate_limit = opts.wait_and_retry_on_rate_limit
					cv_md = comicVine.fetchIssueDataByIssueID( opts.issue_id, settings )
				except ComicVineTalkerException:
					print "Network error while getting issue details.  Save aborted"
					match_results.fetchDataFailures.append(filename)
					return
				
				if cv_md is None:
					print "No match for ID {0} was found.".format(opts.issue_id)
					match_results.noMatches.append(filename)
					return
				
				if settings.apply_cbl_transform_on_cv_import:
					cv_md = CBLTransformer( cv_md, settings ).apply()
			else:
				ii = IssueIdentifier( ca, settings )
	
				if md is None or md.isEmpty:
					print "No metadata given to search online with!"
					match_results.noMatches.append(filename)
					return
	
				def myoutput( text ):
					if opts.verbose:
						IssueIdentifier.defaultWriteOutput( text )
					
				# use our overlayed MD struct to search
				ii.setAdditionalMetadata( md )
				ii.onlyUseAdditionalMetaData = True
				ii.waitAndRetryOnRateLimit = opts.wait_and_retry_on_rate_limit
				ii.setOutputFunction( myoutput )
				ii.cover_page_index = md.getCoverPageIndexList()[0]
				matches = ii.search()
				
				result = ii.search_result
				
				found_match = False
				choices = False
				low_confidence = False
				
				if result == ii.ResultNoMatches:
					pass
				elif result == ii.ResultFoundMatchButBadCoverScore:
					low_confidence = True
					found_match = True
				elif result == ii.ResultFoundMatchButNotFirstPage :
					found_match = True
				elif result == ii.ResultMultipleMatchesWithBadImageScores:
					low_confidence = True
					choices = True
				elif result == ii.ResultOneGoodMatch:
					found_match = True
				elif result == ii.ResultMultipleGoodMatches:
					choices = True
	
				if choices:
					if low_confidence:
						print "Online search: Multiple low confidence matches.  Save aborted"
						match_results.lowConfidenceMatches.append(MultipleMatch(filename,matches))
						return
					else:
						print "Online search: Multiple good matches.  Save aborted"
						match_results.multipleMatches.append(MultipleMatch(filename,matches))
						return
				if low_confidence and opts.abortOnLowConfidence:
					print "Online search: Low confidence match.  Save aborted"
					match_results.lowConfidenceMatches.append(MultipleMatch(filename,matches))
					return
				if not found_match:
					print "Online search: No match found.  Save aborted"
					match_results.noMatches.append(filename)
					return
	
	
				# we got here, so we have a single match
				
				# now get the particular issue data
				cv_md = actual_issue_data_fetch(matches[0], settings, opts)
				if cv_md is None:
					match_results.fetchDataFailures.append(filename)
					return
			
			md.overlay( cv_md )
			
		# ok, done building our metadata. time to save
		if not actual_metadata_save( ca, opts, md ):
				match_results.writeFailures.append(filename)
		else:
				match_results.goodMatches.append(filename)

	elif opts.rename_file:

		msg_hdr = ""
		if batch_mode:
			msg_hdr = u"{0}: ".format(filename)

		if opts.data_style is not None:
			use_tags = has[ opts.data_style ]
		else:
			use_tags = False
			
		md = create_local_metadata( opts, ca, use_tags )
		
		if md.series is None:
			print msg_hdr + "Can't rename without series name"
			return

		new_ext = None  # default
		if settings.rename_extension_based_on_archive:
			if ca.isZip():
				new_ext = ".cbz"
			elif ca.isRar():
				new_ext = ".cbr"
			
		renamer = FileRenamer( md )
		renamer.setTemplate( settings.rename_template )
		renamer.setIssueZeroPadding( settings.rename_issue_number_padding )
		renamer.setSmartCleanup( settings.rename_use_smart_string_cleanup )
		
		new_name = renamer.determineName( filename, ext=new_ext )
			
		if new_name == os.path.basename(filename):
			print msg_hdr + "Filename is already good!"
			return
		
		folder = os.path.dirname( os.path.abspath( filename ) )
		new_abs_path = utils.unique_file( os.path.join( folder, new_name ) )

		suffix = ""
		if not opts.dryrun:
			# rename the file
			os.rename( filename, new_abs_path )
		else:
			suffix = " (dry-run, no change)"

		print u"renamed '{0}' -> '{1}' {2}".format(os.path.basename(filename), new_name, suffix)

	elif opts.export_to_zip:
		msg_hdr = ""
		if batch_mode:
			msg_hdr = u"{0}: ".format(filename)

		if not ca.isRar():
			print msg_hdr + "Archive is not a RAR."
			return
		
		rar_file = os.path.abspath( os.path.abspath( filename ) )
		new_file = os.path.splitext(rar_file)[0] + ".cbz"
		
		if opts.abort_export_on_conflict and os.path.lexists( new_file ):
			print  msg_hdr + "{0} already exists in the that folder.".format(os.path.split(new_file)[1])
			return
		
		new_file = utils.unique_file( os.path.join( new_file ) )
	
		delete_success = False
		export_success = False
		if not opts.dryrun:
			if ca.exportAsZip( new_file ):
				export_success = True
				if opts.delete_rar_after_export:
					try:
						os.unlink( rar_file )
					except:
						print msg_hdr + "Error deleting original RAR after export"
						delete_success = False
					else:
						delete_success = True
			else:
				# last export failed, so remove the zip, if it exists
				if os.path.lexists( new_file ):
					os.remove( new_file )
		else:
			msg = msg_hdr + u"Dry-run:  Would try to create {0}".format(os.path.split(new_file)[1])
			if opts.delete_rar_after_export:
				msg += u" and delete orginal."
			print msg
			return
			
		msg = msg_hdr
		if export_success:
			msg += u"Archive exported successfully to: {0}".format( os.path.split(new_file)[1] )
			if opts.delete_rar_after_export and delete_success:
				msg += u" (Original deleted) "
		else:
			msg += u"Archive failed to export!"
			
		print msg
コード例 #15
0
	def search( self ):

		ca = self.comic_archive
		self.match_list = []
		self.cancel = False
		self.search_result = self.ResultNoMatches
		
		if not pil_available:
			self.log_msg( "Python Imaging Library (PIL) is not available and is needed for issue identification." )
			return self.match_list
			
		if not ca.seemsToBeAComicArchive():
			self.log_msg( "Sorry, but "+ opts.filename + "  is not a comic archive!")
			return self.match_list
		
		cover_image_data = ca.getPage( self.cover_page_index )
		cover_hash = self.calculateHash( cover_image_data )

		#check the apect ratio
		# if it's wider than it is high, it's probably a two page spread
		# if so, crop it and calculate a second hash
		narrow_cover_hash = None
		aspect_ratio = self.getAspectRatio( cover_image_data )
		if aspect_ratio < 1.0:
			right_side_image_data = self.cropCover( cover_image_data )
			if right_side_image_data is not None:
				narrow_cover_hash = self.calculateHash( right_side_image_data )
				
		#self.log_msg( "Cover hash = {0:016x}".format(cover_hash) )

		keys = self.getSearchKeys()
		#normalize the issue number
		keys['issue_number'] = IssueString(keys['issue_number']).asString()
		
		# we need, at minimum, a series and issue number
		if keys['series'] is None or keys['issue_number'] is None:
			self.log_msg("Not enough info for a search!")
			return []
		
		
		self.log_msg( "Going to search for:" )
		self.log_msg( "\tSeries: " + keys['series'] )
		self.log_msg( "\tIssue : " + keys['issue_number']  )
		if keys['issue_count'] is not None:
			self.log_msg( "\tCount : " + str(keys['issue_count']) )
		if keys['year'] is not None:
			self.log_msg( "\tYear :  " + str(keys['year']) )
		if keys['month'] is not None:
			self.log_msg( "\tMonth : " + str(keys['month']) )
		
		#self.log_msg("Publisher Blacklist: " + str(self.publisher_blacklist))
		
		comicVine = ComicVineTalker( )
		comicVine.setLogFunc( self.output_function )

		#self.log_msg( ( "Searching for " + keys['series'] + "...")
		self.log_msg( u"Searching for  {0} #{1} ...".format( keys['series'], keys['issue_number']) )
		try:
			cv_search_results = comicVine.searchForSeries( keys['series'] )
		except ComicVineTalkerException:
			self.log_msg( "Network issue while searching for series.  Aborting...")
			return []
		
		#self.log_msg( "Found " + str(len(cv_search_results)) + " initial results" )
		if self.cancel == True:
			return []
		
		series_second_round_list = []
		
		#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 str(keys['year']).isdigit() and item['start_year'] is not None and str(item['start_year']).isdigit():
				if int(keys['year']) < int(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_second_round_list.append(item)

		self.log_msg( "Searching in " + str(len(series_second_round_list)) +" series" )
		
		if self.callback is not None:
			self.callback( 0, len(series_second_round_list))
			
		# now sort the list by name length
		series_second_round_list.sort(key=lambda x: len(x['name']), reverse=False)
		
		#build a list of volume IDs
		volume_id_list = list()
		for series in series_second_round_list:
			volume_id_list.append( series['id'])
			
		try:
			issue_list = comicVine.fetchIssuesByVolumeIssueNumAndYear( volume_id_list,
																	keys['issue_number'],
																	keys['year'])

		except ComicVineTalkerException:
			self.log_msg( "Network issue while searching for series details.  Aborting...")
			return []
			
		shortlist = list()
		#now re-associate the issues and volumes
		for issue in issue_list:
			for series in series_second_round_list:
				if series['id'] == issue['volume']['id']:
					shortlist.append( (series, issue) )
					break
		
		if keys['year'] is None:
			self.log_msg( u"Found {0} series that have an issue #{1}".format(len(shortlist), keys['issue_number']) )
		else:
			self.log_msg( u"Found {0} series that have an issue #{1} from {2}".format(len(shortlist), keys['issue_number'], keys['year'] ))
		
			
		# now we have a shortlist of volumes with the desired issue number
		# Do first round of cover matching
		counter = len(shortlist)
		for series, issue in  shortlist:		
			if self.callback is not None:
				self.callback( counter, len(shortlist)*3)
				counter += 1
			
			self.log_msg( u"Examining covers for  ID: {0} {1} ({2}) ...".format(
			               series['id'], 
			               series['name'], 
			               series['start_year']), newline=False )
			
			# parse out the cover date
			day, month, year = comicVine.parseDateStr( issue['cover_date'] )

			# Now check the cover match against the primary image
			hash_list = [ cover_hash ]
			if narrow_cover_hash is not None:
				hash_list.append(narrow_cover_hash)

			try:	
				image_url = issue['image']['super_url']
				thumb_url = issue['image']['thumb_url']
				page_url = issue['site_detail_url']

				score_item = self.getIssueCoverMatchScore( comicVine, issue['id'], image_url, thumb_url, page_url, hash_list, useRemoteAlternates = False )
			except:
				self.match_list = []
				return self.match_list

			match = dict()
			match['series'] = u"{0} ({1})".format(series['name'], series['start_year'])
			match['distance'] = score_item['score']
			match['issue_number'] = keys['issue_number']
			match['cv_issue_count'] = series['count_of_issues']
			match['url_image_hash'] = score_item['hash']
			match['issue_title'] = issue['name']
			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']
			match['image_url'] = image_url
			match['thumb_url'] = thumb_url
			match['page_url'] = page_url			
			match['description'] = issue['description']			
				
			self.match_list.append(match)

			self.log_msg( " --> {0}".format(match['distance']), newline=False )

			self.log_msg( "" )
		
		if len(self.match_list) == 0:
			self.log_msg( ":-(  no matches!" )
			self.search_result = self.ResultNoMatches
			return self.match_list


		# sort list by image match scores
		self.match_list.sort(key=lambda k: k['distance'])		
		
		l = []
		for i in self.match_list:
			l.append( i['distance'] )

		self.log_msg( "Compared to covers in {0} issue(s):".format(len(self.match_list)), newline=False)
		self.log_msg( str(l))

		def print_match(item):
			self.log_msg( u"-----> {0} #{1} {2} ({3}/{4}) -- score: {5}".format(
									item['series'], 
									item['issue_number'], 
									item['issue_title'],
									item['month'],
									item['year'],
									item['distance']) )
		
		best_score = self.match_list[0]['distance']

		if best_score >= self.min_score_thresh:
			# we have 1 or more low-confidence matches (all bad cover scores)
			# look at a few more pages in the archive, and also alternate covers online
			self.log_msg( "Very weak scores for the cover.  Analyzing alternate pages and covers..." )
			hash_list = [ cover_hash ]
			if narrow_cover_hash is not None:
				hash_list.append(narrow_cover_hash)
			for i in range( 1, min(3, ca.getNumberOfPages())):
				image_data = ca.getPage(i)
				page_hash = self.calculateHash( image_data )
				hash_list.append( page_hash )
				
			second_match_list = []
			counter = 2*len(self.match_list)
			for m in self.match_list:
				if self.callback is not None:
					self.callback( counter, len(self.match_list)*3)
					counter += 1
				self.log_msg( u"Examining alternate covers for ID: {0} {1} ...".format(
							   m['volume_id'], 
							   m['series']), newline=False )
				try:
					score_item = self.getIssueCoverMatchScore( comicVine, m['issue_id'], m['image_url'], m['thumb_url'], m['page_url'], hash_list, useRemoteAlternates = True )
				except:
					self.match_list = []
					return self.match_list
				self.log_msg("--->{0}".format(score_item['score']))
				self.log_msg( "" )

				if score_item['score'] < self.min_alternate_score_thresh:
					second_match_list.append(m)
					m['distance'] = score_item['score']
					
			if len(	second_match_list ) == 0:
				if len( self.match_list) == 1:
					self.log_msg( "No matching pages in the issue." )
					self.log_msg( u"--------------------------------------------------")
					print_match(self.match_list[0])
					self.log_msg( u"--------------------------------------------------")
					self.search_result = self.ResultFoundMatchButBadCoverScore
				else:
					self.log_msg( u"--------------------------------------------------")
					self.log_msg( u"Multiple bad cover matches!  Need to use other info..." )
					self.log_msg( u"--------------------------------------------------")
					self.search_result = self.ResultMultipleMatchesWithBadImageScores
				return self.match_list
			else:
				# We did good, found something!
				self.log_msg( "Success in secondary/alternate cover matching!" )
				
				self.match_list = second_match_list
				# sort new list by image match scores
				self.match_list.sort(key=lambda k: k['distance'])		
				best_score = self.match_list[0]['distance']
				self.log_msg("[Second round cover matching: best score = {0}]".format(best_score))
				# now drop down into the rest of the processing
				
		if self.callback is not None:
			self.callback( 99, 100)
		
		#now pare down list, remove any item more than specified distant from the top scores
		for item in reversed(self.match_list):
			if item['distance'] > best_score + self.min_score_distance:
				self.match_list.remove(item)

		# One more test for the case choosing limited series first issue vs a trade with the same cover:
		# if we have a given issue count > 1 and the volume from CV has count==1, remove it from match list
		if len(self.match_list) >= 2 and keys['issue_count'] is not None and keys['issue_count'] != 1:
			new_list = list()
			for match in self.match_list:
				if match['cv_issue_count'] != 1:
					new_list.append(match)
				else:
					self.log_msg("Removing volume {0} [{1}] from consideration (only 1 issue)".format(match['series'], match['volume_id']))
				
			if len(new_list) > 0:
				self.match_list = new_list
		
		if len(self.match_list) == 1:
			self.log_msg( u"--------------------------------------------------")
			print_match(self.match_list[0])
			self.log_msg( u"--------------------------------------------------")
			self.search_result = self.ResultOneGoodMatch
			
		elif len(self.match_list) == 0:
			self.log_msg( u"--------------------------------------------------")
			self.log_msg( "No matches found :(" )
			self.log_msg( u"--------------------------------------------------")
			self.search_result = self.ResultNoMatches
		else:
			# we've got multiple good matches:
			self.log_msg( "More than one likley candiate." )
			self.search_result = self.ResultMultipleGoodMatches
			self.log_msg( u"--------------------------------------------------")
			for item in self.match_list:
				print_match(item)
			self.log_msg( u"--------------------------------------------------")

		return self.match_list
コード例 #16
0
    def search(self):

        ca = self.comic_archive
        self.match_list = []
        self.cancel = False
        self.search_result = self.ResultNoMatches

        if not pil_available:
            self.log_msg(
                "Python Imaging Library (PIL) is not available and is needed for issue identification.")
            return self.match_list

        if not ca.seemsToBeAComicArchive():
            self.log_msg(
                "Sorry, but " + opts.filename + " is not a comic archive!")
            return self.match_list

        cover_image_data = ca.getPage(self.cover_page_index)
        cover_hash = self.calculateHash(cover_image_data)

        # check the aspect ratio
        # if it's wider than it is high, it's probably a two page spread
        # if so, crop it and calculate a second hash
        narrow_cover_hash = None
        aspect_ratio = self.getAspectRatio(cover_image_data)
        if aspect_ratio < 1.0:
            right_side_image_data = self.cropCover(cover_image_data)
            if right_side_image_data is not None:
                narrow_cover_hash = self.calculateHash(right_side_image_data)

        #self.log_msg("Cover hash = {0:016x}".format(cover_hash))

        keys = self.getSearchKeys()
        # normalize the issue number
        keys['issue_number'] = IssueString(keys['issue_number']).asString()

        # we need, at minimum, a series and issue number
        if keys['series'] is None or keys['issue_number'] is None:
            self.log_msg("Not enough info for a search!")
            return []

        self.log_msg("Going to search for:")
        self.log_msg("\tSeries: " + keys['series'])
        self.log_msg("\tIssue:  " + keys['issue_number'])
        if keys['issue_count'] is not None:
            self.log_msg("\tCount:  " + str(keys['issue_count']))
        if keys['year'] is not None:
            self.log_msg("\tYear:   " + str(keys['year']))
        if keys['month'] is not None:
            self.log_msg("\tMonth:  " + str(keys['month']))

        #self.log_msg("Publisher Blacklist: " + str(self.publisher_blacklist))
        comicVine = ComicVineTalker()
        comicVine.wait_for_rate_limit = self.waitAndRetryOnRateLimit

        comicVine.setLogFunc(self.output_function)

        # self.log_msg(("Searching for " + keys['series'] + "...")
        self.log_msg(u"Searching for  {0} #{1} ...".format(
            keys['series'], keys['issue_number']))
        try:
            cv_search_results = comicVine.searchForSeries(keys['series'])
        except ComicVineTalkerException:
            self.log_msg(
                "Network issue while searching for series. Aborting...")
            return []

        #self.log_msg("Found " + str(len(cv_search_results)) + " initial results")
        if self.cancel:
            return []

        if cv_search_results is None:
            return []

        series_second_round_list = []

        #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 str(
                    keys['year']).isdigit() and item['start_year'] is not None and str(
                    item['start_year']).isdigit():
                if int(keys['year']) < int(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_second_round_list.append(item)

        self.log_msg(
            "Searching in " + str(len(series_second_round_list)) + " series")

        if self.callback is not None:
            self.callback(0, len(series_second_round_list))

        # now sort the list by name length
        series_second_round_list.sort(
            key=lambda x: len(x['name']), reverse=False)

        # build a list of volume IDs
        volume_id_list = list()
        for series in series_second_round_list:
            volume_id_list.append(series['id'])

        try:
            issue_list = comicVine.fetchIssuesByVolumeIssueNumAndYear(
                volume_id_list,
                keys['issue_number'],
                keys['year'])

        except ComicVineTalkerException:
            self.log_msg(
                "Network issue while searching for series details. Aborting...")
            return []

        if issue_list is None:
            return []

        shortlist = list()
        # now re-associate the issues and volumes
        for issue in issue_list:
            for series in series_second_round_list:
                if series['id'] == issue['volume']['id']:
                    shortlist.append((series, issue))
                    break

        if keys['year'] is None:
            self.log_msg(u"Found {0} series that have an issue #{1}".format(
                len(shortlist), keys['issue_number']))
        else:
            self.log_msg(
                u"Found {0} series that have an issue #{1} from {2}".format(
                    len(shortlist),
                    keys['issue_number'],
                    keys['year']))

        # now we have a shortlist of volumes with the desired issue number
        # Do first round of cover matching
        counter = len(shortlist)
        for series, issue in shortlist:
            if self.callback is not None:
                self.callback(counter, len(shortlist) * 3)
                counter += 1

            self.log_msg(u"Examining covers for  ID: {0} {1} ({2}) ...".format(
                series['id'],
                series['name'],
                series['start_year']), newline=False)

            # parse out the cover date
            day, month, year = comicVine.parseDateStr(issue['cover_date'])

            # Now check the cover match against the primary image
            hash_list = [cover_hash]
            if narrow_cover_hash is not None:
                hash_list.append(narrow_cover_hash)

            try:
                image_url = issue['image']['super_url']
                thumb_url = issue['image']['thumb_url']
                page_url = issue['site_detail_url']

                score_item = self.getIssueCoverMatchScore(
                    comicVine,
                    issue['id'],
                    image_url,
                    thumb_url,
                    page_url,
                    hash_list,
                    useRemoteAlternates=False)
            except:
                self.match_list = []
                return self.match_list

            match = dict()
            match['series'] = u"{0} ({1})".format(
                series['name'], series['start_year'])
            match['distance'] = score_item['score']
            match['issue_number'] = keys['issue_number']
            match['cv_issue_count'] = series['count_of_issues']
            match['url_image_hash'] = score_item['hash']
            match['issue_title'] = issue['name']
            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']
            match['image_url'] = image_url
            match['thumb_url'] = thumb_url
            match['page_url'] = page_url
            match['description'] = issue['description']

            self.match_list.append(match)

            self.log_msg(" --> {0}".format(match['distance']), newline=False)

            self.log_msg("")

        if len(self.match_list) == 0:
            self.log_msg(":-(no matches!")
            self.search_result = self.ResultNoMatches
            return self.match_list

        # sort list by image match scores
        self.match_list.sort(key=lambda k: k['distance'])

        l = []
        for i in self.match_list:
            l.append(i['distance'])

        self.log_msg("Compared to covers in {0} issue(s):".format(
            len(self.match_list)), newline=False)
        self.log_msg(str(l))

        def print_match(item):
            self.log_msg(u"-----> {0} #{1} {2} ({3}/{4}) -- score: {5}".format(
                item['series'],
                item['issue_number'],
                item['issue_title'],
                item['month'],
                item['year'],
                item['distance']))

        best_score = self.match_list[0]['distance']

        if best_score >= self.min_score_thresh:
            # we have 1 or more low-confidence matches (all bad cover scores)
            # look at a few more pages in the archive, and also alternate
            # covers online
            self.log_msg(
                "Very weak scores for the cover. Analyzing alternate pages and covers...")
            hash_list = [cover_hash]
            if narrow_cover_hash is not None:
                hash_list.append(narrow_cover_hash)
            for i in range(1, min(3, ca.getNumberOfPages())):
                image_data = ca.getPage(i)
                page_hash = self.calculateHash(image_data)
                hash_list.append(page_hash)

            second_match_list = []
            counter = 2 * len(self.match_list)
            for m in self.match_list:
                if self.callback is not None:
                    self.callback(counter, len(self.match_list) * 3)
                    counter += 1
                self.log_msg(
                    u"Examining alternate covers for ID: {0} {1} ...".format(
                        m['volume_id'],
                        m['series']),
                    newline=False)
                try:
                    score_item = self.getIssueCoverMatchScore(
                        comicVine,
                        m['issue_id'],
                        m['image_url'],
                        m['thumb_url'],
                        m['page_url'],
                        hash_list,
                        useRemoteAlternates=True)
                except:
                    self.match_list = []
                    return self.match_list
                self.log_msg("--->{0}".format(score_item['score']))
                self.log_msg("")

                if score_item['score'] < self.min_alternate_score_thresh:
                    second_match_list.append(m)
                    m['distance'] = score_item['score']

            if len(second_match_list) == 0:
                if len(self.match_list) == 1:
                    self.log_msg("No matching pages in the issue.")
                    self.log_msg(
                        u"--------------------------------------------------------------------------")
                    print_match(self.match_list[0])
                    self.log_msg(
                        u"--------------------------------------------------------------------------")
                    self.search_result = self.ResultFoundMatchButBadCoverScore
                else:
                    self.log_msg(
                        u"--------------------------------------------------------------------------")
                    self.log_msg(
                        u"Multiple bad cover matches!  Need to use other info...")
                    self.log_msg(
                        u"--------------------------------------------------------------------------")
                    self.search_result = self.ResultMultipleMatchesWithBadImageScores
                return self.match_list
            else:
                # We did good, found something!
                self.log_msg("Success in secondary/alternate cover matching!")

                self.match_list = second_match_list
                # sort new list by image match scores
                self.match_list.sort(key=lambda k: k['distance'])
                best_score = self.match_list[0]['distance']
                self.log_msg(
                    "[Second round cover matching: best score = {0}]".format(best_score))
                # now drop down into the rest of the processing

        if self.callback is not None:
            self.callback(99, 100)

        # now pare down list, remove any item more than specified distant from
        # the top scores
        for item in reversed(self.match_list):
            if item['distance'] > best_score + self.min_score_distance:
                self.match_list.remove(item)

        # One more test for the case choosing limited series first issue vs a trade with the same cover:
        # if we have a given issue count > 1 and the volume from CV has
        # count==1, remove it from match list
        if len(self.match_list) >= 2 and keys[
                'issue_count'] is not None and keys['issue_count'] != 1:
            new_list = list()
            for match in self.match_list:
                if match['cv_issue_count'] != 1:
                    new_list.append(match)
                else:
                    self.log_msg(
                        "Removing volume {0} [{1}] from consideration (only 1 issue)".format(
                            match['series'],
                            match['volume_id']))

            if len(new_list) > 0:
                self.match_list = new_list

        if len(self.match_list) == 1:
            self.log_msg(
                u"--------------------------------------------------------------------------")
            print_match(self.match_list[0])
            self.log_msg(
                u"--------------------------------------------------------------------------")
            self.search_result = self.ResultOneGoodMatch

        elif len(self.match_list) == 0:
            self.log_msg(
                u"--------------------------------------------------------------------------")
            self.log_msg("No matches found :(")
            self.log_msg(
                u"--------------------------------------------------------------------------")
            self.search_result = self.ResultNoMatches
        else:
            # we've got multiple good matches:
            self.log_msg("More than one likely candidate.")
            self.search_result = self.ResultMultipleGoodMatches
            self.log_msg(
                u"--------------------------------------------------------------------------")
            for item in self.match_list:
                print_match(item)
            self.log_msg(
                u"--------------------------------------------------------------------------")

        return self.match_list
コード例 #17
0
ファイル: cli.py プロジェクト: yonkyunior/mylar
def process_file_cli(filename, opts, settings, match_results):

    batch_mode = len(opts.file_list) > 1

    ca = ComicArchive(filename, settings.rar_exe_path)

    if not os.path.lexists(filename):
        print "Cannot find " + filename
        return

    if not ca.seemsToBeAComicArchive():
        print "Sorry, but " + filename + "  is not a comic archive!"
        return

    #if not ca.isWritableForStyle( opts.data_style ) and ( opts.delete_tags or opts.save_tags or opts.rename_file ):
    if not ca.isWritable() and (opts.delete_tags or opts.copy_tags
                                or opts.save_tags or opts.rename_file):
        print "This archive is not writable for that tag type"
        return

    has = [False, False, False]
    if ca.hasCIX(): has[MetaDataStyle.CIX] = True
    if ca.hasCBI(): has[MetaDataStyle.CBI] = True
    if ca.hasCoMet(): has[MetaDataStyle.COMET] = True

    if opts.print_tags:

        if opts.data_style is None:
            page_count = ca.getNumberOfPages()

            brief = ""

            if batch_mode:
                brief = u"{0}: ".format(filename)

            if ca.isZip(): brief += "ZIP archive    "
            elif ca.isRar(): brief += "RAR archive    "
            elif ca.isFolder(): brief += "Folder archive "

            brief += "({0: >3} pages)".format(page_count)
            brief += "  tags:[ "

            if not (has[MetaDataStyle.CBI] or has[MetaDataStyle.CIX]
                    or has[MetaDataStyle.COMET]):
                brief += "none "
            else:
                if has[MetaDataStyle.CBI]: brief += "CBL "
                if has[MetaDataStyle.CIX]: brief += "CR "
                if has[MetaDataStyle.COMET]: brief += "CoMet "
            brief += "]"

            print brief

        if opts.terse:
            return

        print

        if opts.data_style is None or opts.data_style == MetaDataStyle.CIX:
            if has[MetaDataStyle.CIX]:
                print "------ComicRack tags--------"
                if opts.raw:
                    print u"{0}".format(
                        unicode(ca.readRawCIX(), errors='ignore'))
                else:
                    print u"{0}".format(ca.readCIX())

        if opts.data_style is None or opts.data_style == MetaDataStyle.CBI:
            if has[MetaDataStyle.CBI]:
                print "------ComicBookLover tags--------"
                if opts.raw:
                    pprint(json.loads(ca.readRawCBI()))
                else:
                    print u"{0}".format(ca.readCBI())

        if opts.data_style is None or opts.data_style == MetaDataStyle.COMET:
            if has[MetaDataStyle.COMET]:
                print "------CoMet tags--------"
                if opts.raw:
                    print u"{0}".format(ca.readRawCoMet())
                else:
                    print u"{0}".format(ca.readCoMet())

    elif opts.delete_tags:
        style_name = MetaDataStyle.name[opts.data_style]
        if has[opts.data_style]:
            if not opts.dryrun:
                if not ca.removeMetadata(opts.data_style):
                    print u"{0}: Tag removal seemed to fail!".format(filename)
                else:
                    print u"{0}: Removed {1} tags.".format(
                        filename, style_name)
            else:
                print u"{0}: dry-run.  {1} tags not removed".format(
                    filename, style_name)
        else:
            print u"{0}: This archive doesn't have {1} tags to remove.".format(
                filename, style_name)

    elif opts.copy_tags:
        dst_style_name = MetaDataStyle.name[opts.data_style]
        if opts.no_overwrite and has[opts.data_style]:
            print u"{0}: Already has {1} tags.  Not overwriting.".format(
                filename, dst_style_name)
            return
        if opts.copy_source == opts.data_style:
            print u"{0}: Destination and source are same: {1}.  Nothing to do.".format(
                filename, dst_style_name)
            return

        src_style_name = MetaDataStyle.name[opts.copy_source]
        if has[opts.copy_source]:
            if not opts.dryrun:
                md = ca.readMetadata(opts.copy_source)

                if settings.apply_cbl_transform_on_bulk_operation and opts.data_style == MetaDataStyle.CBI:
                    md = CBLTransformer(md, settings).apply()

                if not ca.writeMetadata(md, opts.data_style):
                    print u"{0}: Tag copy seemed to fail!".format(filename)
                else:
                    print u"{0}: Copied {1} tags to {2} .".format(
                        filename, src_style_name, dst_style_name)
            else:
                print u"{0}: dry-run.  {1} tags not copied".format(
                    filename, src_style_name)
        else:
            print u"{0}: This archive doesn't have {1} tags to copy.".format(
                filename, src_style_name)

    elif opts.save_tags:

        if opts.no_overwrite and has[opts.data_style]:
            print u"{0}: Already has {1} tags.  Not overwriting.".format(
                filename, MetaDataStyle.name[opts.data_style])
            return

        if batch_mode:
            print u"Processing {0}...".format(filename)

        md = create_local_metadata(opts, ca, has[opts.data_style])
        if md.issue is None or md.issue == "":
            if opts.assume_issue_is_one_if_not_set:
                md.issue = "1"

        # now, search online
        if opts.search_online:
            if opts.issue_id is not None:
                # we were given the actual ID to search with
                try:
                    comicVine = ComicVineTalker()
                    comicVine.wait_for_rate_limit = opts.wait_and_retry_on_rate_limit
                    cv_md = comicVine.fetchIssueDataByIssueID(
                        opts.issue_id, settings)
                except ComicVineTalkerException:
                    print "Network error while getting issue details.  Save aborted"
                    match_results.fetchDataFailures.append(filename)
                    return

                if cv_md is None:
                    print "No match for ID {0} was found.".format(
                        opts.issue_id)
                    match_results.noMatches.append(filename)
                    return

                if settings.apply_cbl_transform_on_cv_import:
                    cv_md = CBLTransformer(cv_md, settings).apply()
            else:
                ii = IssueIdentifier(ca, settings)

                if md is None or md.isEmpty:
                    print "No metadata given to search online with!"
                    match_results.noMatches.append(filename)
                    return

                def myoutput(text):
                    if opts.verbose:
                        IssueIdentifier.defaultWriteOutput(text)

                # use our overlayed MD struct to search
                ii.setAdditionalMetadata(md)
                ii.onlyUseAdditionalMetaData = True
                ii.waitAndRetryOnRateLimit = opts.wait_and_retry_on_rate_limit
                ii.setOutputFunction(myoutput)
                ii.cover_page_index = md.getCoverPageIndexList()[0]
                matches = ii.search()

                result = ii.search_result

                found_match = False
                choices = False
                low_confidence = False

                if result == ii.ResultNoMatches:
                    pass
                elif result == ii.ResultFoundMatchButBadCoverScore:
                    low_confidence = True
                    found_match = True
                elif result == ii.ResultFoundMatchButNotFirstPage:
                    found_match = True
                elif result == ii.ResultMultipleMatchesWithBadImageScores:
                    low_confidence = True
                    choices = True
                elif result == ii.ResultOneGoodMatch:
                    found_match = True
                elif result == ii.ResultMultipleGoodMatches:
                    choices = True

                if choices:
                    if low_confidence:
                        print "Online search: Multiple low confidence matches.  Save aborted"
                        match_results.lowConfidenceMatches.append(
                            MultipleMatch(filename, matches))
                        return
                    else:
                        print "Online search: Multiple good matches.  Save aborted"
                        match_results.multipleMatches.append(
                            MultipleMatch(filename, matches))
                        return
                if low_confidence and opts.abortOnLowConfidence:
                    print "Online search: Low confidence match.  Save aborted"
                    match_results.lowConfidenceMatches.append(
                        MultipleMatch(filename, matches))
                    return
                if not found_match:
                    print "Online search: No match found.  Save aborted"
                    match_results.noMatches.append(filename)
                    return

                # we got here, so we have a single match

                # now get the particular issue data
                cv_md = actual_issue_data_fetch(matches[0], settings, opts)
                if cv_md is None:
                    match_results.fetchDataFailures.append(filename)
                    return

            md.overlay(cv_md)

        # ok, done building our metadata. time to save
        if not actual_metadata_save(ca, opts, md):
            match_results.writeFailures.append(filename)
        else:
            match_results.goodMatches.append(filename)

    elif opts.rename_file:

        msg_hdr = ""
        if batch_mode:
            msg_hdr = u"{0}: ".format(filename)

        if opts.data_style is not None:
            use_tags = has[opts.data_style]
        else:
            use_tags = False

        md = create_local_metadata(opts, ca, use_tags)

        if md.series is None:
            print msg_hdr + "Can't rename without series name"
            return

        new_ext = None  # default
        if settings.rename_extension_based_on_archive:
            if ca.isZip():
                new_ext = ".cbz"
            elif ca.isRar():
                new_ext = ".cbr"

        renamer = FileRenamer(md)
        renamer.setTemplate(settings.rename_template)
        renamer.setIssueZeroPadding(settings.rename_issue_number_padding)
        renamer.setSmartCleanup(settings.rename_use_smart_string_cleanup)

        new_name = renamer.determineName(filename, ext=new_ext)

        if new_name == os.path.basename(filename):
            print msg_hdr + "Filename is already good!"
            return

        folder = os.path.dirname(os.path.abspath(filename))
        new_abs_path = utils.unique_file(os.path.join(folder, new_name))

        suffix = ""
        if not opts.dryrun:
            # rename the file
            os.rename(filename, new_abs_path)
        else:
            suffix = " (dry-run, no change)"

        print u"renamed '{0}' -> '{1}' {2}".format(os.path.basename(filename),
                                                   new_name, suffix)

    elif opts.export_to_zip:
        msg_hdr = ""
        if batch_mode:
            msg_hdr = u"{0}: ".format(filename)

        if not ca.isRar():
            print msg_hdr + "Archive is not a RAR."
            return

        rar_file = os.path.abspath(os.path.abspath(filename))
        new_file = os.path.splitext(rar_file)[0] + ".cbz"

        if opts.abort_export_on_conflict and os.path.lexists(new_file):
            print msg_hdr + "{0} already exists in the that folder.".format(
                os.path.split(new_file)[1])
            return

        new_file = utils.unique_file(os.path.join(new_file))

        delete_success = False
        export_success = False
        if not opts.dryrun:
            if ca.exportAsZip(new_file):
                export_success = True
                if opts.delete_rar_after_export:
                    try:
                        os.unlink(rar_file)
                    except:
                        print msg_hdr + "Error deleting original RAR after export"
                        delete_success = False
                    else:
                        delete_success = True
            else:
                # last export failed, so remove the zip, if it exists
                if os.path.lexists(new_file):
                    os.remove(new_file)
        else:
            msg = msg_hdr + u"Dry-run:  Would try to create {0}".format(
                os.path.split(new_file)[1])
            if opts.delete_rar_after_export:
                msg += u" and delete orginal."
            print msg
            return

        msg = msg_hdr
        if export_success:
            msg += u"Archive exported successfully to: {0}".format(
                os.path.split(new_file)[1])
            if opts.delete_rar_after_export and delete_success:
                msg += u" (Original deleted) "
        else:
            msg += u"Archive failed to export!"

        print msg
コード例 #18
0
    def searchComplete(self):
        self.progdialog.accept()
        if self.search_thread.cv_error:
            if self.search_thread.error_code == ComicVineTalkerException.RateLimit:
                QtGui.QMessageBox.critical(
                    self,
                    self.tr("Comic Vine Error"),
                    ComicVineTalker.getRateLimitMessage())
            else:
                QtGui.QMessageBox.critical(
                    self,
                    self.tr("Network Issue"),
                    self.tr("Could not connect to Comic Vine to search for series!"))
            return

        self.cv_search_results = self.search_thread.cv_search_results
        self.updateButtons()

        self.twList.setSortingEnabled(False)

        while self.twList.rowCount() > 0:
            self.twList.removeRow(0)

        row = 0
        for record in self.cv_search_results:
            self.twList.insertRow(row)

            item_text = record['name']
            item = QtGui.QTableWidgetItem(item_text)
            item.setData(QtCore.Qt.ToolTipRole, item_text)
            item.setData(QtCore.Qt.UserRole, record['id'])
            item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
            self.twList.setItem(row, 0, item)

            item_text = str(record['start_year'])
            item = QtGui.QTableWidgetItem(item_text)
            item.setData(QtCore.Qt.ToolTipRole, item_text)
            item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
            self.twList.setItem(row, 1, item)

            item_text = record['count_of_issues']
            item = QtGui.QTableWidgetItem(item_text)
            item.setData(QtCore.Qt.ToolTipRole, item_text)
            item.setData(QtCore.Qt.DisplayRole, record['count_of_issues'])
            item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
            self.twList.setItem(row, 2, item)

            if record['publisher'] is not None:
                item_text = record['publisher']['name']
                item.setData(QtCore.Qt.ToolTipRole, item_text)
                item = QtGui.QTableWidgetItem(item_text)
                item.setFlags(
                    QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
                self.twList.setItem(row, 3, item)

            row += 1

        self.twList.resizeColumnsToContents()
        self.twList.setSortingEnabled(True)
        self.twList.sortItems(2, QtCore.Qt.DescendingOrder)
        self.twList.selectRow(0)
        self.twList.resizeColumnsToContents()

        if len(self.cv_search_results) == 0:
            QtCore.QCoreApplication.processEvents()
            QtGui.QMessageBox.information(
                self, "Search Result", "No matches found!")

        if self.immediate_autoselect and len(self.cv_search_results) > 0:
            # defer the immediate autoselect so this dialog has time to pop up
            QtCore.QCoreApplication.processEvents()
            QtCore.QTimer.singleShot(10, self.doImmediateAutoselect)
コード例 #19
0
class CoverImageWidget(QWidget):
	
	ArchiveMode = 0
	AltCoverMode = 1
	URLMode = 1
	DataMode = 3
	
	def __init__(self, parent, mode, expand_on_click = True ):
		super(CoverImageWidget, self).__init__(parent)
		
		uic.loadUi(ComicTaggerSettings.getUIFile('coverimagewidget.ui' ), self)

		utils.reduceWidgetFontSize( self.label )

		self.mode = mode
		self.comicVine = ComicVineTalker()
		self.page_loader = None
		self.showControls = True

		self.btnLeft.setIcon(QIcon(ComicTaggerSettings.getGraphic('left.png')))
		self.btnRight.setIcon(QIcon(ComicTaggerSettings.getGraphic('right.png')))
		
		self.btnLeft.clicked.connect( self.decrementImage )
		self.btnRight.clicked.connect( self.incrementImage )
		self.resetWidget()
		if expand_on_click:
			clickable(self.lblImage).connect(self.showPopup)
		else:
			self.lblImage.setToolTip( "" )

		self.updateContent()

	def resetWidget(self):
		self.comic_archive = None
		self.issue_id = None
		self.comicVine = None
		self.cover_fetcher = None
		self.url_list = []
		if self.page_loader is not None:
			self.page_loader.abandoned = True
		self.page_loader = None
		self.imageIndex = -1
		self.imageCount = 1
		self.imageData = None
		
	def clear( self ):
		self.resetWidget()
		self.updateContent()
		
	def incrementImage( self ):
		self.imageIndex += 1
		if self.imageIndex == self.imageCount:
			self.imageIndex = 0
		self.updateContent()

	def decrementImage( self ):
		self.imageIndex -= 1
		if self.imageIndex == -1:
			self.imageIndex = self.imageCount -1
		self.updateContent()
			
	def setArchive( self, ca, page=0 ):
		if self.mode == CoverImageWidget.ArchiveMode:
			self.resetWidget()
			self.comic_archive = ca
			self.imageIndex = page
			self.imageCount = ca.getNumberOfPages()
			self.updateContent()

	def setURL( self, url ):
		if self.mode == CoverImageWidget.URLMode:
			self.resetWidget()
			self.updateContent()
			
			self.url_list = [ url ] 
			self.imageIndex = 0
			self.imageCount = 1
			self.updateContent()

	def setIssueID( self, issue_id ):
		if self.mode == CoverImageWidget.AltCoverMode:
			self.resetWidget()
			self.updateContent()
			
			self.issue_id = issue_id

			self.comicVine = ComicVineTalker()
			self.comicVine.urlFetchComplete.connect( self.primaryUrlFetchComplete )	
			self.comicVine.asyncFetchIssueCoverURLs( int(self.issue_id) )

	def setImageData( self, image_data ):
		if self.mode == CoverImageWidget.DataMode:
			self.resetWidget()
			
			if image_data is None:
				self.imageIndex = -1
			else:
				self.imageIndex = 0
				self.imageData = image_data
				
			self.updateContent()
			
	def primaryUrlFetchComplete( self, primary_url, thumb_url, issue_id ):
		self.url_list.append(str(primary_url))
		self.imageIndex = 0
		self.imageCount = len(self.url_list)
		self.updateContent()

		#defer the alt cover search 		
		QTimer.singleShot(1, self.startAltCoverSearch)

	def startAltCoverSearch( self ):

		# now we need to get the list of alt cover URLs
		self.label.setText("Searching for alt. covers...")
		
		# page URL should already be cached, so no need to defer
		self.comicVine = ComicVineTalker()
		issue_page_url = self.comicVine.fetchIssuePageURL( self.issue_id )
		self.comicVine.altUrlListFetchComplete.connect( self.altCoverUrlListFetchComplete )	
		self.comicVine.asyncFetchAlternateCoverURLs( int(self.issue_id),  issue_page_url)
		
	def altCoverUrlListFetchComplete( self, url_list, issue_id ):
		if len(url_list) > 0:
			self.url_list.extend(url_list)
			self.imageCount = len(self.url_list)
		self.updateControls()

	def setPage( self, pagenum ):
		if self.mode == CoverImageWidget.ArchiveMode:
			self.imageIndex = pagenum
			self.updateContent()
	
	def updateContent( self ):
		self.updateImage()
		self.updateControls()
		
	def updateImage( self ):
		if self.imageIndex == -1:
			self.loadDefault()
		elif self.mode in [ CoverImageWidget.AltCoverMode,  CoverImageWidget.URLMode ]:
			self.loadURL()
		elif self.mode == CoverImageWidget.DataMode:
			self.coverRemoteFetchComplete( self.imageData, 0 )
		else:
			self.loadPage()
	
	def updateControls( self ):
		if not self.showControls or self.mode == CoverImageWidget.DataMode:
			self.btnLeft.hide()
			self.btnRight.hide()
			self.label.hide()
			return
			
		if self.imageIndex == -1  or self.imageCount == 1:
			self.btnLeft.setEnabled(False)
			self.btnRight.setEnabled(False)
			self.btnLeft.hide()
			self.btnRight.hide()
		else:
			self.btnLeft.setEnabled(True)
			self.btnRight.setEnabled(True)
			self.btnLeft.show()
			self.btnRight.show()
		
		if self.imageIndex == -1  or self.imageCount == 1:
			self.label.setText("")		
		elif self.mode == CoverImageWidget.AltCoverMode:		
			self.label.setText("Cover {0} ( of {1} )".format(self.imageIndex+1, self.imageCount))
		else:
			self.label.setText("Page {0} ( of {1} )".format(self.imageIndex+1, self.imageCount))
	
	def loadURL( self ):
		self.loadDefault()
		self.cover_fetcher = ImageFetcher( )
		self.cover_fetcher.fetchComplete.connect(self.coverRemoteFetchComplete)
		self.cover_fetcher.fetch( self.url_list[self.imageIndex] )
		#print "ATB cover fetch started...."
				
	# called when the image is done loading from internet
	def coverRemoteFetchComplete( self, image_data, issue_id ):
		img = QImage()
		img.loadFromData( image_data )
		self.current_pixmap = QPixmap(img)
		self.setDisplayPixmap( 0, 0)
		#print "ATB cover fetch complete!"

	def loadPage( self ):
		if self.comic_archive is not None:
			if self.page_loader is not None:
				self.page_loader.abandoned = True
			self.page_loader = PageLoader( self.comic_archive, self.imageIndex )
			self.page_loader.loadComplete.connect( self.pageLoadComplete )	
			self.page_loader.start()

	def pageLoadComplete( self, img ):
		self.current_pixmap = QPixmap(img)
		self.setDisplayPixmap( 0, 0)
		self.page_loader = None
					
	def loadDefault( self ):
		self.current_pixmap = QPixmap(ComicTaggerSettings.getGraphic('nocover.png'))
		#print "loadDefault called"
		self.setDisplayPixmap( 0, 0)

	def resizeEvent( self, resize_event ):
		if self.current_pixmap is not None:
			delta_w = resize_event.size().width() - resize_event.oldSize().width()
			delta_h = resize_event.size().height() - resize_event.oldSize().height()
			#print "ATB resizeEvent deltas", resize_event.size().width(), resize_event.size().height()
			self.setDisplayPixmap( delta_w , delta_h )
							
	def setDisplayPixmap( self, delta_w , delta_h ):
			# the deltas let us know what the new width and height of the label will be
			"""
			new_h = self.frame.height() + delta_h
			new_w = self.frame.width() + delta_w
			print "ATB setDisplayPixmap deltas", delta_w , delta_h
			print "ATB self.frame", self.frame.width(), self.frame.height()
			print "ATB self.", self.width(), self.height()
			
			frame_w = new_w
			frame_h = new_h
			"""
			new_h = self.frame.height() 
			new_w = self.frame.width() 
			frame_w = self.frame.width() 
			frame_h = self.frame.height() 

			new_h -= 4
			new_w -= 4
			
			if new_h < 0:
				new_h = 0;
			if new_w < 0:
				new_w = 0;

			#print "ATB setDisplayPixmap deltas", delta_w , delta_h
			#print "ATB self.frame", frame_w, frame_h
			#print "ATB new size", new_w, new_h
			
			# scale the pixmap to fit in the frame
			scaled_pixmap = self.current_pixmap.scaled(new_w, new_h, Qt.KeepAspectRatio)			
			self.lblImage.setPixmap( scaled_pixmap )
			
			# move and resize the label to be centered in the fame
			img_w = scaled_pixmap.width()
			img_h = scaled_pixmap.height()
			self.lblImage.resize( img_w, img_h )
			self.lblImage.move( (frame_w - img_w)/2, (frame_h - img_h)/2 )
			
	def showPopup( self ):
		self.popup = ImagePopup(self, self.current_pixmap)
コード例 #20
0
    def performQuery(self):

        QtGui.QApplication.setOverrideCursor(
            QtGui.QCursor(QtCore.Qt.WaitCursor))

        try:
            comicVine = ComicVineTalker()
            volume_data = comicVine.fetchVolumeData(self.series_id)
            self.issue_list = comicVine.fetchIssuesByVolume(self.series_id)
        except ComicVineTalkerException as e:
            QtGui.QApplication.restoreOverrideCursor()
            if e.code == ComicVineTalkerException.RateLimit:
                QtGui.QMessageBox.critical(
                    self, self.tr("Comic Vine Error"),
                    ComicVineTalker.getRateLimitMessage())
            else:
                QtGui.QMessageBox.critical(
                    self, self.tr("Network Issue"),
                    self.tr("Could not connect to ComicVine to list issues!"))
            return

        while self.twList.rowCount() > 0:
            self.twList.removeRow(0)

        self.twList.setSortingEnabled(False)

        row = 0
        for record in self.issue_list:
            self.twList.insertRow(row)

            item_text = record['issue_number']
            item = IssueNumberTableWidgetItem(item_text)
            item.setData(QtCore.Qt.ToolTipRole, item_text)
            item.setData(QtCore.Qt.UserRole, record['id'])
            item.setData(QtCore.Qt.DisplayRole, item_text)
            item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
            self.twList.setItem(row, 0, item)

            item_text = record['cover_date']
            if item_text is None:
                item_text = ""
            #remove the day of "YYYY-MM-DD"
            parts = item_text.split("-")
            if len(parts) > 1:
                item_text = parts[0] + "-" + parts[1]

            item = QtGui.QTableWidgetItem(item_text)
            item.setData(QtCore.Qt.ToolTipRole, item_text)
            item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
            self.twList.setItem(row, 1, item)

            item_text = record['name']
            if item_text is None:
                item_text = ""
            item = QtGui.QTableWidgetItem(item_text)
            item.setData(QtCore.Qt.ToolTipRole, item_text)
            item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
            self.twList.setItem(row, 2, item)

            if IssueString(
                    record['issue_number']).asString().lower() == IssueString(
                        self.issue_number).asString().lower():
                self.initial_id = record['id']

            row += 1

        self.twList.setSortingEnabled(True)
        self.twList.sortItems(0, QtCore.Qt.AscendingOrder)

        QtGui.QApplication.restoreOverrideCursor()
コード例 #21
0
    def searchComplete(self):
        self.progdialog.accept()
        if self.search_thread.cv_error:
            if self.search_thread.error_code == ComicVineTalkerException.RateLimit:
                QtGui.QMessageBox.critical(
                    self, self.tr("Comic Vine Error"),
                    ComicVineTalker.getRateLimitMessage())
            else:
                QtGui.QMessageBox.critical(
                    self, self.tr("Network Issue"),
                    self.tr(
                        "Could not connect to Comic Vine to search for series!"
                    ))
            return

        self.cv_search_results = self.search_thread.cv_search_results
        self.updateButtons()

        self.twList.setSortingEnabled(False)

        while self.twList.rowCount() > 0:
            self.twList.removeRow(0)

        row = 0
        for record in self.cv_search_results:
            self.twList.insertRow(row)

            item_text = record['name']
            item = QtGui.QTableWidgetItem(item_text)
            item.setData(QtCore.Qt.ToolTipRole, item_text)
            item.setData(QtCore.Qt.UserRole, record['id'])
            item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
            self.twList.setItem(row, 0, item)

            item_text = str(record['start_year'])
            item = QtGui.QTableWidgetItem(item_text)
            item.setData(QtCore.Qt.ToolTipRole, item_text)
            item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
            self.twList.setItem(row, 1, item)

            item_text = record['count_of_issues']
            item = QtGui.QTableWidgetItem(item_text)
            item.setData(QtCore.Qt.ToolTipRole, item_text)
            item.setData(QtCore.Qt.DisplayRole, record['count_of_issues'])
            item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
            self.twList.setItem(row, 2, item)

            if record['publisher'] is not None:
                item_text = record['publisher']['name']
                item.setData(QtCore.Qt.ToolTipRole, item_text)
                item = QtGui.QTableWidgetItem(item_text)
                item.setFlags(QtCore.Qt.ItemIsSelectable
                              | QtCore.Qt.ItemIsEnabled)
                self.twList.setItem(row, 3, item)

            row += 1

        self.twList.resizeColumnsToContents()
        self.twList.setSortingEnabled(True)
        self.twList.sortItems(2, QtCore.Qt.DescendingOrder)
        self.twList.selectRow(0)
        self.twList.resizeColumnsToContents()

        if len(self.cv_search_results) == 0:
            QtCore.QCoreApplication.processEvents()
            QtGui.QMessageBox.information(self, "Search Result",
                                          "No matches found!")

        if self.immediate_autoselect and len(self.cv_search_results) > 0:
            # defer the immediate autoselect so this dialog has time to pop up
            QtCore.QCoreApplication.processEvents()
            QtCore.QTimer.singleShot(10, self.doImmediateAutoselect)