mirror of
https://github.com/mupen64plus/mupen64plus-ui-python.git
synced 2025-04-02 10:51:53 -04:00
support multiple files in archives
This commit is contained in:
parent
ade2ede291
commit
c901c27246
3 changed files with 110 additions and 92 deletions
|
@ -15,7 +15,6 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import bz2
|
||||
import gzip
|
||||
import zipfile
|
||||
|
@ -23,12 +22,7 @@ import shutil
|
|||
import tempfile
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
try:
|
||||
from m64py.utils import which
|
||||
except ImportError, err:
|
||||
sys.stderr.write("Error: Can't import m64py modules%s%s%s" % (
|
||||
os.linesep, str(err), os.linesep))
|
||||
sys.exit(1)
|
||||
from m64py.utils import which
|
||||
|
||||
try:
|
||||
import UnRAR2
|
||||
|
@ -64,12 +58,11 @@ class Archive():
|
|||
def __init__(self, filename):
|
||||
"""Opens archive."""
|
||||
self.file = os.path.realpath(filename)
|
||||
if not os.path.isfile(self.file) \
|
||||
or not os.access(self.file, os.R_OK):
|
||||
raise IOError("Cannot open %s. No such file." % (
|
||||
self.file))
|
||||
if not os.path.isfile(self.file) or not os.access(self.file, os.R_OK):
|
||||
raise IOError("Cannot open %s. No such file." % (self.file))
|
||||
|
||||
self.filetype = self.get_filetype()
|
||||
|
||||
if self.filetype == ZIP:
|
||||
self.fd = zipfile.ZipFile(self.file, 'r')
|
||||
elif self.filetype == GZIP:
|
||||
|
@ -84,41 +77,39 @@ class Archive():
|
|||
elif RAR_CMD:
|
||||
self.fd = RarCmd(self.file)
|
||||
else:
|
||||
raise IOError("UnRAR2 module or rar/unrar is needed for %s." % (
|
||||
self.file))
|
||||
raise IOError("UnRAR2 module or rar/unrar is needed for %s." % (self.file))
|
||||
elif self.filetype == LZMA:
|
||||
if HAS_7Z:
|
||||
self.fd = Archive7z(open(self.file, 'rb'))
|
||||
elif LZMA_CMD:
|
||||
self.fd = LzmaCmd(self.file)
|
||||
else:
|
||||
raise IOError("lzma module or 7z is needed for %s." % (
|
||||
self.file))
|
||||
raise IOError("lzma module or 7z is needed for %s." % (self.file))
|
||||
else:
|
||||
raise IOError("File %s is not a N64 ROM file." % (
|
||||
self.file))
|
||||
raise IOError("File %s is not a N64 ROM file." % (self.file))
|
||||
|
||||
def read(self):
|
||||
"""Reads data. If archive has more then one
|
||||
file the first one is used."""
|
||||
self.namelist = self.get_namelist()
|
||||
|
||||
def read(self, filename=None):
|
||||
"""Reads data."""
|
||||
data = None
|
||||
fname = self.namelist[0] if not filename else filename
|
||||
if self.filetype == ZIP:
|
||||
data = self.fd.read(self.fd.infolist()[0])
|
||||
data = self.fd.read(fname)
|
||||
elif self.filetype == GZIP:
|
||||
data = self.fd.read()
|
||||
elif self.filetype == BZIP:
|
||||
data = self.fd.read()
|
||||
elif self.filetype == RAR:
|
||||
if HAS_RAR:
|
||||
data = self.fd.read_files()[0][1]
|
||||
data = self.fd.read_files(fname)[0][1]
|
||||
elif RAR_CMD:
|
||||
data = self.fd.read()
|
||||
data = self.fd.read(fname)
|
||||
elif self.filetype == LZMA:
|
||||
if HAS_7Z:
|
||||
data = self.fd.getmember(
|
||||
self.fd.getnames()[0]).read()
|
||||
data = self.fd.getmember(fname).read()
|
||||
elif LZMA_CMD:
|
||||
data = self.fd.read()
|
||||
data = self.fd.read(fname)
|
||||
elif self.filetype == ROM:
|
||||
data = self.fd.read()
|
||||
return data
|
||||
|
@ -131,6 +122,29 @@ class Archive():
|
|||
else:
|
||||
self.fd.close()
|
||||
|
||||
def get_namelist(self):
|
||||
"""Gets list of files in archive."""
|
||||
if self.filetype == ZIP:
|
||||
namelist = [name.filename for name in self.fd.infolist()]
|
||||
elif self.filetype == GZIP:
|
||||
namelist = [os.path.basename(self.file)]
|
||||
elif self.filetype == BZIP:
|
||||
namelist = [os.path.basename(self.file)]
|
||||
elif self.filetype == RAR:
|
||||
if HAS_RAR:
|
||||
for filename in self.fd.infoiter():
|
||||
namelist.append(filename.filename)
|
||||
elif RAR_CMD:
|
||||
namelist = self.fd.namelist
|
||||
elif self.filetype == LZMA:
|
||||
if HAS_7Z:
|
||||
namelist = self.fd.getnames()
|
||||
elif LZMA_CMD:
|
||||
namelist = self.fd.namelist
|
||||
elif self.filetype == ROM:
|
||||
namelist = [os.path.basename(self.file)]
|
||||
return namelist
|
||||
|
||||
def get_filetype(self):
|
||||
"""Gets archive type."""
|
||||
fd = open(self.file, 'rb')
|
||||
|
@ -155,13 +169,10 @@ class RarCmd:
|
|||
|
||||
def __init__(self, archive):
|
||||
"""Opens archive."""
|
||||
self.fd = None
|
||||
self.file = archive
|
||||
self.namelist = self.namelist()
|
||||
self.filename = self.namelist[0]
|
||||
self.tempdir = tempfile.mkdtemp(self.file)
|
||||
self.extract()
|
||||
self.fd = open(os.path.join(
|
||||
self.tempdir, self.filename), "rb")
|
||||
self.tempdir = tempfile.mkdtemp()
|
||||
|
||||
def namelist(self):
|
||||
"""Returns list of filenames in archive."""
|
||||
|
@ -170,21 +181,24 @@ class RarCmd:
|
|||
|
||||
def extract(self):
|
||||
"""Extracts archive to temp dir."""
|
||||
proc = Popen([RAR_CMD, 'x', '-kb', '-p-', '-o-', '-inul', '--',
|
||||
self.file, self.filename, self.tempdir],
|
||||
stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
||||
cmd = [RAR_CMD, 'x', '-kb', '-p-', '-o-', '-inul', '--',
|
||||
self.file, self.filename, self.tempdir]
|
||||
proc = Popen(cmd, stdout=PIPE, stderr=PIPE)
|
||||
out = proc.communicate()
|
||||
if out[1] != '':
|
||||
raise IOError("Error extracting file %s: %s." % (
|
||||
self.file, out[1]))
|
||||
raise IOError("Error extracting file %s: %s." % (self.file, out[1]))
|
||||
|
||||
def read(self):
|
||||
def read(self, filename=None):
|
||||
"""Reads data."""
|
||||
self.filename = self.namelist[0] if not filename else filename
|
||||
self.extract()
|
||||
self.fd = open(os.path.join(self.tempdir, self.filename), "rb")
|
||||
return self.fd.read()
|
||||
|
||||
def close(self):
|
||||
"""Closes file descriptor and clean resources."""
|
||||
self.fd.close()
|
||||
if self.fd:
|
||||
self.fd.close()
|
||||
shutil.rmtree(self.tempdir)
|
||||
|
||||
class LzmaCmd:
|
||||
|
@ -192,35 +206,35 @@ class LzmaCmd:
|
|||
|
||||
def __init__(self, archive):
|
||||
"""Opens archive."""
|
||||
self.fd = None
|
||||
self.file = archive
|
||||
self.namelist = self.namelist()
|
||||
self.filename = self.namelist[0]
|
||||
self.tempdir = tempfile.mkdtemp(self.filename)
|
||||
self.extract()
|
||||
self.fd = open(os.path.join(
|
||||
self.tempdir, self.filename), "rb")
|
||||
self.tempdir = tempfile.mkdtemp()
|
||||
|
||||
def namelist(self):
|
||||
"""Returns list of filenames in archive."""
|
||||
proc1 = Popen([LZMA_CMD, 'l', self.file], stdout=PIPE)
|
||||
proc2 = Popen(['grep', '-F', '...A'], stdin=proc1.stdout, stdout=PIPE)
|
||||
lines = [name.rstrip(os.linesep) for name in proc2.stdout.readlines()]
|
||||
proc = Popen([LZMA_CMD, 'l', self.file], stdout=PIPE)
|
||||
lines = [name.rstrip(os.linesep) for name in proc.stdout.readlines() if '...A' in name]
|
||||
return [name[53:] for name in lines]
|
||||
|
||||
def extract(self):
|
||||
"""Extracts archive to temp dir."""
|
||||
proc = Popen([LZMA_CMD, 'x', '-o'+self.tempdir, self.file, self.filename],
|
||||
stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
||||
cmd = [LZMA_CMD, 'x', '-o'+self.tempdir, self.file, self.filename]
|
||||
proc = Popen(cmd, stdout=PIPE, stderr=PIPE)
|
||||
out = proc.communicate()
|
||||
if "Error" in out[0]:
|
||||
raise IOError("Error extracting file %s: %s." % (
|
||||
self.file, out[0]))
|
||||
|
||||
def read(self):
|
||||
def read(self, filename=None):
|
||||
"""Reads data."""
|
||||
self.filename = self.namelist[0] if not filename else filename
|
||||
self.extract()
|
||||
self.fd = open(os.path.join(self.tempdir, self.filename), "rb")
|
||||
return self.fd.read()
|
||||
|
||||
def close(self):
|
||||
"""Closes file descriptor and clean resources."""
|
||||
self.fd.close()
|
||||
if self.fd:
|
||||
self.fd.close()
|
||||
shutil.rmtree(self.tempdir)
|
||||
|
|
|
@ -14,28 +14,23 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import sys
|
||||
from PyQt4.QtCore import *
|
||||
from PyQt4.QtGui import QDialog, QMessageBox, QListWidgetItem
|
||||
|
||||
from PyQt4.QtGui import QDialog, QMessageBox
|
||||
|
||||
try:
|
||||
from m64py.core.defs import FRONTEND_VERSION
|
||||
from m64py.ui.about_ui import Ui_AboutDialog
|
||||
from m64py.ui.license_ui import Ui_LicenseDialog
|
||||
except ImportError, err:
|
||||
sys.stderr.write("Error: Can't import m64py modules%s%s%s" % (
|
||||
os.linesep, str(err), os.linesep))
|
||||
sys.exit(1)
|
||||
from m64py.utils import version_split
|
||||
from m64py.core.defs import FRONTEND_VERSION
|
||||
from m64py.ui.about_ui import Ui_AboutDialog
|
||||
from m64py.ui.license_ui import Ui_LicenseDialog
|
||||
from m64py.ui.archive_ui import Ui_ArchiveDialog
|
||||
|
||||
class AboutDialog(QDialog, Ui_AboutDialog):
|
||||
def __init__(self, parent):
|
||||
QDialog.__init__(self, parent)
|
||||
self.setupUi(self)
|
||||
text = self.labelAbout.text()
|
||||
text.replace("FRONTEND_VERSION", FRONTEND_VERSION)
|
||||
text.replace("CORE_VERSION",
|
||||
str(parent.worker.m64p.core_version))
|
||||
text = text.replace("FRONTEND_VERSION", FRONTEND_VERSION)
|
||||
text = text.replace("CORE_VERSION",
|
||||
version_split(parent.worker.m64p.core_version))
|
||||
self.labelAbout.setText(text)
|
||||
self.show()
|
||||
|
||||
|
@ -51,3 +46,17 @@ class InfoDialog(QMessageBox):
|
|||
self.setText(text)
|
||||
self.setWindowTitle("Info")
|
||||
self.show()
|
||||
|
||||
class ArchiveDialog(QDialog, Ui_ArchiveDialog):
|
||||
def __init__(self, parent, files):
|
||||
QDialog.__init__(self, parent)
|
||||
self.setupUi(self)
|
||||
self.build_list(files)
|
||||
|
||||
def build_list(self, files):
|
||||
self.listWidget.clear()
|
||||
for fname in files:
|
||||
item = QListWidgetItem(fname)
|
||||
item.setData(Qt.UserRole, fname)
|
||||
self.listWidget.addItem(item)
|
||||
self.listWidget.setCurrentRow(0)
|
||||
|
|
|
@ -15,21 +15,15 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import fnmatch
|
||||
import ConfigParser
|
||||
|
||||
from PyQt4.QtGui import *
|
||||
from PyQt4.QtCore import *
|
||||
|
||||
try:
|
||||
from m64py.utils import log, md5sum
|
||||
from m64py.archive import Archive, EXT_FILTER
|
||||
from m64py.ui.romlist_ui import Ui_ROMList
|
||||
except ImportError, err:
|
||||
sys.stderr.write("Error: Can't import m64py modules%s%s%s" % (
|
||||
os.linesep, str(err), os.linesep))
|
||||
sys.exit(1)
|
||||
from m64py.utils import log, md5sum
|
||||
from m64py.archive import Archive, EXT_FILTER
|
||||
from m64py.ui.romlist_ui import Ui_ROMList
|
||||
|
||||
try:
|
||||
from m64py.ui import title_rc
|
||||
|
@ -75,8 +69,8 @@ class ROMList(QMainWindow, Ui_ROMList):
|
|||
|
||||
def init(self):
|
||||
self.read_rom_list()
|
||||
self.roms = self.qset.value("rom_list", []).toPyObject()
|
||||
if self.qset.value("show_available", 0).toInt()[0]:
|
||||
self.roms = self.qset.value("rom_list", [])
|
||||
if bool(self.qset.value("show_available", 0)):
|
||||
self.add_available_items(self.roms)
|
||||
else:
|
||||
self.add_items()
|
||||
|
@ -119,7 +113,7 @@ class ROMList(QMainWindow, Ui_ROMList):
|
|||
except KeyError:
|
||||
md5 = key
|
||||
list_item = QListWidgetItem(rom['goodname'])
|
||||
list_item.setData(Qt.UserRole, (md5, None))
|
||||
list_item.setData(Qt.UserRole, (md5, None, None))
|
||||
list_item.setFlags(Qt.ItemIsEnabled)
|
||||
self.listWidget.addItem(list_item)
|
||||
self.pushOpen.setEnabled(False)
|
||||
|
@ -135,11 +129,11 @@ class ROMList(QMainWindow, Ui_ROMList):
|
|||
self.qset.setValue("rom_list", self.roms)
|
||||
self.qset.sync()
|
||||
self.listWidget.clear()
|
||||
for md5, path in self.roms:
|
||||
for md5, path, fname in self.roms:
|
||||
if md5 in self.romlist:
|
||||
goodname = self.romlist[md5]['goodname']
|
||||
list_item = QListWidgetItem(goodname)
|
||||
list_item.setData(Qt.UserRole, (md5, path))
|
||||
list_item.setData(Qt.UserRole, (md5, path, fname))
|
||||
self.listWidget.addItem(list_item)
|
||||
self.progressBar.setValue(0)
|
||||
self.progressBar.hide()
|
||||
|
@ -150,7 +144,7 @@ class ROMList(QMainWindow, Ui_ROMList):
|
|||
|
||||
def refresh_items(self):
|
||||
"""Refreshes available ROMs list"""
|
||||
path_roms = self.qset.value("Paths/ROM").toString()
|
||||
path_roms = self.qset.value("Paths/ROM")
|
||||
if not path_roms:
|
||||
self.parent.emit(SIGNAL(
|
||||
"info_dialog(PyQt_PyObject)"),
|
||||
|
@ -162,31 +156,31 @@ class ROMList(QMainWindow, Ui_ROMList):
|
|||
self.reader.set_path(path_roms)
|
||||
self.reader.start()
|
||||
|
||||
def file_open(self, path):
|
||||
def file_open(self, path, fname):
|
||||
"""Opens ROM file."""
|
||||
self.close()
|
||||
if self.parent.isMinimized():
|
||||
self.parent.activateWindow()
|
||||
self.parent.emit(SIGNAL(
|
||||
"file_open(PyQt_PyObject)"), str(path))
|
||||
"file_open(PyQt_PyObject, PyQt_PyObject)"), path, fname)
|
||||
|
||||
def on_progress_bar_changed(self, value):
|
||||
self.progressBar.setValue(value)
|
||||
|
||||
def on_item_open(self):
|
||||
item = self.listWidget.currentItem()
|
||||
md5, path = item.data(Qt.UserRole).toPyObject()
|
||||
md5, path, fname = item.data(Qt.UserRole)
|
||||
if path:
|
||||
self.file_open(path)
|
||||
self.file_open(path, fname)
|
||||
|
||||
def on_item_activated(self, item):
|
||||
md5, path = item.data(Qt.UserRole).toPyObject()
|
||||
md5, path, fname = item.data(Qt.UserRole)
|
||||
if path:
|
||||
self.file_open(path)
|
||||
self.file_open(path, fname)
|
||||
|
||||
def on_item_changed(self, current, previous):
|
||||
if not current: return
|
||||
md5, path = current.data(Qt.UserRole).toPyObject()
|
||||
md5, path, fname = current.data(Qt.UserRole)
|
||||
|
||||
title = QPixmap(os.path.join(
|
||||
self.user_data_path, "title", "%s.png") % md5)
|
||||
|
@ -241,7 +235,7 @@ class ROMReader(QThread):
|
|||
|
||||
def set_path(self, path):
|
||||
"""Sets ROM directory path."""
|
||||
self.rom_path = str(path)
|
||||
self.rom_path = path
|
||||
|
||||
def get_roms(self):
|
||||
"""Returns ROM list."""
|
||||
|
@ -265,13 +259,14 @@ class ROMReader(QThread):
|
|||
fullpath = os.path.join(self.rom_path, filename)
|
||||
try:
|
||||
archive = Archive(fullpath)
|
||||
romfile = archive.read()
|
||||
archive.close()
|
||||
for fname in archive.namelist:
|
||||
romfile = archive.read(fname)
|
||||
archive.close()
|
||||
rom_md5 = md5sum(filedata=romfile)
|
||||
self.roms.append((rom_md5.upper(), fullpath, fname))
|
||||
except Exception, err:
|
||||
log.warn(str(err))
|
||||
continue
|
||||
rom_md5 = md5sum(filedata=romfile)
|
||||
self.roms.append((rom_md5.upper(), fullpath))
|
||||
percent = float(filenum) / float(num_files) * 100
|
||||
self.parent.progressBar.emit(
|
||||
SIGNAL("valueChanged(int)"), percent)
|
||||
|
|
Loading…
Add table
Reference in a new issue