I have prepared a patch for those who want to use rom collections stored on networked drives on systems that do not support files on networked drives ("smb://...", etc...) natively - such as Android. With this patch a new option "Make Local Copy" is added to "Edit Rom Collection" -> "Launch Games". When checked the rom will be copied from the location it was imported from into a temporary local storage, where emulators and the compressed file handling routines (for *.zip and *.7zip) can pick it up. The copying is accomplished by XBMC's internal file copy system, so every file on whatever networked storage XBMC can pick up can also be copied. Once a local copy has been made, the launched emulator should have no problem reading the file.
Here's the story behind this patch:
I have a Fire TV, so Android, unrooted and unrootable. Import from a network share worked. Launching a game did not. Checking the logs, it showed that for uncompressed files the emulators were fed with the network location of the file, such as "smb://SHARENAME/roms/game.nes". Android emulators such as RetroArch cannot access these files. They can only read local copies. Using zipped ROMs should work since RCB uncompresses these to a local location before launching the emu. Sadly RCB's uncompress routines also do not like networked files. To fix this I put in the "Make local copy" option before the ROM is launched or uncompressed. That's what this patch adds to the current repo version (2.0.17) of RCB.
Code:
Index: resources/language/English/strings.xml
===================================================================
--- resources/language/English/strings.xml (revision 1825)
+++ resources/language/English/strings.xml (working copy)
@@ -255,6 +255,7 @@
<string id="52036">Autoplay Video (Info Window)</string>
<string id="52037">Use RetroPlayer</string>
<string id="52038">Gameclient</string>
+ <string id="52039">Make Local Copy</string>
<string id="52034">Save Config</string>
<string id="52035">Cancel</string>
Index: resources/lib/config.py
===================================================================
--- resources/lib/config.py (revision 1825)
+++ resources/lib/config.py (working copy)
@@ -235,6 +235,7 @@
maxFolderDepth = 99
useFoldernameAsGamename = False
doNotExtractZipFiles = False
+ makeLocalCopy = False
diskPrefix = '_Disk.*'
xboxCreateShortcut = False
xboxCreateShortcutAddRomfile = False
@@ -493,6 +494,11 @@
doNotExtractZipFiles = self.readTextElement(romCollectionRow, 'doNotExtractZipFiles')
if(doNotExtractZipFiles != ''):
romCollection.doNotExtractZipFiles = doNotExtractZipFiles.upper() == 'TRUE'
+
+ makeLocalCopy = self.readTextElement(romCollectionRow, 'makeLocalCopy')
+ if(makeLocalCopy != ''):
+ romCollection.makeLocalCopy = makeLocalCopy.upper() == 'TRUE'
+
romCollection.diskPrefix = self.readTextElement(romCollectionRow, 'diskPrefix')
@@ -742,4 +748,4 @@
else:
return ''
-
\ No newline at end of file
+
Index: resources/lib/configxmlwriter.py
===================================================================
--- resources/lib/configxmlwriter.py (revision 1825)
+++ resources/lib/configxmlwriter.py (working copy)
@@ -74,6 +74,7 @@
SubElement(romCollectionXml, 'useFoldernameAsGamename').text = str(romCollection.useFoldernameAsGamename)
SubElement(romCollectionXml, 'maxFolderDepth').text = str(romCollection.maxFolderDepth)
SubElement(romCollectionXml, 'doNotExtractZipFiles').text = str(romCollection.doNotExtractZipFiles)
+ SubElement(romCollectionXml, 'makeLocalCopy').text = str(romCollection.makeLocalCopy)
SubElement(romCollectionXml, 'diskPrefix').text = str(romCollection.diskPrefix)
if (os.environ.get( "OS", "xbox" ) == "xbox"):
@@ -370,4 +371,4 @@
except Exception, (exc):
print("Error: Cannot write config.xml: " +str(exc))
return False, util.localize(32008) +": " +str(exc)
-
\ No newline at end of file
+
Index: resources/lib/dialogeditromcollection.py
===================================================================
--- resources/lib/dialogeditromcollection.py (revision 1825)
+++ resources/lib/dialogeditromcollection.py (working copy)
@@ -60,8 +60,8 @@
CONTROL_BUTTON_SAVESTATEPARAMS = 5480
CONTROL_BUTTON_PRECMD = 5510
CONTROL_BUTTON_POSTCMD = 5520
+CONTROL_BUTTON_MAKELOCALCOPY = 5560
-
class EditRomCollectionDialog(dialogbase.DialogBaseEdit):
selectedControlId = 0
@@ -429,6 +429,9 @@
control = self.getControlById(CONTROL_BUTTON_DONTEXTRACTZIP)
control.setSelected(self.selectedRomCollection.doNotExtractZipFiles)
+ control = self.getControlById(CONTROL_BUTTON_MAKELOCALCOPY)
+ control.setSelected(self.selectedRomCollection.makeLocalCopy)
+
control = self.getControlById(CONTROL_BUTTON_PRECMD)
util.setLabel(self.selectedRomCollection.preCmd, control)
@@ -510,7 +513,10 @@
self.selectedRomCollection.usePopen = bool(control.isSelected())
control = self.getControlById(CONTROL_BUTTON_DONTEXTRACTZIP)
self.selectedRomCollection.doNotExtractZipFiles = bool(control.isSelected())
+ control = self.getControlById(CONTROL_BUTTON_MAKELOCALCOPY)
+ self.selectedRomCollection.makeLocalCopy = bool(control.isSelected())
+
Logutil.log('updateSelectedRomCollection: precmd = ' +self.selectedRomCollection.preCmd, util.LOG_LEVEL_INFO)
@@ -735,4 +741,4 @@
if(site != None):
sites.append(site)
- return sites
\ No newline at end of file
+ return sites
Index: resources/lib/launcher.py
===================================================================
--- resources/lib/launcher.py (revision 1825)
+++ resources/lib/launcher.py (working copy)
@@ -177,6 +177,19 @@
for fileNameRow in filenameRows:
rom = fileNameRow[0]
Logutil.log('rom: ' +str(rom), util.LOG_LEVEL_INFO)
+
+ if romCollection.makeLocalCopy:
+ localDir = os.path.join(util.getTempDir(), romCollection.name)
+ if os.path.exists(localDir):
+ Logutil.log("Trying to delete local rom files", util.LOG_LEVEL_INFO)
+ files = os.listdir(localDir)
+ for file in files:
+ os.remove(os.path.join(localDir, file))
+ localRom = os.path.join(localDir, os.path.basename(str(rom)))
+ Logutil.log('Creating local copy: ' + str(localRom), util.LOG_LEVEL_INFO)
+ if xbmcvfs.copy(rom, localRom):
+ Logutil.log('Local copy created', util.LOG_LEVEL_INFO)
+ rom = localRom
# If it's a .7z file
# Don't extract zip files in case of savestate handling and when called From skin
@@ -289,11 +302,12 @@
#Note: Trying to delete temporary files (from zip or 7z extraction) from last run
#Do this before launching a new game. Otherwise game could be deleted before launch
try:
- Logutil.log("Trying to delete temporary rom files", util.LOG_LEVEL_INFO)
- tempDir = util.getTempDir()
- files = os.listdir(tempDir)
- for file in files:
- os.remove(os.path.join(tempDir, file))
+ tempDir = os.path.join(util.getTempDir(), 'extracted')
+ if os.path.exists(tempDir):
+ Logutil.log("Trying to delete temporary rom files", util.LOG_LEVEL_INFO)
+ files = os.listdir(tempDir)
+ for file in files:
+ os.remove(os.path.join(tempDir, file))
except Exception, (exc):
Logutil.log("Error deleting files after launch emu: " +str(exc), util.LOG_LEVEL_ERROR)
gui.writeMsg(util.localize(32036) +": " +str(exc))
@@ -334,7 +348,7 @@
Logutil.log('Error handling compressed file', util.LOG_LEVEL_WARNING)
return []
for archive in archives:
- newPath = os.path.join(util.getTempDir(), archive[0])
+ newPath = os.path.join(util.getTempDir(), 'extracted', archive[0])
fp = open(newPath, 'wb')
fp.write(archive[1])
fp.close()
@@ -768,4 +782,4 @@
archive = zipfile.ZipFile(fp)
archivesDecompressed = [(name, archive.read(name)) for name in archiveList]
fp.close()
- return archivesDecompressed
\ No newline at end of file
+ return archivesDecompressed
Index: resources/skins/Default/720p/script-RCB-editromcollection.xml
===================================================================
--- resources/skins/Default/720p/script-RCB-editromcollection.xml (revision 1825)
+++ resources/skins/Default/720p/script-RCB-editromcollection.xml (working copy)
@@ -1942,6 +1942,24 @@
<onleft>7000</onleft>
<onright>6000</onright>
<onup>5520</onup>
+ <ondown>5560</ondown>
+ </control>
+
+ <!-- Make local copy -->
+ <control type="radiobutton" id="5560">
+ <posx>0</posx>
+ <posy>300</posy>
+ <width>660</width>
+ <height>30</height>
+ <font>font13</font>
+ <label>$ADDON[script.games.rom.collection.browser 52039]</label>
+ <textcolor>88FFFFFF</textcolor>
+ <focusedcolor>FFFFFFFF</focusedcolor>
+ <texturefocus>rcb-MenuItemFO.png</texturefocus>
+ <texturenofocus>rcb-MenuItemNF.png</texturenofocus>
+ <onleft>7000</onleft>
+ <onright>6000</onright>
+ <onup>5450</onup>
<ondown>5540</ondown>
</control>
@@ -1948,7 +1966,7 @@
<!-- Use RetroPlayer -->
<control type="radiobutton" id="5540">
<posx>0</posx>
- <posy>300</posy>
+ <posy>330</posy>
<width>660</width>
<height>30</height>
<font>font13</font>
@@ -1965,7 +1983,7 @@
<!-- Game Client -->
<control type="image">
<posx>0</posx>
- <posy>330</posy>
+ <posy>360</posy>
<width>270</width>
<height>30</height>
<texture>rcb-MenuItemFO.png</texture>
@@ -1973,7 +1991,7 @@
</control>
<control type="label">
<posx>7</posx>
- <posy>330</posy>
+ <posy>360</posy>
<width>200</width>
<height>30</height>
<font>font13</font>
@@ -1986,7 +2004,7 @@
</control>
<control type="label">
<posx>7</posx>
- <posy>330</posy>
+ <posy>360</posy>
<width>200</width>
<height>30</height>
<font>font13</font>
@@ -2000,7 +2018,7 @@
<control type="button" id="5550">
<description>Game client</description>
<posx>240</posx>
- <posy>330</posy>
+ <posy>360</posy>
<width>410</width>
<height>30</height>
<visible>true</visible>
@@ -2077,4 +2095,4 @@
<onright>7000</onright>
</control>
</controls>
-</window>
\ No newline at end of file
+</window>
To apply this patch you need two programs. A subversion client (svn) to checkout the latest RCB source code and a patch program that can handle Unix diff and patch files. Both things are available for every current OS; TortoiseSVN for Windows comes to mind, nearly every Linux distro got an subversion package in their repositories; the Window's compatible patch program might be more difficult, Linux got this already on board in even the most basic installs. Here's what needs to be done:
1. Get the latest RCB source via SVN from code.google.com:
Code:
svn checkout http://romcollectionbrowser.googlecode.com/svn/trunk/ romcollectionbrowser-read-only
You will get a new directory romcollectionbrowser-read-only.
2. Apply the patch by placing it in that same directory, and apply the patch to the source:
Code:
patch -p0 -i name-of-the-patch-file.diff
3. Zip up the romcollectionbrowser-read-only direcotry and choose System->Add-Ons->Install from zip file in XBMC and select the zip file. On my Fire TV I had to push the zip onto the device via adb first, but how you get the zip onto your XBMC device depends on your device.
4. When editing a ROM collection you should see a new option "Make local copy" at the bottom. If not, the patch was not applied or the install went wrong or something else entirely. In that case just keep trying and watch out for errors along the way. Google is your friend.