Added settings dialog for setting rar paths and CV api key

git-svn-id: http://comictagger.googlecode.com/svn/trunk@12 6c5673fe-1810-88d6-992b-cd32ca31540c
This commit is contained in:
beville@gmail.com 2012-11-06 20:29:18 +00:00
parent d8e528eb98
commit 1ec485de2a
9 changed files with 176 additions and 74 deletions

View File

@ -7,7 +7,9 @@ import os
import struct
import sys
import tempfile
from subprocess import call
import subprocess
import platform
import time
sys.path.insert(0, os.path.abspath(".") )
import UnRAR2
@ -151,7 +153,18 @@ class RarArchiver:
def __init__( self, path ):
self.path = path
self.rar_exe_path = None
self.devnull = open(os.devnull, "w")
# windows only, keeps the cmd.exe from popping up
if platform.system() == "Windows":
self.startupinfo = subprocess.STARTUPINFO()
self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
else:
self.startupinfo = None
def __del__(self):
self.devnull.close()
def getArchiveComment( self ):
rarc = UnRAR2.RarFile( self.path )
@ -167,8 +180,13 @@ class RarArchiver:
f.close()
# use external program to write comment to Rar archive
call([self.rar_exe_path, 'c', '-z' + tmp_name, self.path])
subprocess.call([self.rar_exe_path, 'c', '-c-', '-z' + tmp_name, self.path],
startupinfo=self.startupinfo,
stdout=self.devnull)
if platform.system() == "Darwin":
time.sleep(1)
os.remove( tmp_name)
def readArchiveFile( self, archive_file ):
@ -194,8 +212,12 @@ class RarArchiver:
f.close()
# use external program to write file to Rar archive
call([self.rar_exe_path, 'a', '-ep', self.path, tmp_file])
subprocess.call([self.rar_exe_path, 'a', '-c-', '-ep', self.path, tmp_file],
startupinfo=self.startupinfo,
stdout=self.devnull)
if platform.system() == "Darwin":
time.sleep(1)
os.remove( tmp_file)
os.rmdir( tmp_folder)
@ -203,7 +225,12 @@ class RarArchiver:
if self.rar_exe_path is not None:
# use external program to remove file from Rar archive
call([self.rar_exe_path, 'd', self.path, archive_file])
subprocess.call([self.rar_exe_path, 'd','-c-', self.path, archive_file],
startupinfo=self.startupinfo,
stdout=self.devnull)
if platform.system() == "Darwin":
time.sleep(1)
def getArchiveFilenameList( self ):
@ -227,6 +254,7 @@ class FolderArchiver:
def readArchiveFile( self, archive_file ):
data = ""
fname = os.path.join( self.path, archive_file )
try:
with open( fname, 'rb' ) as f:

View File

@ -10,7 +10,21 @@ from genericmetadata import GenericMetadata
class ComicVineTalker:
api_key = '67ac5baeba16a2f56acf7ff136a1d591324c2253'
def __init__(self, api_key):
self.api_key = api_key
def testKey( self ):
test_url = "http://api.comicvine.com/issue/1/?api_key=" + self.api_key + "&format=json&field_list=name"
resp = urllib2.urlopen( test_url )
content = resp.read()
cv_response = json.loads( content )
# Bogus request, but if the key is wrong, you get error 100: "Invalid API Key"
return cv_response[ 'status_code' ] != 100
def searchForSeries( self, series_name ):

View File

@ -4,18 +4,19 @@ from PyQt4 import QtCore, QtGui, uic
from PyQt4.QtCore import QUrl
from PyQt4.QtNetwork import QNetworkAccessManager, QNetworkRequest
from comicvinetalker import *
from comicvinetalker import ComicVineTalker
class IssueSelectionWindow(QtGui.QDialog):
volume_id = 0
def __init__(self, parent, series_id, issue_number):
def __init__(self, parent, cv_api_key, series_id, issue_number):
super(IssueSelectionWindow, self).__init__(parent)
uic.loadUi('issueselectionwindow.ui', self)
self.series_id = series_id
self.cv_api_key = cv_api_key
if issue_number is None or issue_number == "":
self.issue_number = 1
@ -45,7 +46,7 @@ class IssueSelectionWindow(QtGui.QDialog):
while self.twList.rowCount() > 0:
self.twList.removeRow(0)
comicVine = ComicVineTalker()
comicVine = ComicVineTalker( self.cv_api_key )
volume_data = comicVine.fetchVolumeData( self.series_id )
self.issue_list = volume_data['issues']
@ -101,7 +102,7 @@ class IssueSelectionWindow(QtGui.QDialog):
# We don't yet have an image URL for this issue. Make a request for URL, and hold onto it
# TODO: this should be reworked... too much UI latency, maybe chain the NAMs??
if record['url'] == None:
record['url'] = ComicVineTalker().fetchIssueCoverURL( self.issue_id )
record['url'] = ComicVineTalker( self.cv_api_key ).fetchIssueCoverURL( self.issue_id )
self.labelThumbnail.setText("loading...")
self.nam = QNetworkAccessManager()

View File

@ -11,6 +11,10 @@ import xml
from pprint import pprint
from PyQt4 import QtCore, QtGui
import signal
import os
from settings import ComicTaggerSettings
from taggerwindow import TaggerWindow
from options import Options, MetaDataStyle
@ -19,6 +23,7 @@ from comicarchive import ComicArchive
from comicvinetalker import ComicVineTalker
from comicinfoxml import ComicInfoXml
from comicbookinfo import ComicBookInfo
import utils
#-----------------------------
def cliProcedure( opts ):
@ -52,22 +57,13 @@ def cliProcedure( opts ):
def main():
opts = Options()
opts.parseCmdLineArgs()
settings = ComicTaggerSettings()
# make sure unrar program is in the path for the UnRAR class
utils.addtopath(os.path.dirname(settings.unrar_exe_path))
signal.signal(signal.SIGINT, signal.SIG_DFL)
#ca = ComicArchive( opts.filename )
#metadata = ca.readMetadata( MetaDataStyle.CBI )
#ca.writeMetadata( metadata, MetaDataStyle.CIX )
#ComicInfoXml().writeToExternalFile( "test.xml", metadata )
#ComicBookInfo().writeToExternalFile("test.json", metadata)
#quit()
if opts.no_gui:
cliProcedure( opts )
@ -75,7 +71,7 @@ def main():
else:
app = QtGui.QApplication(sys.argv)
tagger_window = TaggerWindow( opts )
tagger_window = TaggerWindow( opts, settings )
tagger_window.show()
sys.exit(app.exec_())

View File

@ -1,6 +1,7 @@
from PyQt4 import QtCore, QtGui, uic
import locale
import platform
from volumeselectionwindow import VolumeSelectionWindow
from options import Options, MetaDataStyle
@ -8,6 +9,8 @@ from genericmetadata import GenericMetadata
from comicvinetalker import ComicVineTalker
from comicarchive import ComicArchive
from crediteditorwindow import CreditEditorWindow
from settingswindow import SettingsWindow
from settings import ComicTaggerSettings
import utils
# this reads the environment and inits the right locale
@ -19,7 +22,7 @@ class TaggerWindow( QtGui.QMainWindow):
appName = "ComicTagger"
def __init__(self, opts , parent = None):
def __init__(self, opts, settings, parent = None):
super(TaggerWindow, self).__init__(parent)
uic.loadUi('taggerwindow.ui', self)
@ -27,8 +30,10 @@ class TaggerWindow( QtGui.QMainWindow):
self.center()
self.raise_()
print platform.system(), platform.release()
self.dirtyFlag = False
self.opts = opts
self.settings = settings
self.data_style = opts.data_style
#set up a default metadata object
@ -116,6 +121,10 @@ class TaggerWindow( QtGui.QMainWindow):
self.actionRepackage.setStatusTip( 'Re-create archive as CBZ' )
self.actionRepackage.triggered.connect( self.repackageArchive )
#self.actionRepackage.setShortcut( )
self.actionSettings.setStatusTip( 'Configure ComicTagger' )
self.actionSettings.triggered.connect( self.showSettings )
# Tag Menu
self.actionParse_Filename.setShortcut( 'Ctrl+F' )
self.actionParse_Filename.setStatusTip( 'Try to extract tags from filename' )
@ -171,8 +180,9 @@ class TaggerWindow( QtGui.QMainWindow):
return
ca = ComicArchive( path )
ca.setExternalRarProgram( "/usr/bin/rar" )
if self.settings.rar_exe_path != "":
ca.setExternalRarProgram( self.settings.rar_exe_path )
if ca is not None and ca.seemsToBeAComicArchive():
# clear form and current metadata, we're all in!
@ -329,7 +339,6 @@ class TaggerWindow( QtGui.QMainWindow):
assignText( self.teComments, md.comments )
assignText( self.teNotes, md.notes )
assignText( self.leCriticalRating, md.criticalRating )
assignText( self.leMaturityRating, md.maturityRating )
assignText( self.leStoryArc, md.storyArc )
assignText( self.leScanInfo, md.scanInfo )
assignText( self.leSeriesGroup, md.seriesGroup )
@ -341,7 +350,14 @@ class TaggerWindow( QtGui.QMainWindow):
assignText( self.teTeams, md.teams )
assignText( self.teLocations, md.locations )
assignText( self.leFormat, md.format )
if md.maturityRating is not None and md.maturityRating != "":
i = self.cbMaturityRating.findText( md.maturityRating )
if i == -1:
self.cbMaturityRating.setEditText( md.maturityRating )
else:
self.cbMaturityRating.setCurrentIndex( i )
if md.language is not None:
i = self.cbLanguage.findData( md.language )
self.cbLanguage.setCurrentIndex( i )
@ -432,7 +448,7 @@ class TaggerWindow( QtGui.QMainWindow):
md.comments = xlate( self.teComments.toPlainText(), "str" )
md.notes = xlate( self.teNotes.toPlainText(), "str" )
md.criticalRating = xlate( self.leCriticalRating.text(), "int" )
md.maturityRating = xlate( self.leMaturityRating.text(), "str" )
md.maturityRating = xlate( self.cbMaturityRating.currentText(), "str" )
md.storyArc = xlate( self.leStoryArc.text(), "str" )
md.scanInfo = xlate( self.leScanInfo.text(), "str" )
@ -504,6 +520,13 @@ class TaggerWindow( QtGui.QMainWindow):
def queryOnline(self):
if self.settings.cv_api_key == "":
QtGui.QMessageBox.warning(self, self.tr("Online Query"),
self.tr("You need an API key from ComicVine to search online. " +
"Go to settings and enter it."))
return
if str(self.leSeries.text()).strip() != "":
series_name = str(self.leSeries.text()).strip()
@ -513,14 +536,14 @@ class TaggerWindow( QtGui.QMainWindow):
issue_number = str(self.leIssueNum.text()).strip()
selector = VolumeSelectionWindow( self, series_name, issue_number )
selector = VolumeSelectionWindow( self, self.settings.cv_api_key, series_name, issue_number )
selector.setModal(True)
selector.exec_()
if selector.result():
#we should now have a volume ID
comicVine = ComicVineTalker()
comicVine = ComicVineTalker( self.settings.cv_api_key )
self.metadata = comicVine.fetchIssueData( selector.volume_id, selector.issue_number )
# Now push the right data into the edit controls
@ -595,7 +618,7 @@ class TaggerWindow( QtGui.QMainWindow):
self.leStoryArc, self.leScanInfo, self.leSeriesGroup,
self.leAltSeries, self.leAltIssueNum, self.leAltIssueCount,
self.leWebLink, self.teCharacters, self.teTeams,
self.teLocations, self.leMaturityRating, self.leFormat
self.teLocations, self.cbMaturityRating, self.leFormat
]
if self.data_style == MetaDataStyle.CIX:
@ -677,6 +700,13 @@ class TaggerWindow( QtGui.QMainWindow):
self.twCredits.removeRow( row )
self.setDirtyFlag()
def showSettings( self ):
settingswin = SettingsWindow( self, self.settings )
settingswin.setModal(True)
settingswin.exec_()
if settingswin.result():
pass
def center(self):
screen = QtGui.QDesktopWidget().screenGeometry()
@ -716,6 +746,22 @@ class TaggerWindow( QtGui.QMainWindow):
self.cbManga.addItem( "Yes (Right to Left)", "YesAndRightToLeft" )
self.cbManga.addItem( "No", "No" )
# Add the entries to the maturity combobox
self.cbMaturityRating.addItem( "", "" )
self.cbMaturityRating.addItem( "Everyone", "" )
self.cbMaturityRating.addItem( "G", "" )
self.cbMaturityRating.addItem( "Early Childhood", "" )
self.cbMaturityRating.addItem( "Everyone 10+", "" )
self.cbMaturityRating.addItem( "PG", "" )
self.cbMaturityRating.addItem( "Kids to Adults", "" )
self.cbMaturityRating.addItem( "Teen", "" )
self.cbMaturityRating.addItem( "MA15+", "" )
self.cbMaturityRating.addItem( "Mature 17+", "" )
self.cbMaturityRating.addItem( "R18+", "" )
self.cbMaturityRating.addItem( "X18+", "" )
self.cbMaturityRating.addItem( "Adults Only 18+", "" )
self.cbMaturityRating.addItem( "Rating Pending", "" )
def removeCBLTags( self ):
self.removeTags( MetaDataStyle.CBI )

View File

@ -323,9 +323,6 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="leMaturityRating"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
@ -336,6 +333,16 @@
<item row="0" column="1">
<widget class="QLineEdit" name="leCriticalRating"/>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="cbMaturityRating">
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="formLayoutWidget_9">
@ -702,6 +709,7 @@
<addaction name="actionRepackage"/>
<addaction name="menuReload"/>
<addaction name="menuRemove"/>
<addaction name="actionSettings"/>
<addaction name="actionExit"/>
</widget>
<widget class="QMenu" name="menuHelp">
@ -805,6 +813,11 @@
<string>Reload Selected Tag Style</string>
</property>
</action>
<action name="actionSettings">
<property name="text">
<string>Settings...</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>

View File

@ -1,15 +1,6 @@
Verification prompt for removing tags
Add License/Copyright headers
ComicArchive support for folders
ComicArchive support for reading RARs
API Key config
Toolbar icons
Consolidate Credit Roles for english variants? : Penciler vs Penciller
@ -20,7 +11,8 @@ TaggerWindow entry fields
General layout
Special Dialogs needed for:
Pages Info
Color changing stuff need more work
- Indicate credits for CR style
CR has editable dropdowns/comboboxes for Format, Publisher, Imprint
-----------
@ -33,12 +25,9 @@ Lots of error checking
Archive function to detect tag blocks out of sync
Use external RAR tools to generate rar with CIX!
Hourglass popup, or whatever, for when busy
Idea: Support only CBI or CIX for any given file, and not both
Determine style when opening file, and set that as current save style
If user selects different one, warn about potential loss/re-arranging of data
Longer term:
@ -46,17 +35,23 @@ Longer term:
Maybe: keep a history of tagged volumes IDs from CV, and present those first
Remember preferred style (and other stuff) (prolly kept in ~/.comictagger.conf, or some such)
Other settings possibilities:
Last tag style
Last "Open" folder (include dragged)
Keep a history of queries somewhere??
Content Hashes!!
App option to covert RAR to ZIP
If no unrar in path, then filter out CBR/RAR from open dialog
"Select Issues" dialog request cover URLs in background
"Select Issues" dialog cache cover images
----------------------------------------------
COMIC RACK Questions
Missing from XML as enterable in ComicRack:
Main Character or Team
@ -69,18 +64,3 @@ Some that seem library only:
Proposed Values
Community Rating
Age Rating:
Adults Only 18+
Early Childhood
Everyone
Everyone 10+
G
Kids to Adults
MA15+
Mature 17+
PG
r18+
Rating Pending
Teen
X18+

View File

@ -1,5 +1,7 @@
# coding=utf-8
import os
def listToString( l ):
string = ""
if l is not None:
@ -9,7 +11,28 @@ def listToString( l ):
string += item
return string
def which(program):
import os
def is_exe(fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
fpath, fname = os.path.split(program)
if fpath:
if is_exe(program):
return program
else:
for path in os.environ["PATH"].split(os.pathsep):
exe_file = os.path.join(path, program)
if is_exe(exe_file):
return exe_file
return None
def addtopath( dir ):
# TODO only add if not there already
if dir is not None and dir != "":
os.environ['PATH'] = dir + os.pathsep + os.environ['PATH']
# -o- coding: utf-8 -o-
# ISO639 python dict

View File

@ -11,13 +11,14 @@ class VolumeSelectionWindow(QtGui.QDialog):
volume_id = 0
def __init__(self, parent, series_name, issue_number):
def __init__(self, parent, cv_api_key, series_name, issue_number):
super(VolumeSelectionWindow, self).__init__(parent)
uic.loadUi('volumeselectionwindow.ui', self)
self.series_name = series_name
self.issue_number = issue_number
self.cv_api_key = cv_api_key
self.performQuery()
@ -34,7 +35,7 @@ class VolumeSelectionWindow(QtGui.QDialog):
self.twList.selectRow(0)
def showIssues( self ):
selector = IssueSelectionWindow( self, self.volume_id, self.issue_number )
selector = IssueSelectionWindow( self, self.cv_api_key, self.volume_id, self.issue_number )
selector.setModal(True)
selector.exec_()
if selector.result():
@ -48,7 +49,7 @@ class VolumeSelectionWindow(QtGui.QDialog):
while self.twList.rowCount() > 0:
self.twList.removeRow(0)
comicVine = ComicVineTalker()
comicVine = ComicVineTalker( self.cv_api_key )
self.cv_search_results = comicVine.searchForSeries( self.series_name )
self.twList.setSortingEnabled(False)