2012-08-21 19:28:14 +02:00
# -*- coding: utf-8 -*-
"""
Module implementing Qwad ' s main window
"""
from PyQt4 . QtGui import QMainWindow , QFileDialog , QMessageBox , QLabel
from PyQt4 . QtCore import pyqtSignature , QString , QT_TR_NOOP , SIGNAL , QObject
from WiiPy . archive import WAD
from WiiPy . title import NUS , TMD
from Ui_VenPri import Ui_Qwad
from shutil import rmtree
from threading import Thread
import TitleIDs
import tempfile , os , time
2012-08-22 22:29:02 +02:00
import binascii
2012-08-21 19:28:14 +02:00
CWD = os . getcwd ( )
2013-06-17 19:38:09 +02:00
def str2bool ( v ) :
return v . lower ( ) in ( " yes " , " true " , " t " , " 1 " )
2012-08-21 19:28:14 +02:00
class MWQwad ( QMainWindow , Ui_Qwad ) :
"""
Class documentation goes here .
"""
def __init__ ( self , parent = None ) :
"""
Constructor
"""
QMainWindow . __init__ ( self , parent )
self . setupUi ( self )
self . defaultversion = self . trUtf8 ( """ (Latest) """ )
2012-08-21 21:50:18 +02:00
self . availableVersions . setText ( " (---) " )
2012-08-21 19:28:14 +02:00
self . VersionlineEdit . setText ( self . defaultversion )
2012-08-21 20:06:52 +02:00
for key in TitleIDs . sorted_copy ( TitleIDs . TitleDict ) :
2012-08-21 19:28:14 +02:00
self . comboBox . addItem ( key )
2012-08-23 13:35:48 +02:00
for key in TitleIDs . SupportedRegions :
self . ChooseRegion . addItem ( key )
2012-08-21 19:28:14 +02:00
self . getReady ( )
2012-08-23 13:35:48 +02:00
self . default_region = " "
2012-08-21 19:28:14 +02:00
def Status ( self , status ) :
print status
self . setEnabled ( False )
self . statusBar . showMessage ( status )
def getReady ( self ) :
self . setEnabled ( True )
self . statusBar . showMessage ( self . trUtf8 ( " Ready " ) )
os . chdir ( CWD )
print " Done. "
def ErrorDiag ( self , error = QT_TR_NOOP ( " Unknown error " ) ) :
print error
QMessageBox . critical ( None ,
self . trUtf8 ( " Error " ) ,
self . trUtf8 ( """ An error has ocurred: """ ) + " " + str ( error ) ,
QMessageBox . StandardButtons ( \
QMessageBox . Ok ) ,
QMessageBox . Ok )
def loadTMD ( self , tmdpath ) : #TODO: TMD viewer
"""
Displays _TMD information in the UI
"""
tmd = TMD ( ) . loadFile ( tmdpath )
self . TitleID . setText ( " %016x " % tmd . tmd . titleid )
2012-11-25 13:44:20 +01:00
tid = " %016x " % tmd . tmd . titleid
tid = tid [ 8 : ]
asc = ' ' . join ( [ chr ( int ( ' ' . join ( c ) , 16 ) ) for c in zip ( tid [ 0 : : 2 ] , tid [ 1 : : 2 ] ) ] )
self . idASCII . setText ( " %s " % asc )
2012-08-22 22:29:02 +02:00
self . IOSversion . setText ( TitleIDs . TitleSwapDict [ " %s " % ( " %016x " % tmd . tmd . iosversion ) ] )
2012-08-21 19:28:14 +02:00
self . TitleType . setText ( str ( tmd . tmd . title_type ) )
self . GroupID . setText ( str ( tmd . tmd . group_id ) )
2012-08-22 22:29:02 +02:00
self . Reserved . setText ( str ( tmd . tmd . reserved ) )
2012-08-21 19:28:14 +02:00
self . AccessRights . setText ( str ( tmd . tmd . access_rights ) )
self . Version . setText ( str ( tmd . tmd . title_version ) )
self . Contents . setText ( str ( tmd . tmd . numcontents ) )
self . BootIndex . setText ( str ( tmd . tmd . boot_index ) )
@pyqtSignature ( " " )
def on_BotonRutaWad_clicked ( self ) :
"""
Get path to WAD file
"""
WadPath = QFileDialog . getOpenFileName ( \
None ,
self . trUtf8 ( " Select WAD file " ) ,
QString ( ) ,
self . trUtf8 ( " *.wad; *.WAD " ) ,
None )
if WadPath != " " :
self . MuestraRutaWad . setText ( WadPath )
@pyqtSignature ( " " )
def on_BotonRutaExtraer_clicked ( self ) :
"""
WAD contents output path
"""
OutputDir = QFileDialog . getExistingDirectory ( \
None ,
self . trUtf8 ( " Select where to store WAD contents " ) ,
QString ( ) ,
QFileDialog . Options ( QFileDialog . ShowDirsOnly ) )
if OutputDir != " " :
self . MuestraRutaExtraer . setText ( OutputDir )
@pyqtSignature ( " " )
def on_Desempaqueta_clicked ( self ) :
"""
Unpack wad
"""
try :
self . unpack = Unpacking ( str ( self . MuestraRutaWad . text ( ) ) , str ( self . MuestraRutaExtraer . text ( ) ) , self )
self . unpack . start ( )
except Exception , e :
self . ErrorDiag ( e )
@pyqtSignature ( " " )
def on_BotonRutaEmpaquetado_clicked ( self ) :
"""
Select where to save the newly created WAD
"""
NewWadPath = QFileDialog . getSaveFileName ( \
None ,
self . trUtf8 ( " Select where to save the newly created WAD " ) ,
QString ( " output.wad " ) ,
self . trUtf8 ( " *.wad; *.WAD " ) ,
None )
if NewWadPath != " " :
self . MuestraRutaEmpaquetado . setText ( NewWadPath )
@pyqtSignature ( " " )
def on_BotonRutaDesempaquetado_clicked ( self ) :
"""
Get path off folder to pack .
"""
Dir2Wad = QFileDialog . getExistingDirectory ( \
None ,
self . trUtf8 ( " Select folder to pack into WAD " ) ,
QString ( ) ,
QFileDialog . Options ( QFileDialog . ShowDirsOnly ) )
if Dir2Wad != " " :
self . MuestraRutaDesempaquetado . setText ( Dir2Wad )
@pyqtSignature ( " " )
def on_Empaqueta_clicked ( self ) :
"""
Create WAD
"""
self . setEnabled ( False )
try :
self . packing = Packing ( str ( self . MuestraRutaDesempaquetado . text ( ) ) , str ( self . MuestraRutaEmpaquetado . text ( ) ) , self )
self . packing . start ( )
except Exception , e :
self . ErrorDiag ( e )
self . setEnabled ( True )
@pyqtSignature ( " " )
def on_actionAcerca_de_Qwad_triggered ( self ) :
"""
About Qwad
"""
from AboutQwad import AboutQwad
Pop = AboutQwad ( )
Pop . exec_ ( )
@pyqtSignature ( " " )
def on_actionAbout_Qt_triggered ( self ) :
"""
About Qt
"""
QMessageBox . aboutQt ( None ,
self . trUtf8 ( " About Qt " ) )
@pyqtSignature ( " " )
def on_Download_from_NUS_clicked ( self ) :
"""
Start doing the actual work . . . well , in fact , the actual work is done by Wii . py
"""
try :
version = self . VersionlineEdit . text ( )
if version == self . defaultversion :
print " downloading latest version "
version = None
else :
version = str ( version )
print " downloading version " + version
outputdir = str ( self . NusOutputPath . text ( ) )
self . nusdow = nusDownloading ( int ( str ( self . enteredTitleID . text ( ) ) . lower ( ) , 16 ) , version , outputdir , self . decryptCheck . isChecked ( ) , self )
self . nusdow . start ( )
except Exception , e :
self . ErrorDiag ( e )
@pyqtSignature ( " " )
def on_NusOutputButton_clicked ( self ) :
"""
Selects the output path
"""
if self . pack_in_WAD_checkbox . isChecked ( ) :
outputdir = QFileDialog . getSaveFileName ( \
None ,
self . trUtf8 ( " Select where to save the downloaded WAD " ) ,
QString ( ) ,
self . trUtf8 ( " *.wad; *.WAD " ) ,
None )
else :
outputdir = QFileDialog . getExistingDirectory ( \
None ,
self . trUtf8 ( " Select the directory where store the downloaded files " ) ,
QString ( ) ,
QFileDialog . Options ( QFileDialog . ShowDirsOnly ) )
if outputdir != " " :
self . NusOutputPath . setText ( outputdir )
@pyqtSignature ( " QString " )
def on_comboBox_currentIndexChanged ( self , selection ) :
"""
Show the title ID of the selected title
"""
2012-08-23 13:35:48 +02:00
if self . comboBox . findText ( selection ) == 0 :
self . enteredTitleID . setText ( " " )
self . availableVersions . setText ( " " )
elif self . comboBox . findText ( selection ) > 0 :
2012-08-21 19:28:14 +02:00
self . enteredTitleID . enabled = False
self . enteredTitleID . setText ( TitleIDs . TitleDict [ str ( selection ) ] )
2012-08-21 19:29:25 +02:00
self . availableVersions . setText ( TitleIDs . IOSdict [ str ( selection ) ] )
2012-08-21 19:28:14 +02:00
2012-08-21 20:46:05 +02:00
@pyqtSignature ( " QString " )
def on_comboBox2_currentIndexChanged ( self , selection ) :
"""
Show the title ID of the selected title
"""
2012-08-23 13:35:48 +02:00
if self . comboBox2 . findText ( selection ) == 0 :
self . enteredTitleID . setText ( " " )
self . availableVersions . setText ( " " )
elif self . comboBox2 . findText ( selection ) > 0 :
2012-08-21 20:46:05 +02:00
self . enteredTitleID . enabled = False
2012-08-23 13:35:48 +02:00
if self . default_region == " JAP " :
self . enteredTitleID . setText ( TitleIDs . ChannelJAPDict [ str ( selection ) ] )
self . availableVersions . setText ( TitleIDs . ChannelJAPVerDict [ str ( selection ) ] )
elif self . default_region == " PAL " :
self . enteredTitleID . setText ( TitleIDs . ChannelPALDict [ str ( selection ) ] )
self . availableVersions . setText ( TitleIDs . ChannelPALVerDict [ str ( selection ) ] )
elif self . default_region == " USA " :
self . enteredTitleID . setText ( TitleIDs . ChannelUSADict [ str ( selection ) ] )
self . availableVersions . setText ( TitleIDs . ChannelUSAVerDict [ str ( selection ) ] )
@pyqtSignature ( " QString " )
def on_ChooseRegion_currentIndexChanged ( self , selection ) :
self . default_region = " JAP "
if self . default_region != " " :
count = self . comboBox2 . count ( )
while count > - 1 :
self . comboBox2 . removeItem ( count )
count = count - 1
if self . ChooseRegion . findText ( selection ) != 0 :
self . default_region = str ( selection )
self . comboBox2 . addItem ( " Choose Channel " )
if self . default_region == " JAP " :
for key in TitleIDs . sorted_copy ( TitleIDs . ChannelJAPDict ) :
self . comboBox2 . addItem ( key )
elif self . default_region == " PAL " :
for key in TitleIDs . sorted_copy ( TitleIDs . ChannelPALDict ) :
self . comboBox2 . addItem ( key )
elif self . default_region == " USA " :
for key in TitleIDs . sorted_copy ( TitleIDs . ChannelUSADict ) :
self . comboBox2 . addItem ( key )
2012-08-21 20:46:05 +02:00
2012-08-21 19:28:14 +02:00
@pyqtSignature ( " " )
def on_enteredTitleID_returnPressed ( self ) :
"""
Place combobox un custom titleid
"""
self . comboBox . setCurrentIndex ( 0 )
@pyqtSignature ( " int " )
def on_pack_in_WAD_checkbox_stateChanged ( self , state ) :
"""
Clear output path , because we change output type
"""
self . NusOutputPath . clear ( )
if state == 2 :
self . decryptCheck . setChecked ( False )
self . decryptCheck . setEnabled ( False )
elif state == 0 :
self . decryptCheck . setChecked ( True )
self . decryptCheck . setEnabled ( True )
elif state == 1 :
print " OMG, what are you doing? "
else :
print " This is the end of the world. For PyQt4, at least "
@pyqtSignature ( " " )
def on_TMDfilepath_returnPressed ( self ) :
"""
Trigger loadTMD
"""
self . loadTMD ( str ( self . TMDfilepath . text ( ) ) )
@pyqtSignature ( " " )
def on_TMDfilebutton_clicked ( self ) :
"""
Trigger loadTMD
"""
tmdpath = QFileDialog . getOpenFileName ( \
None ,
self . trUtf8 ( " Select a TMD file " ) ,
QString ( ) ,
2013-09-16 19:47:13 +02:00
self . trUtf8 ( " *.tmd; *.TMD; tmd; TMD " ) ,
2012-08-21 19:28:14 +02:00
None ,
QFileDialog . Options ( QFileDialog . DontResolveSymlinks ) )
if tmdpath != " " :
self . TMDfilepath . setText ( tmdpath )
self . loadTMD ( str ( tmdpath ) )
#Here useful thread classes
class Unpacking ( Thread ) :
def __init__ ( self , wadpath , dirpath , QMW ) :
Thread . __init__ ( self )
self . wadpath = wadpath
self . dirpath = dirpath
self . QMW = QMW
self . qobject = QObject ( )
self . qobject . connect ( self . qobject , SIGNAL ( " working " ) , self . QMW . Status )
self . qobject . connect ( self . qobject , SIGNAL ( " Exception " ) , self . QMW . ErrorDiag )
self . qobject . connect ( self . qobject , SIGNAL ( " Done " ) , self . QMW . getReady )
def run ( self ) :
self . qobject . emit ( SIGNAL ( " working " ) , UNPACKING )
try :
WAD . loadFile ( self . wadpath ) . dumpDir ( self . dirpath )
except Exception , e :
print e
self . qobject . emit ( SIGNAL ( " Exception " ) , e )
self . qobject . emit ( SIGNAL ( " Done " ) )
2012-11-19 23:00:16 +01:00
class UnpackingCLI ( Thread ) :
def __init__ ( self , wadpath , dirpath ) :
Thread . __init__ ( self )
self . wadpath = wadpath
self . dirpath = dirpath
def run ( self ) :
try :
WAD . loadFile ( self . wadpath ) . dumpDir ( self . dirpath )
except Exception , e :
print e
print " Done "
2012-08-21 19:28:14 +02:00
class Packing ( Unpacking ) :
def __init__ ( self , dirpath , wadpath , QMW , deletedir = False ) :
Unpacking . __init__ ( self , wadpath , dirpath , QMW )
self . deletedir = deletedir
def run ( self ) :
self . qobject . emit ( SIGNAL ( " working " ) , PACKING )
try :
print self . wadpath
2013-06-17 10:00:37 +02:00
print self . dirpath
WAD . loadDir ( self . dirpath ) . dumpFile ( self . wadpath )
2012-08-21 19:28:14 +02:00
if self . deletedir :
print " Cleaning temporary files "
self . qobject . emit ( SIGNAL ( " working " ) , CLEANING )
rmtree ( self . dirpath )
except Exception , e :
if self . deletedir :
print " Cleaning temporary files "
self . qobject . emit ( SIGNAL ( " working " ) , CLEANING )
rmtree ( self . dirpath )
print e
self . qobject . emit ( SIGNAL ( " Exception " ) , e )
self . qobject . emit ( SIGNAL ( " Done " ) )
2012-11-19 23:00:16 +01:00
class PackingCLI ( UnpackingCLI ) :
def __init__ ( self , dirpath , wadpath , deletedir = False ) :
UnpackingCLI . __init__ ( self , wadpath , dirpath )
self . deletedir = deletedir
def run ( self ) :
try :
print self . dirpath
print self . wadpath
WAD . loadDir ( self . dirpath ) . dumpFile ( self . wadpath )
if self . deletedir :
print " Cleaning temporary files "
rmtree ( self . dirpath )
except Exception , e :
if self . deletedir :
print " Cleaning temporary files "
rmtree ( self . dirpath )
print e
print " Done "
2012-08-21 19:28:14 +02:00
class nusDownloading ( Unpacking ) :
def __init__ ( self , titleid , version , outputdir , decrypt , QMW ) :
Unpacking . __init__ ( self , None , outputdir , QMW )
if version != None :
self . version = int ( version )
else :
self . version = None
self . decrypt = decrypt
self . titleid = titleid
2013-06-17 10:00:37 +02:00
print self . titleid
print self . version
2012-08-21 19:28:14 +02:00
def run ( self ) :
self . qobject . emit ( SIGNAL ( " working " ) , DOWNLOADING )
try :
if self . QMW . pack_in_WAD_checkbox . isChecked ( ) :
self . dirpath = tempfile . gettempdir ( ) + " /NUS_ " + str ( time . time ( ) ) . replace ( " . " , " " ) # A safe place for temporary files
NUS ( self . titleid , self . version ) . download ( self . dirpath , decrypt = self . decrypt )
self . packing = Packing ( self . dirpath , str ( self . QMW . NusOutputPath . text ( ) ) , self . QMW , True )
self . packing . start ( )
else :
NUS ( self . titleid , self . version ) . download ( self . dirpath , decrypt = self . decrypt )
self . qobject . emit ( SIGNAL ( " Done " ) )
except Exception , e :
print e
Errormsg = str ( e ) + " . " + QT_TR_NOOP ( QString ( " Title % 1 version % 2 maybe isn ' t available for download on NUS. " ) . arg ( str ( self . titleid ) ) . arg ( str ( self . version ) ) )
self . qobject . emit ( SIGNAL ( " Exception " ) , Errormsg )
self . qobject . emit ( SIGNAL ( " Done " ) )
2012-11-19 23:00:16 +01:00
class nusDownloadingCLI ( UnpackingCLI ) :
def __init__ ( self , titleid , version , outputdir , decrypt , pack ) :
UnpackingCLI . __init__ ( self , None , outputdir )
if version != None :
self . version = int ( version )
else :
self . version = None
2013-06-17 19:38:09 +02:00
self . decrypt = str2bool ( decrypt )
self . pack = str2bool ( pack )
2012-11-19 23:00:16 +01:00
self . titleid = titleid
self . outputdir = outputdir
def run ( self ) :
try :
if self . pack :
self . dirpath = tempfile . gettempdir ( ) + " /NUS_ " + str ( time . time ( ) ) . replace ( " . " , " " )
2013-06-17 10:00:37 +02:00
NUS ( self . titleid , self . version ) . download ( self . dirpath , decrypt = self . decrypt )
2012-11-19 23:00:16 +01:00
self . packing = PackingCLI ( self . dirpath , str ( self . outputdir ) , True )
self . packing . start ( )
else :
2013-06-17 19:38:09 +02:00
NUS ( self . titleid , self . version ) . download ( self . outputdir , decrypt = self . decrypt )
2012-11-19 23:00:16 +01:00
except Exception , e :
print e
2012-11-25 13:44:20 +01:00
def ShowTMD ( tmdpath ) :
"""
Displays _TMD information in the CLI
"""
tmd = TMD ( ) . loadFile ( tmdpath )
print " Title ID (HEX) : %016x " % tmd . tmd . titleid
tid = " %016x " % tmd . tmd . titleid
tid = tid [ 8 : ]
asc = ' ' . join ( [ chr ( int ( ' ' . join ( c ) , 16 ) ) for c in zip ( tid [ 0 : : 2 ] , tid [ 1 : : 2 ] ) ] )
print " Title ID (ASCII) : %s " % asc
print " Title Version : %s " % tmd . tmd . title_version
print " Title Boot Index : %s " % tmd . tmd . boot_index
print " Title Contents : %s " % tmd . tmd . numcontents
2013-06-17 10:00:37 +02:00
if ( " %016x " % tmd . tmd . iosversion ) == " 0000000000000000 " :
print " Title IOS : -- "
else :
print " Title IOS : %s " % TitleIDs . TitleSwapDict [ " %s " % ( " %016x " % tmd . tmd . iosversion ) ]
2012-11-25 13:44:20 +01:00
print " Title Access Rights: %s " % tmd . tmd . access_rights
print " Title Type : %s " % tmd . tmd . title_type
print " Title Group ID : %s " % tmd . tmd . group_id
print " Title Reserved : %s " % ' ' . join ( str ( tmd . tmd . reserved ) )
2012-08-21 19:28:14 +02:00
#Statusbar messages
#FIXME: Why don't they get translated? It's frustrating
DOWNLOADING = QT_TR_NOOP ( " Downloading files from NUS... This may take a while, please, be patient. " )
UNPACKING = QT_TR_NOOP ( " Unpacking WAD... " )
PACKING = QT_TR_NOOP ( " Packing into WAD... " )
CLEANING = QT_TR_NOOP ( " Cleaning temporary files... " )