def __init__(self, *args, **kwargs): # Don't put GUI sensitive stuff here (as the xml hasn't been read yet) log.info("init ContextMenu") self.gui = kwargs["gui"] self.doModal()
def insertFile(self, fileName, gameId, fileType, romCollectionId, publisherId, developerId): log.debug("Begin Insert file: %s" % fileName) parentId = None # TODO console and romcollection could be done only once per RomCollection # fileTypeRow[3] = parent if fileType.parent == 'game': parentId = gameId elif fileType.parent == 'romcollection': parentId = romCollectionId elif fileType.parent == 'publisher': parentId = publisherId elif fileType.parent == 'developer': parentId = developerId log.info("Inserting file with parent {0} (type {1})".format(parentId, fileType.parent)) fileRow = File(self.gdb).getFileByNameAndTypeAndParent(fileName, fileType.id, parentId) if fileRow is None: log.info("File does not exist in database. Insert file: %s" % fileName) f = File(self.gdb) try: f.insert((fileName, fileType.id, parentId)) except Exception, (exc): log.warn("Error inserting into database: %s" % fileName)
def updateSelectedRomCollection(self): log.info("updateSelectedRomCollection") sites = [] sites = self.addScraperToSiteList(CONTROL_LIST_SCRAPER1, sites, self.selectedRomCollection) self.selectedRomCollection.scraperSites = sites # Image Placing Main control = self.getControlById(CONTROL_LIST_IMAGEPLACING_MAIN) imgPlacingItem = control.getSelectedItem() imgPlacingName = imgPlacingItem.getLabel() # HACK search key by value for item in config.imagePlacingDict.items(): if item[1] == imgPlacingName: imgPlacingName = item[0] imgPlacing, errorMsg = self.gui.config.readImagePlacing(imgPlacingName, self.gui.config.tree) self.selectedRomCollection.imagePlacingMain = imgPlacing # Image Placing Info control = self.getControlById(CONTROL_LIST_IMAGEPLACING_INFO) imgPlacingItem = control.getSelectedItem() imgPlacingName = imgPlacingItem.getLabel() # HACK search key by value for item in config.imagePlacingDict.items(): if item[1] == imgPlacingName: imgPlacingName = item[0] imgPlacing, errorMsg = self.gui.config.readImagePlacing(imgPlacingName, self.gui.config.tree) self.selectedRomCollection.imagePlacingInfo = imgPlacing # Update values for each of the buttons for btn in self._control_buttons: control = self.getControlById(btn['control']) setattr(self.selectedRomCollection, btn['value'], bool(control.isSelected()))
def __checkGameHasSaveStates(self, gameRow, filenameRows): if self.romCollection.saveStatePath == '': log.debug("No save state path set") return '' rom = filenameRows[0][0] saveStatePath = self.__replacePlaceholdersInParams(self.romCollection.saveStatePath, rom, gameRow) saveStateFiles = glob.glob(saveStatePath) if len(saveStateFiles) == 0: log.debug("No save state files found") return '' log.info('saveStateFiles found: ' + str(saveStateFiles)) # don't select savestatefile if ASKNUM is requested in Params if re.search('(?i)%ASKNUM%', self.romCollection.saveStateParams): return saveStateFiles[0] options = [util.localize(32165)] for f in saveStateFiles: options.append(os.path.basename(f)) selectedFile = xbmcgui.Dialog().select(util.localize(32166), options) # If selections is canceled or "Don't launch statefile" option if selectedFile < 1: return '' return saveStateFiles[selectedFile - 1]
def addScraperToSiteList(self, controlId, sites, romCollection): log.info("addScraperToSiteList") control = self.getControlById(controlId) scraperItem = control.getSelectedItem() scraper = scraperItem.getLabel() if scraper == util.localize(32854): return sites #check if this site is already available for current RC for site in romCollection.scraperSites: if site.name == scraper: sites.append(site) return sites siteRow = None siteRows = self.gui.config.tree.findall('Scrapers/Site') for element in siteRows: if element.attrib.get('name') == scraper: siteRow = element break if siteRow is None: xbmcgui.Dialog().ok(util.localize(32021), util.localize(32022) % scraper) return None site, errorMsg = self.gui.config.readScraper(siteRow, romCollection.name, '', '', True, self.gui.config.tree) if site is not None: sites.append(site) return sites
def selectScrapersInList(self, sitesInRomCollection, sitesInList): log.info("selectScrapersInList") if len(sitesInRomCollection) >= 1: self.selectItemInList(sitesInRomCollection[0].name, CONTROL_LIST_SCRAPER1) else: self.selectItemInList(util.localize(32854), CONTROL_LIST_SCRAPER1)
def updateControls(self): log.info('updateControls') control = self.getControlById(CONTROL_LIST_ROMCOLLECTIONS) selectedRomCollectionName = str(control.getSelectedItem().getLabel()) self.selectedRomCollection = self.gui.config.getRomCollectionByName(selectedRomCollectionName)
def walkDownPath(self, files, romPath, maxFolderDepth): log.info("alkDownPath romPath: %s" % romPath) files = self.walkDown(files, romPath, maxFolderDepth) log.info("files after walkDown = %s" % files) return files
def __init__(self, *args, **kwargs): log.info("init Edit Rom Collection") self.gui = kwargs["gui"] self.romCollections = self.gui.config.romCollections self.scraperSites = self.gui.config.scraperSites self.doModal()
def open_xml_url(self, **kwargs): log.info('Retrieving url %s, params = %s' %(kwargs['url'], kwargs['params'])) r = requests.get(kwargs['url'], headers=self._headers, params=kwargs['params']) log.debug(u"Retrieving {0} as XML - HTTP{1}".format(r.url, r.status_code)) # Need to ensure we are sending back Unicode text return r.text.encode('utf-8')
def selectItemInList(self, options, itemName, controlId): log.info('selectItemInList') for i in range(0, len(options)): option = options[i] if itemName == option: control = self.getControlById(controlId) control.selectItem(i) break
def compareNames(self, gamename, searchkey, checkSubtitle): if checkSubtitle: if searchkey.find(gamename) > -1: log.info("%s is a subtitle of %s. Using result %s" % (gamename, searchkey, searchkey)) return True else: if gamename == searchkey: log.info("Perfect match. Using result %s" % searchkey) return True return False
def findFilesByGameDescription(self, key, fileDict): log.info("searching for Key: %s" % key) try: filename = fileDict[key] log.info("result found: %s" % filename) except KeyError: filename = None return filename
def getScrapingMode(self): mode = 0 scrape_options = {util.SCRAPING_OPTION_AUTO_ACCURATE_TXT: 0, util.SCRAPING_OPTION_INTERACTIVE_TXT: 1} try: mode = scrape_options[__addon__.getSetting(util.SETTING_RCB_SCRAPINGMODE)] except KeyError: pass log.info("Scraping mode: {0}".format(mode)) return mode
def onInit(self): log.info('onInit Remove Rom Collection') # Rom Collections log.info('build rom collection list') self.addItemsToList(CONTROL_LIST_ROMCOLLECTIONS, self.gui.config.getRomCollectionNames()) # Delete Options rcDeleteOptions = [util.localize(32137), util.localize(32138)] self.addItemsToList(CONTROL_LIST_DELETEOPTIONS, rcDeleteOptions, properties=['RCollection', 'Roms']) self.updateControls()
def walkDown(self, files, romPath, maxFolderDepth): log.info("Running walkdown on: %s" % romPath) dirs, newFiles, dirname, filemask = self.getFilesByWildcardExt(romPath) files.extend(newFiles) for dir in dirs: newRomPath = util.joinPath(dirname, dir, filemask) maxFolderDepth = maxFolderDepth - 1 if (maxFolderDepth > 0): self.walkDown(files, newRomPath, maxFolderDepth) return files
def insertForeignKeyItem(self, result, itemName, gdbObject): item = self.resolveParseResult(result, itemName) if item != "" and item is not None: itemRow = gdbObject.getOneByName(item) if itemRow is None: log.info("%s does not exist in database. Insert: %s" % (itemName, item.encode('utf-8'))) gdbObject.insert((item,)) del item itemId = self.gdb.cursor.lastrowid else: itemId = itemRow[0] else: itemId = None return itemId
def matchGamename(self, results, gamenameFromFile, checkSubtitle): for idx, result in enumerate(results): try: # Check if the result has the correct platform (if needed) found_platform = self.resolveParseResult(result, 'PlatformSearchKey') if found_platform != '' and self.expected_platform != found_platform: log.info("Platform mismatch. %s != %s. Result will be skipped." % ( self.expected_platform, found_platform)) continue searchKey = self.resolveParseResult(result, 'SearchKey') # keep it for later reference searchkey_orig = searchKey gamename_orig = gamenameFromFile # if no searchkey is specified first result is valid (1 file per game scenario) if searchkey_orig == '': log.info("No searchKey found. Using first result") return result log.info("Comparing %s with %s" % (gamename_orig, searchkey_orig)) if gamename_orig == searchkey_orig: # perfect match return result # normalize name and searchkey before comparison gnu = GameNameUtil() gamename_normalized = gnu.normalize_name(gamename_orig) searchkey_normalized = gnu.normalize_name(searchkey_orig) log.info("Try normalized names. Comparing %s with %s" % (gamename_normalized, searchkey_normalized)) if gamename_normalized == searchkey_normalized: # perfect match return result #strip additional info from gamename gamename_stripped = gnu.strip_addinfo_from_name(gamename_orig) gamename_stripped = gnu.normalize_name(gamename_stripped) log.info("Try with stripped additional info. Comparing %s with %s" % (gamename_stripped, searchkey_normalized)) if gamename_stripped == searchkey_normalized: # perfect match return result except Exception, (exc): log.warn("An error occured while matching the best result: " + str(exc))
def onInit(self): log.info("onInit ContextMenu") self.selectedGame = self.gui.getSelectedItem() # Set mark favorite text if self.selectedGame is not None: if self.selectedGame.getProperty('isfavorite') == '1': buttonMarkFavorite = self.getControlById(CONTROL_BUTTON_SETFAVORITE_GAME) if buttonMarkFavorite is not None: buttonMarkFavorite.setLabel(util.localize(32133)) buttonMarkFavorite = self.getControlById(CONTROL_BUTTON_SETFAVORITE_SELECTION) if buttonMarkFavorite is not None: buttonMarkFavorite.setLabel(util.localize(32134)) # Hide Set Gameclient option if not helper.isRetroPlayerSupported(): control = self.getControlById(5224) control.setVisible(False) control.setEnabled(False)
def insertGameFromDesc(self, gamedescription, gamename, romCollection, filenamelist, foldername, isUpdate, gameId): log.info("insertGameFromDesc") if gamedescription is not None: game = self.resolveParseResult(gamedescription, 'Game') else: game = '' # if no game name has been scraped we expect that no results have been found if game == '': self.missingDescFile.add_entry(gamename) if __addon__.getSetting(util.SETTING_RCB_IGNOREGAMEWITHOUTDESC).upper() == 'TRUE': log.warn("No description found for game '%s'. Game will not be imported." % gamename) return None gamedescription = {} gameId = self.insertData(gamedescription, gamename, romCollection, filenamelist, foldername, isUpdate, gameId) return gameId
def insertForeignKeyItemList(self, result, itemName, gdbObject): idList = [] try: itemList = result[itemName] log.info("Result %s = %s" % (itemName, itemList)) except KeyError: log.warn("Error while resolving item: %s" % itemName) return idList for item in itemList: itemRow = gdbObject.getOneByName(item) if itemRow is None: log.info("%s does not exist in database. Insert: %s" % (itemName, item.encode('utf-8'))) gdbObject.insert((item,)) idList.append(self.gdb.cursor.lastrowid) else: idList.append(itemRow[0]) return idList
def __handleCompressedFile(self, gui, filext, rom, emuParams): log.info("__handleCompressedFile") # 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 tempDir = os.path.join(util.getTempDir(), 'extracted', self.romCollection.name) # check if folder exists if not xbmcvfs.exists(tempDir +'\\'): log.info("Create temporary folder: " +tempDir) xbmcvfs.mkdir(tempDir) try: if xbmcvfs.exists(tempDir +'\\'): log.info("Trying to delete temporary rom files") #can't use xbmcvfs.listdir here as it seems to cache the file list and RetroPlayer won't find newly created files anymore files = os.listdir(tempDir) for f in files: #RetroPlayer places savestate files next to the roms. Don't delete these files. fname, ext = os.path.splitext(f) if(ext not in ('.sav', '.xml', '.png')): xbmcvfs.delete(os.path.join(tempDir, f)) except Exception, (exc): log.error("Error deleting files after launch emu: " + str(exc)) gui.writeMsg(util.localize(32036) + ": " + str(exc))
def open_json_url(self, **kwargs): log.info('Retrieving url %s, params = %s' %(kwargs['url'], kwargs['params'])) try: r = requests.get(kwargs['url'], headers=self._headers, params=kwargs['params']) except ValueError as e: # Typically non-JSON response raise ScraperUnexpectedContentException("Non-JSON response received") log.debug(u"Retrieving {0} as JSON - HTTP{1}".format(r.url, r.status_code)) if r.status_code == 401: # Mobygames and GiantBomb send a 401 if the API key is invalid raise ScraperUnauthorisedException("Invalid API key sent") if r.status_code == 429: raise ScraperExceededAPIQuoteException("Scraper exceeded API key limits") if r.status_code == 500: raise ScraperWebsiteUnavailableException("Website unavailable") return r.json()
def __copyLauncherScriptsToUserdata(self): log.info('__copyLauncherScriptsToUserdata') oldBasePath = os.path.join(util.getAddonInstallPath(), 'resources', 'scriptfiles') newBasePath = os.path.join(util.getAddonDataPath(), 'scriptfiles') files = [] # Copy applaunch shell script/batch file if self.env == 'win32': files.append('applaunch.bat') else: files.append('applaunch.sh') # Copy VBS files if self.env == 'win32' and __addon__.getSetting(util.SETTING_RCB_USEVBINSOLOMODE).lower() == 'true': files += ['applaunch-vbs.bat', 'LaunchKodi.vbs', 'Sleep.vbs'] for f in files: if not xbmcvfs.exists(os.path.join(newBasePath, f)): log.debug("Copying file {0} from {1} to {2}".format(f, oldBasePath, newBasePath)) if not xbmcvfs.copy(os.path.join(oldBasePath, f), os.path.join(newBasePath, f)): log.warn("Error copying file")
def getArtworkForGame(self, romCollection, gamename, gamenameFromFile, gamedescription, foldername, publisher, developer): artWorkFound = False artworkfiles = {} artworkurls = {} for path in romCollection.mediaPaths: log.info("FileType: {0}".format(path.fileType.name)) # TODO replace %ROMCOLLECTION%, %PUBLISHER%, ... fileName = path.path.replace("%GAME%", gamenameFromFile) continueUpdate, artworkurls = self.getThumbFromOnlineSource(gamedescription, path.fileType.name, fileName, artworkurls) if not continueUpdate: return False, {}, {} log.debug("Additional data path: %s" % path.path) files = self.resolvePath((path.path,), gamename, gamenameFromFile, foldername, romCollection.name, publisher, developer) if len(files) > 0: artWorkFound = True # HACK: disable static image check as a preparation for new default image handling (this code has problems with [] in rom names) """ imagePath = str(self.resolvePath((path.path,), gamename, gamenameFromFile, foldername, romCollection.name, publisher, developer)) staticImageCheck = imagePath.upper().find(gamenameFromFile.upper()) #make sure that it was no default image that was found here if(staticImageCheck != -1): artWorkFound = True """ else: self.missingArtworkFile.add_entry(gamename, gamenameFromFile, path.fileType.name) artworkfiles[path.fileType] = files return artWorkFound, artworkfiles, artworkurls
def getFilesByWildcardExt(self, pathName): log.info("Begin getFilesByWildcard. pathName = %s" % pathName) files = [] dirs = [] dirname = os.path.dirname(pathName) log.info("dirname: %s" % dirname) filemask = os.path.basename(pathName) # HACK: escape [] for use with fnmatch filemask = filemask.replace('[', '[[]') filemask = filemask.replace(']', '[]]') # This might be stupid but it was late... filemask = filemask.replace('[[[]]', '[[]') log.info("filemask: %s" % filemask) dirsLocal, filesLocal = xbmcvfs.listdir(dirname) log.info("xbmcvfs dirs: %s" % dirs) log.info("xbmcvfs files: %s" % filesLocal) for dir in dirsLocal: if type(dir) == str: dirs.append(dir.decode('utf-8')) else: dirs.append(dir) for file in filesLocal: if fnmatch.fnmatch(file, filemask): # allFiles = [f.decode(sys.getfilesystemencoding()).encode('utf-8') for f in glob.glob(newRomPath)] if type(file) == str: file = file.decode('utf-8') file = util.joinPath(dirname, file) # return unicode filenames so relating scraping actions can handle them correctly files.append(file) return dirs, files, dirname, filemask """
def getRomFilesByRomCollection(self, romCollection, enableFullReimport): log.info("Rom path: %s" % romCollection.romPaths) log.info("Reading rom files") files = [] for romPath in romCollection.romPaths: log.info("Reading rom files in path: %s" % romPath) files = self.walkDownPath(files, unicode(romPath), romCollection.maxFolderDepth) # only use files that are not already present in database if enableFullReimport == False: inDBFiles = DataBaseObject(self.gdb, '').getFileAllFilesByRCId(romCollection.id) files = [f for f in files if not f in inDBFiles] files.sort() log.info("Files read: %s" % files) return files
def insertGame(self, gameName, description, romCollectionId, publisherId, developerId, reviewerId, yearId, players, rating, votes, url, region, media, perspective, controller, originalTitle, alternateTitle, translatedBy, version, isFavorite, launchCount, isUpdate, gameId, allowUpdate): # Check if exists and insert/update as appropriate; move this functionality to the Game object try: if not isUpdate: log.info(u"Game does not exist in database. Insert game: %s" % gameName) Game(self.gdb).insert( (gameName, description, None, None, romCollectionId, publisherId, developerId, reviewerId, yearId, players, rating, votes, url, region, media, perspective, controller, int(isFavorite), int(launchCount), originalTitle, alternateTitle, translatedBy, version)) return self.gdb.cursor.lastrowid else: if allowUpdate: # check if we are allowed to update with null values allowOverwriteWithNullvalues = __addon__.getSetting( util.SETTING_RCB_ALLOWOVERWRITEWITHNULLVALUES).upper() == 'TRUE' log.info("allowOverwriteWithNullvalues: {0}".format(allowOverwriteWithNullvalues)) log.info(u"Game does exist in database. Update game: %s" % gameName) Game(self.gdb).update(('name', 'description', 'romCollectionId', 'publisherId', 'developerId', 'reviewerId', 'yearId', 'maxPlayers', 'rating', 'numVotes', 'url', 'region', 'media', 'perspective', 'controllerType', 'originalTitle', 'alternateTitle', 'translatedBy', 'version', 'isFavorite', 'launchCount'), (gameName, description, romCollectionId, publisherId, developerId, reviewerId, yearId, players, rating, votes, url, region, media, perspective, controller, originalTitle, alternateTitle, translatedBy, version, int(isFavorite), int(launchCount)), gameId, allowOverwriteWithNullvalues) else: log.info( u"Game does exist in database but update is not allowed for current rom collection. game: %s" % gameName) return gameId except Exception, (exc): log.error(u"An error occured while adding game '%s'. Error: %s" % (gameName, exc)) return None
def onInit(self): log.info("onInit Edit Rom Collection") # Rom Collections self.addItemsToList(CONTROL_LIST_ROMCOLLECTIONS, self.gui.config.getRomCollectionNames()) log.info("build scraper lists") self.availableScrapers = self.getAvailableScrapers() self.addItemsToList(CONTROL_LIST_SCRAPER1, self.availableScrapers) log.info("build imagePlacing list") self.imagePlacingList = [] imagePlacingRows = self.gui.config.tree.findall('ImagePlacing/fileTypeFor') for imagePlacing in imagePlacingRows: log.info("add image placing: {0}".format(imagePlacing.attrib.get('name'))) option = imagePlacing.attrib.get('name') # HACK: remove all video options from config if option.upper().find('VIDEO') >= 0: continue try: option = config.imagePlacingDict[option] except IndexError: pass self.imagePlacingList.append(option) self.addItemsToList(CONTROL_LIST_IMAGEPLACING_MAIN, self.imagePlacingList) self.addItemsToList(CONTROL_LIST_IMAGEPLACING_INFO, self.imagePlacingList) if not helper.isRetroPlayerSupported(): for ctrl_id in [CONTROL_BUTTON_USERETROPLAYER, CONTROL_BUTTON_GAMECLIENT]: try: control = self.getControlById(ctrl_id) control.setEnabled(False) control.setVisible(False) except AttributeError: pass self.updateRomCollectionControls()
def checkRomfileAlreadyExists(self, filename, enableFullReimport): isUpdate = False gameId = None log.debug("Checking if file already exists in DB: %s" % filename) romFile = File(self.gdb).getFileByNameAndType(filename, 0) if romFile is not None: isUpdate = True gameId = romFile[3] # FIXME TODO Replace with FILE_parentId log.info("File '%s' already exists in database." % filename) log.info("Always rescan imported games = {0}".format(enableFullReimport)) if enableFullReimport is False: log.info("Won't scrape this game again. Set 'Always rescan imported games' to True to force scraping.") return False, isUpdate, gameId else: log.debug("Couldn't find file in DB") return True, isUpdate, gameId
def onClick(self, controlID): log.info("onClick") if controlID == CONTROL_BUTTON_EXIT: # Close window button log.info("close") self.close() # OK elif controlID == CONTROL_BUTTON_SAVE: log.info("save") # Store selectedRomCollection if self.selectedRomCollection is not None: self.updateSelectedRomCollection() self.romCollections[ self.selectedRomCollection.id] = self.selectedRomCollection configWriter = ConfigXmlWriter(False) success, message = configWriter.writeRomCollections( self.romCollections, True) if not success: xbmcgui.Dialog().ok(util.localize(32021), message) self.close() # Cancel elif controlID == CONTROL_BUTTON_CANCEL: self.close() elif controlID == CONTROL_BUTTON_ADD_RC: statusOk, errorMsg = wizardconfigxml.ConfigXmlWizard( ).addRomCollection(self.gui.config) if statusOk is False: xbmcgui.Dialog().ok(util.SCRIPTNAME, util.localize(32001), errorMsg) log.info("Error updating config.xml: {0}".format(errorMsg)) return #update self.config self.gui.config = Config(None) statusOk, errorMsg = self.gui.config.readXml() if statusOk is False: xbmcgui.Dialog().ok(util.SCRIPTNAME, util.localize(32002), errorMsg) log.info("Error reading config.xml: {0}".format(errorMsg)) return self.addItemsToList(CONTROL_LIST_ROMCOLLECTIONS, self.gui.config.getRomCollectionNames()) self.updateRomCollectionControls() elif controlID == CONTROL_BUTTON_REMOVE_RC: constructorParam = "720p" try: removeRCDialog = dialogdeleteromcollection.RemoveRCDialog( "script-RCB-removeRC.xml", util.getAddonInstallPath(), util.getConfiguredSkin(), constructorParam, gui=self.gui) except: removeRCDialog = dialogdeleteromcollection.RemoveRCDialog( "script-RCB-removeRC.xml", util.getAddonInstallPath(), "Default", constructorParam, gui=self.gui) rDelStat = removeRCDialog.getDeleteStatus() if rDelStat: selectedRCId = removeRCDialog.getSelectedRCId() rcDelStat = removeRCDialog.getRCDeleteStatus() self.gui.deleteRCGames(selectedRCId, rcDelStat, rDelStat) del removeRCDialog self.gui.config = Config(None) statusOk, errorMsg = self.gui.config.readXml() if statusOk is False: xbmcgui.Dialog().ok(util.SCRIPTNAME, util.localize(32002), errorMsg) log.info("Error reading config.xml: {0}".format(errorMsg)) return self.addItemsToList(CONTROL_LIST_ROMCOLLECTIONS, self.gui.config.getRomCollectionNames()) self.updateRomCollectionControls() # Rom Collection list elif self.selectedControlId in (CONTROL_BUTTON_RC_DOWN, CONTROL_BUTTON_RC_UP): if self.selectedRomCollection is not None: # Save current values to selected Rom Collection self.updateSelectedRomCollection() # Store previous selectedRomCollections state self.romCollections[ self.selectedRomCollection.id] = self.selectedRomCollection # HACK: add a little wait time as XBMC needs some ms to execute the MoveUp/MoveDown actions from the skin xbmc.sleep(util.WAITTIME_UPDATECONTROLS) self.updateRomCollectionControls() # Media Path elif self.selectedControlId in (CONTROL_BUTTON_MEDIA_DOWN, CONTROL_BUTTON_MEDIA_UP): # HACK: add a little wait time as XBMC needs some ms to execute the MoveUp/MoveDown actions from the skin xbmc.sleep(util.WAITTIME_UPDATECONTROLS) self.updateMediaPathControls() elif controlID == CONTROL_LIST_OFFLINE_SCRAPER: self.editOfflineScraper() elif controlID == CONTROL_BUTTON_GAMECLIENT: success, gameclient = helper.selectlibretrocore( self.selectedRomCollection.name) if success: self.selectedRomCollection.gameclient = gameclient control = self.getControlById(CONTROL_BUTTON_GAMECLIENT) if gameclient == "": control.setLabel("None") else: control.setLabel(gameclient) elif controlID == CONTROL_BUTTON_EMUCMD: self.editEmuCmd() elif controlID == CONTROL_BUTTON_PARAMS: emulatorParams = self.editTextProperty(CONTROL_BUTTON_PARAMS, util.localize(32625)) self.selectedRomCollection.emulatorParams = emulatorParams elif controlID == CONTROL_BUTTON_ROMPATH: self.editRomPath() elif controlID == CONTROL_BUTTON_FILEMASK: self.editRomFileMask() elif controlID == CONTROL_BUTTON_MEDIAPATH: self.editMediaPath() elif controlID == CONTROL_BUTTON_MEDIAFILEMASK: self.editMediaFileMask() elif controlID == CONTROL_BUTTON_ADDMEDIAPATH: self.addMediaPath() elif controlID == CONTROL_BUTTON_REMOVEMEDIAPATH: self.removeMediaPath() elif controlID == CONTROL_BUTTON_MAXFOLDERDEPTH: maxFolderDepth = self.editTextProperty( CONTROL_BUTTON_MAXFOLDERDEPTH, util.localize(32610)) self.selectedRomCollection.maxFolderDepth = maxFolderDepth elif controlID == CONTROL_BUTTON_DISKINDICATOR: diskIndicator = self.editTextProperty(CONTROL_BUTTON_DISKINDICATOR, util.localize(32611)) self.selectedRomCollection.diskPrefix = diskIndicator elif controlID == CONTROL_BUTTON_SAVESTATEPATH: saveStatePathComplete = self.editPathWithFileMask( CONTROL_BUTTON_SAVESTATEPATH, '%s ' % self.selectedRomCollection.name + util.localize(32629), CONTROL_BUTTON_SAVESTATEMASK) if saveStatePathComplete != '': self.selectedRomCollection.saveStatePath = saveStatePathComplete elif controlID == CONTROL_BUTTON_SAVESTATEMASK: self.selectedRomCollection.saveStatePath = self.editFilemask( CONTROL_BUTTON_SAVESTATEMASK, util.localize(32630), self.selectedRomCollection.saveStatePath) elif controlID == CONTROL_BUTTON_SAVESTATEPARAMS: saveStateParams = self.editTextProperty( CONTROL_BUTTON_SAVESTATEPARAMS, util.localize(32631)) self.selectedRomCollection.saveStateParams = saveStateParams elif controlID == CONTROL_BUTTON_PRECMD: preCmd = self.editTextProperty(CONTROL_BUTTON_PRECMD, util.localize(32632)) self.selectedRomCollection.preCmd = preCmd log.info("OnClick: precmd = {0}".format( self.selectedRomCollection.preCmd)) elif controlID == CONTROL_BUTTON_POSTCMD: postCmd = self.editTextProperty(CONTROL_BUTTON_POSTCMD, util.localize(32633)) self.selectedRomCollection.postCmd = postCmd
def addRomCollections(self, rcId, configObj, consoleList, isUpdate): romCollections = {} dialog = xbmcgui.Dialog() # Scraping scenario - game descriptions and artwork retrieved from online or available locally scenarioIndex = dialog.select( util.localize(32173), [util.localize(32174), util.localize(32175), util.localize(32207)]) log.info("scenarioIndex: " + str(scenarioIndex)) if scenarioIndex == -1: del dialog log.info("No scenario selected. Action canceled.") return False, romCollections autoconfig = EmulatorAutoconfig(util.getEmuAutoConfigPath()) while True: fileTypeList, errorMsg = self.buildMediaTypeList( configObj, isUpdate) romCollection = RomCollection() if (errorMsg): log.warn("Error building Media Type List: {0}" % errorMsg) break # Console platformIndex = dialog.select(util.localize(32176), consoleList) log.info("platformIndex: " + str(platformIndex)) if platformIndex == -1: log.info("No Platform selected. Action canceled.") break console = consoleList[platformIndex] if console == 'Other': console = self.promptOtherConsoleName() if console == '': break else: consoleList.remove(console) log.info("Selected platform: " + console) romCollection.name = console romCollection.id = rcId rcId = rcId + 1 # Check if we have general RetroPlayer support if helper.isRetroPlayerSupported(): #32198 = Use RetroPlayer to launch games? romCollection.useBuiltinEmulator = bool( dialog.yesno(util.SCRIPTNAME, util.localize(32198))) # Only ask for emulator and params if we don't use builtin emulator if not romCollection.useBuiltinEmulator: # Maybe there is autoconfig support preconfiguredEmulator = None # Emulator if romCollection.name in ['Linux', 'Macintosh', 'Windows']: # Check for standalone games romCollection.emulatorCmd = '"%ROM%"' log.info("emuCmd set to '%ROM%' for standalone games.") else: emulist = [] log.info( u'Running on {0}. Trying to find emulator per autoconfig.' .format(util.current_os)) emulators = autoconfig.findEmulators( util.current_os, romCollection.name, True) for emulator in emulators: if emulator.isInstalled: emulist.append( util.localize(32202) % emulator.name) else: emulist.append(emulator.name) # Ask the user which one they want if len(emulist) > 0: try: emuIndex = dialog.select(util.localize(32203), emulist) if emuIndex >= 0: preconfiguredEmulator = emulators[emuIndex] except IndexError: log.info("No Emulator selected.") preconfiguredEmulator = None if preconfiguredEmulator: romCollection.emulatorCmd = preconfiguredEmulator.emuCmd else: consolePath = dialog.browse( 1, util.localize(32178) % console, 'files') Logutil.log('consolePath: ' + str(consolePath), util.LOG_LEVEL_INFO) if consolePath == '': log.info( "No consolePath selected. Action canceled.") break romCollection.emulatorCmd = consolePath # Set emulator parameters if romCollection.name in ['Linux', 'Macintosh', 'Windows']: romCollection.emulatorParams = '' log.info("emuParams set to " " for standalone games.") else: if preconfiguredEmulator: defaultParams = preconfiguredEmulator.emuParams else: defaultParams = '"%ROM%"' romCollection.emulatorParams = self.promptEmulatorParams( defaultParams) # Prompt for rompath romPath = self.promptRomPath(console) if romPath == '': log.info("No romPath selected. Action canceled.") break # Filemask fileMasks = self.promptEmulatorFileMasks() if fileMasks == []: break romCollection.romPaths = [] for fileMask in fileMasks: romCollection.romPaths.append( util.joinPath(romPath, fileMask.strip())) # Specific MAME settings if romCollection.name == 'MAME': romCollection.imagePlacingMain = ImagePlacing() romCollection.imagePlacingMain.name = 'gameinfomamecabinet' # MAME zip files contain several files but they must be passed to the emu as zip file romCollection.doNotExtractZipFiles = True if scenarioIndex == RETRIEVE_INFO_ONLINE_ARTWORK_ONLINE: # Prompt for artwork path artworkPath = self.promptArtworkPath(console, romPath) if artworkPath == '': log.info("No artworkPath selected. Action canceled.") break romCollection.descFilePerGame = True # Media Paths romCollection.mediaPaths = [] if romCollection.name == 'MAME': mediaTypes = [ 'boxfront', 'action', 'title', 'cabinet', 'marquee', 'clearlogo', 'gameplay' ] else: mediaTypes = [ 'boxfront', 'boxback', 'cartridge', 'screenshot', 'fanart', 'clearlogo', 'gameplay' ] for t in mediaTypes: romCollection.mediaPaths.append( self.createMediaPath(t, artworkPath, scenarioIndex)) else: romCollection.mediaPaths = [] # Default to looking in the romPath for the first artwork path lastArtworkPath = romPath while True: # Prompt the user for which artwork type we are selecting fileTypeIndex = dialog.select(util.localize(32183), fileTypeList) if fileTypeIndex == -1: log.info("No fileTypeIndex selected.") break fileType = fileTypeList[fileTypeIndex] fileTypeList.remove(fileType) # Prompt user for path for existing artwork artworkPath = util.convertToUnicodeString( dialog.browse( 0, util.localize(32182) % (console, fileType), 'files', '', False, False, lastArtworkPath)) log.debug(u"artworkPath selected: {0}".format(artworkPath)) if artworkPath == '': log.info("No artworkPath selected.") break lastArtworkPath = artworkPath romCollection.mediaPaths.append( self.createMediaPath(fileType, artworkPath, scenarioIndex)) # Ask to add another artwork path #32184 = Do you want to add another Artwork Path? if not dialog.yesno(util.SCRIPTNAME, util.localize(32184)): break #not used atm as we don't have any offline scrapers with descfile per game """ # Ask user for source of game descriptions (description file per game or for all games) descIndex = dialog.select(util.localize(32185), [util.localize(32186), util.localize(32187)]) log.debug("descIndex: " + str(descIndex)) if descIndex == -1: log.info("No descIndex selected. Action canceled.") break romCollection.descFilePerGame = (descIndex != GAME_DESCRIPTION_SINGLE_FILE) """ if scenarioIndex == RETRIEVE_INFO_LOCAL_ARTWORK_LOCAL: offline_scrapers = AbstractScraper( ).get_available_offline_scrapers(console) scraperIndex = dialog.select(util.localize(32206), offline_scrapers) if scraperIndex == -1: log.info("No Scraper type selected. Action canceled.") break selectedscraper = offline_scrapers[scraperIndex] log.info("Selected scraper = {0}".format(selectedscraper)) #not used atm as we don't have any offline scrapers with descfile per game """ if romCollection.descFilePerGame: # Assume the files are in a single directory with the mask %GAME%.txt # Prompt the user for the path pathValue = dialog.browse(0, util.localize(32189) % console, 'files') if pathValue == '': break # Prompt the user for the description file mask filemask = xbmcgui.Dialog().input(util.localize(32190), defaultt='%GAME%.xml', type=xbmcgui.INPUT_ALPHANUM) descPath = util.joinPath(pathValue, filemask.strip()) else: """ descPath = dialog.browse(1, util.localize(32189) % console, 'files', '', False, False, lastArtworkPath) log.info("descPath: " + str(descPath)) if descPath == '': log.info("No descPath selected. Action canceled.") break # Create scraper site = Site(name=selectedscraper, path=descPath, default=True) romCollection.scraperSites = [site] log.debug("Created new rom collection: {0}".format(romCollection)) romCollections[romCollection.id] = romCollection # Ask the user if they want to add another rom collection #32192 = Do you want to add another Rom Collection? if not dialog.yesno(util.SCRIPTNAME, util.localize(32192)): break del dialog return True, romCollections
def onClick(self, controlID): log.info("onClick") if controlID == CONTROL_BUTTON_EXIT: # Close window button log.info("close") self.close() # OK elif controlID == CONTROL_BUTTON_SAVE: log.info("save") # Store selectedRomCollection if self.selectedRomCollection is not None: self.updateSelectedRomCollection() self.romCollections[self.selectedRomCollection.id] = self.selectedRomCollection configWriter = ConfigXmlWriter(False) success, message = configWriter.writeRomCollections(self.romCollections, True) if not success: xbmcgui.Dialog().ok(util.localize(32021), message) self.close() # Cancel elif controlID == CONTROL_BUTTON_CANCEL: self.close() # Rom Collection list elif self.selectedControlId in (CONTROL_BUTTON_RC_DOWN, CONTROL_BUTTON_RC_UP): if self.selectedRomCollection is not None: # Save current values to selected Rom Collection self.updateSelectedRomCollection() # Store previous selectedRomCollections state self.romCollections[self.selectedRomCollection.id] = self.selectedRomCollection # HACK: add a little wait time as XBMC needs some ms to execute the MoveUp/MoveDown actions from the skin xbmc.sleep(util.WAITTIME_UPDATECONTROLS) self.updateRomCollectionControls() # Media Path elif self.selectedControlId in (CONTROL_BUTTON_MEDIA_DOWN, CONTROL_BUTTON_MEDIA_UP): # HACK: add a little wait time as XBMC needs some ms to execute the MoveUp/MoveDown actions from the skin xbmc.sleep(util.WAITTIME_UPDATECONTROLS) self.updateMediaPathControls() elif controlID == CONTROL_LIST_OFFLINE_SCRAPER: self.editOfflineScraper() elif controlID == CONTROL_BUTTON_GAMECLIENT: success, gameclient = helper.selectlibretrocore(self.selectedRomCollection.name) if success: self.selectedRomCollection.gameclient = gameclient control = self.getControlById(CONTROL_BUTTON_GAMECLIENT) if gameclient == "": control.setLabel("None") else: control.setLabel(gameclient) elif controlID == CONTROL_BUTTON_EMUCMD: self.editEmuCmd() elif controlID == CONTROL_BUTTON_PARAMS: emulatorParams = self.editTextProperty(CONTROL_BUTTON_PARAMS, util.localize(32625)) self.selectedRomCollection.emulatorParams = emulatorParams elif controlID == CONTROL_BUTTON_ROMPATH: self.editRomPath() elif controlID == CONTROL_BUTTON_FILEMASK: self.editRomFileMask() elif controlID == CONTROL_BUTTON_MEDIAPATH: self.editMediaPath() elif controlID == CONTROL_BUTTON_MEDIAFILEMASK: self.editMediaFileMask() elif controlID == CONTROL_BUTTON_ADDMEDIAPATH: self.addMediaPath() elif controlID == CONTROL_BUTTON_REMOVEMEDIAPATH: self.removeMediaPath() elif controlID == CONTROL_BUTTON_MAXFOLDERDEPTH: maxFolderDepth = self.editTextProperty(CONTROL_BUTTON_MAXFOLDERDEPTH, util.localize(32610)) self.selectedRomCollection.maxFolderDepth = maxFolderDepth elif controlID == CONTROL_BUTTON_DISKINDICATOR: diskIndicator = self.editTextProperty(CONTROL_BUTTON_DISKINDICATOR, util.localize(32611)) self.selectedRomCollection.diskPrefix = diskIndicator elif controlID == CONTROL_BUTTON_SAVESTATEPATH: saveStatePathComplete = self.editPathWithFileMask(CONTROL_BUTTON_SAVESTATEPATH, '%s ' % self.selectedRomCollection.name + util.localize(32629), CONTROL_BUTTON_SAVESTATEMASK) if saveStatePathComplete != '': self.selectedRomCollection.saveStatePath = saveStatePathComplete elif controlID == CONTROL_BUTTON_SAVESTATEMASK: self.selectedRomCollection.saveStatePath = self.editFilemask(CONTROL_BUTTON_SAVESTATEMASK, util.localize(32630), self.selectedRomCollection.saveStatePath) elif controlID == CONTROL_BUTTON_SAVESTATEPARAMS: saveStateParams = self.editTextProperty(CONTROL_BUTTON_SAVESTATEPARAMS, util.localize(32631)) self.selectedRomCollection.saveStateParams = saveStateParams elif controlID == CONTROL_BUTTON_PRECMD: preCmd = self.editTextProperty(CONTROL_BUTTON_PRECMD, util.localize(32632)) self.selectedRomCollection.preCmd = preCmd log.info("OnClick: precmd = {0}".format(self.selectedRomCollection.preCmd)) elif controlID == CONTROL_BUTTON_POSTCMD: postCmd = self.editTextProperty(CONTROL_BUTTON_POSTCMD, util.localize(32633)) self.selectedRomCollection.postCmd = postCmd
def post_launch(self, romCollection, gameRow, postcmd): log.info("AbstractLauncher.post_launch()") pass
def _buildCmd(self, gui, filenameRows, gameRow, calledFromSkin): log.info("launcher.buildCmd") compressedExtensions = ['7z', 'zip'] cmd = "" precmd = "" postcmd = "" roms = [] emuCommandLine = self.romCollection.emulatorCmd log.info("emuCommandLine: " + emuCommandLine) log.info("preCmdLine: " + self.romCollection.preCmd) log.info("postCmdLine: " + self.romCollection.postCmd) # handle savestates stateFile = self.__checkGameHasSaveStates(gameRow, filenameRows) if stateFile == '': emuParams = self.romCollection.emulatorParams else: emuParams = self.romCollection.saveStateParams if self.escapeCmd: stateFile = re.escape(stateFile) emuParams = emuParams.replace('%statefile%', stateFile) emuParams = emuParams.replace('%STATEFILE%', stateFile) emuParams = emuParams.replace('%Statefile%', stateFile) # params could be: {-%I% %ROM%} # we have to repeat the part inside the brackets and replace the %I% with the current index emuParams, partToRepeat = self.__prepareMultiRomCommand(emuParams) # ask for disc number if multidisc game diskName = "" if self.romCollection.diskPrefix != '' and '%I%' not in emuParams: log.info("Getting Multiple Disc Parameter") options = [] for disk in filenameRows: gamename = os.path.basename(disk[0]) match = re.search(self.romCollection.diskPrefix, gamename, re.IGNORECASE) if match: disk = gamename[match.start():match.end()] options.append(disk) if len(options) > 1 and not calledFromSkin: diskNum = xbmcgui.Dialog().select(util.localize(32164) + ': ', options) if diskNum < 0: # don't launch game log.info("No disc was chosen. Won't launch game") return "", "", "", None else: diskName = options[diskNum] log.info("Chosen Disc: %s" % diskName) # insert game specific command gameCmd = '' if gameRow[GameView.COL_gameCmd] is not None: gameCmd = str(gameRow[GameView.COL_gameCmd]) # be case insensitive with (?i) emuParams = re.sub('(?i)%gamecmd%', gameCmd, emuParams) log.info("emuParams: " + emuParams) fileindex = int(0) for fileNameRow in filenameRows: rom = fileNameRow[0] log.info("rom: " + rom) if self.romCollection.makeLocalCopy: localDir = os.path.join(util.getTempDir(), self.romCollection.name) if xbmcvfs.exists(localDir + '\\'): log.info("Trying to delete local rom files") dirs, files = xbmcvfs.listdir(localDir) for f in files: xbmcvfs.delete(os.path.join(localDir, f)) localRom = os.path.join(localDir, os.path.basename(str(rom))) log.info("Creating local copy: " + str(localRom)) if xbmcvfs.copy(rom, localRom): log.info("Local copy created") rom = localRom # If it's a .7z file # Don't extract zip files in case of savestate handling and when called From skin filext = rom.split('.')[-1] roms = [rom] if filext in compressedExtensions and not self.romCollection.doNotExtractZipFiles and stateFile == '' and not calledFromSkin: roms = self.__handleCompressedFile(gui, filext, rom, emuParams) log.debug("roms compressed = " + str(roms)) if len(roms) == 0: return "", "", "", None # no use for complete cmd as we just need the game name if self.romCollection.useBuiltinEmulator: log.debug("roms = " + str(roms)) return "", "", "", roms del rom for rom in roms: if fileindex == 0: emuParams = self.__replacePlaceholdersInParams(emuParams, rom, gameRow) if self.escapeCmd: emuCommandLine = re.escape(emuCommandLine) if self.romCollection.name in ['Linux', 'Macintosh', 'Windows']: cmd = self.__replacePlaceholdersInParams(emuCommandLine, rom, gameRow) else: cmd = '\"' + emuCommandLine + '\" ' + emuParams.replace('%I%', str(fileindex)) else: newrepl = partToRepeat newrepl = self.__replacePlaceholdersInParams(newrepl, rom, gameRow) if self.escapeCmd: emuCommandLine = re.escape(emuCommandLine) newrepl = newrepl.replace('%I%', str(fileindex)) if newrepl: cmd += ' ' + newrepl cmdprefix = '' if self.env == "win32": cmdprefix = 'call ' precmd = cmdprefix + self.__replacePlaceholdersInParams(self.romCollection.preCmd, rom, gameRow) postcmd = cmdprefix + self.__replacePlaceholdersInParams(self.romCollection.postCmd, rom, gameRow) fileindex += 1 # A disk was chosen by the user, select it here if diskName: log.info("Choosing Disk: " + str(diskName)) match = re.search(self.romCollection.diskPrefix.lower(), cmd.lower()) replString = cmd[match.start():match.end()] cmd = cmd.replace(replString, diskName) return cmd, precmd, postcmd, roms
def launchEmu(self, gdb, gui, gameId, config, listitem): log.info("Begin launcher.launchEmu") gameRow = GameView(gdb).getObjectById(gameId) if gameRow is None: log.error("Game with id %s could not be found in database" % gameId) return try: self.romCollection = config.romCollections[str(gameRow[GameView.COL_romCollectionId])] except KeyError: log.error("Cannot get rom collection with id: " + str(gameRow[GameView.COL_romCollectionId])) gui.writeMsg(util.localize(32034)) return gui.writeMsg(util.localize(32163) + " " + gameRow[DataBaseObject.COL_NAME]) # Remember viewstate gui.saveViewState(False) filenameRows = File(gdb).getRomsByGameId(gameRow[DataBaseObject.COL_ID]) log.info("files for current game: " + str(filenameRows)) cmd, precmd, postcmd, roms = self._buildCmd(gui, filenameRows, gameRow, False) if not self.romCollection.useBuiltinEmulator: if cmd == '': log.info("No cmd created. Game will not be launched.") return if precmd.strip() == '' or precmd.strip() == 'call': log.info("No precmd created.") if postcmd.strip() == '' or postcmd.strip() == 'call': log.info("No postcmd created.") # solo mode if self.romCollection.useEmuSolo: self.__copyLauncherScriptsToUserdata() # communicate with service via settings __addon__.setSetting(util.SETTING_RCB_LAUNCHONSTARTUP, 'true') # invoke script file that kills xbmc before launching the emulator basePath = os.path.join(util.getAddonDataPath(), 'scriptfiles') if self.env == "win32": if __addon__.getSetting(util.SETTING_RCB_USEVBINSOLOMODE).lower() == 'true': # There is a problem with quotes passed as argument to windows command shell. This only works with "call" # use vb script to restart xbmc cmd = 'call \"' + os.path.join(basePath, 'applaunch-vbs.bat') + '\" ' + cmd else: # There is a problem with quotes passed as argument to windows command shell. This only works with "call" cmd = 'call \"' + os.path.join(basePath, 'applaunch.bat') + '\" ' + cmd else: cmd = os.path.join(basePath, 'applaunch.sh ') + cmd else: # use call to support paths with whitespaces if self.env == "win32": cmd = 'call ' + cmd # update LaunchCount launchCount = gameRow[GameView.COL_launchCount] if launchCount is None: launchCount = 0 Game(gdb).update(('launchCount',), (launchCount + 1,), gameRow[Game.COL_ID], True) gdb.commit() log.info("cmd: " + cmd) log.info("precmd: " + precmd) log.info("postcmd: " + postcmd) try: self.__launchNonXbox(cmd, gameRow, precmd, postcmd, roms, gui, listitem) gui.writeMsg("") except Exception as exc: log.error("Error while launching emu: " + str(exc)) gui.writeMsg(util.localize(32035) + ": " + str(exc)) log.info("End launcher.launchEmu")
def replace_diskname(self, romCollection, cmd, diskName): log.info("AbstractLauncher.replace_disk_name()") return cmd
def __handleCompressedFile(self, gui, filext, rom, emuParams): log.info("__handleCompressedFile") # 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 tempDir = os.path.join(util.getTempDir(), 'extracted', self.romCollection.name) # check if folder exists if not xbmcvfs.exists(tempDir + '\\'): log.info("Create temporary folder: " + tempDir) xbmcvfs.mkdir(tempDir) try: if xbmcvfs.exists(tempDir + '\\'): log.info("Trying to delete temporary rom files") #can't use xbmcvfs.listdir here as it seems to cache the file list and RetroPlayer won't find newly created files anymore files = os.listdir(tempDir) for f in files: #RetroPlayer places savestate files next to the roms. Don't delete these files. fname, ext = os.path.splitext(f) if ext not in ('.sav', '.xml', '.png'): xbmcvfs.delete(os.path.join(tempDir, f)) except Exception as exc: log.error("Error deleting files after launch emu: " + str(exc)) gui.writeMsg(util.localize(32036) + ": " + str(exc)) roms = [] log.info("Treating file as a compressed archive") try: names = self.__getNames(filext, rom) except Exception as exc: log.error("Error handling compressed file: " + str(exc)) return [] if names is None: log.error("Error handling compressed file") return [] chosenROM = -1 # check if we should handle multiple roms match = False if self.romCollection.diskPrefix != '': match = re.search(self.romCollection.diskPrefix.lower(), str(names).lower()) if '%I%' in emuParams and match: log.info("Loading %d archives" % len(names)) try: archives = self.__getArchives(filext, rom, names) except Exception as exc: log.error("Error handling compressed file: " + str(exc)) return [] if archives is None: log.warning("Error handling compressed file") return [] for archive in archives: newPath = os.path.join(tempDir, archive[0]) fp = open(newPath, 'wb') fp.write(archive[1]) fp.close() roms.append(newPath) elif len(names) > 1: log.info("The Archive has %d files" % len(names)) chosenROM = xbmcgui.Dialog().select('Choose a ROM', names) elif len(names) == 1: log.info("Archive only has one file inside; picking that one") chosenROM = 0 else: log.error("Archive had no files inside!") return [] if chosenROM != -1: # Extract all files to %TMP% archives = self.__getArchives(filext, rom, names) if archives is None: log.warn("Error handling compressed file") return [] for archive in archives: newPath = os.path.join(tempDir, archive[0]) log.info("Putting extracted file in %s" % newPath) fo = open(str(newPath), 'wb') fo.write(archive[1]) fo.close() # Point file name to the chosen file and continue as usual roms = [os.path.join(tempDir, names[chosenROM])] return roms
def onClick(self, controlID): log.info('onClick') if controlID == CONTROL_BUTTON_EXIT: # Close window button log.info('Close') self.close() elif controlID == CONTROL_BUTTON_CANCEL: # Cancel button self.close() elif controlID == CONTROL_BUTTON_SAVE: # OK log.info('Save') # Store selectedRomCollection if self.selectedRomCollection is not None: # Code to Remove Roms log.info('Removing Roms') self._setDeleteStatus(True) # Code to Remove Collection if self.romDelete == 'RCollection': self._setRCDeleteStatus(True) Logutil.log('Removing Rom Collection', util.LOG_LEVEL_INFO) configWriterRCDel = ConfigXmlWriter(False) RCName = str(self.selectedRomCollection.name) success, message = configWriterRCDel.removeRomCollection( RCName) if success is False: log.error(message) xbmcgui.Dialog().ok(util.localize(32019), util.localize(32020)) log.info('Click Close') self.close() elif self.selectedControlId in (CONTROL_BUTTON_RC_DOWN, CONTROL_BUTTON_RC_UP): # Changing selection in Rom Collection list if self.selectedRomCollection is not None: # Store previous selectedRomCollections state self.romCollections[ self.selectedRomCollection.id] = self.selectedRomCollection # HACK: add a little wait time as XBMC needs some ms to execute the MoveUp/MoveDown actions from the skin xbmc.sleep(util.WAITTIME_UPDATECONTROLS) self.updateControls() elif self.selectedControlId in (CONTROL_BUTTON_DEL_DOWN, CONTROL_BUTTON_DEL_UP): # Changing selection in Delete Option list control = self.getControlById(CONTROL_LIST_DELETEOPTIONS) selectedDeleteOption = str(control.getSelectedItem().getLabel2()) log.info('selectedDeleteOption = {0}'.format(selectedDeleteOption)) self.romDelete = selectedDeleteOption
def __launchNonXbox(self, cmd, gameRow, precmd, postcmd, roms, gui, listitem): log.info("launchEmu on non-xbox") screenModeToggled = False # use libretro core to play game if self.romCollection.useBuiltinEmulator: log.info("launching game with internal emulator") rom = roms[0] gameclient = self.romCollection.gameclient # HACK: use alternateGameCmd as gameclient if gameRow[GameView.COL_alternateGameCmd] is not None and gameRow[GameView.COL_alternateGameCmd] != "": gameclient = str(gameRow[GameView.COL_alternateGameCmd]) log.info("Preferred gameclient: " + gameclient) log.info("Setting platform: " + self.romCollection.name) #if game is launched from RCB widget there is no listitem if listitem is None: listitem = xbmcgui.ListItem(rom) parameters = {"platform": self.romCollection.name} if gameclient != "": parameters["gameclient"] = gameclient listitem.setInfo(type="game", infoLabels=parameters) log.info("launching rom: " + rom) gui.player.play(rom, listitem) # xbmc.executebuiltin('PlayMedia(\"%s\", platform=%s, gameclient=%s)' %(rom, romCollection.name, romCollection.gameclient)) return if not self.romCollection.useEmuSolo: screenMode = xbmc.getInfoLabel("System.Screenmode") log.info("screenMode: " + screenMode) isFullScreen = screenMode.endswith("Full Screen") toggleScreenMode = __addon__.getSetting(util.SETTING_RCB_TOGGLESCREENMODE).upper() == 'TRUE' if isFullScreen and toggleScreenMode: log.info("Toggling to windowed mode") # this minimizes xbmc some apps seems to need it xbmc.executeJSONRPC(KODI_JSONRPC_TOGGLE_FULLSCREEN) screenModeToggled = True log.info("launch emu") self.__executePreCommand(precmd) self.__preDelay() self.__audioSuspend() self.__executeCommand(cmd) log.info("launch emu done") self.__postDelay() self.__audioResume() self.__executePostCommand(postcmd) if screenModeToggled: log.info("Toggle to Full Screen mode") # this brings xbmc back xbmc.executeJSONRPC(KODI_JSONRPC_TOGGLE_FULLSCREEN)
def launch(self, romCollection, gameRow, cmd, roms, listitem): log.info("AbstractLauncher.launch()") pass
def __executePreCommand(self, precmd): # pre launch command if precmd.strip() != '' and precmd.strip() != 'call': log.info("Got to PRE: " + precmd.strip()) os.system(precmd)
def is_archive(self, rom): log.info("ArchiveHandler.is_archive") if rom is None: return False return rom.split('.')[-1] in self.compressedExtensions
def updateRomCollectionControls(self): log.info("updateRomCollectionControls") control = self.getControlById(CONTROL_LIST_ROMCOLLECTIONS) selectedRomCollectionName = str(control.getSelectedItem().getLabel()) log.info( "selected rom collection: {0}".format(selectedRomCollectionName)) self.selectedRomCollection = self.gui.config.getRomCollectionByName( selectedRomCollectionName) if self.selectedRomCollection is None: return log.info("build scraper lists") self.availableScrapers = AbstractScraper().get_available_scrapers( self.selectedRomCollection.name) self.addItemsToList(CONTROL_LIST_DEFAULT_SCRAPER, self.availableScrapers) # Import Games self.updateRomParams() # Set the currently selected state for all the buttons for item in self._control_buttons: control = self.getControlById(item['control']) control.setSelected( getattr(self.selectedRomCollection, item['value'])) log.info('Set button control ID ' + str(item['control']) + ' to value ' + str(getattr(self.selectedRomCollection, item['value']))) # Set the value for all the labels for item in self._control_labels: control = self.getControlById(item['control']) util.setLabel(getattr(self.selectedRomCollection, item['value']), control) log.info('Set label control ID ' + str(item['control']) + ' to value ' + str(getattr(self.selectedRomCollection, item['value']))) # preferred scraper self.selectScrapersInList(self.selectedRomCollection.scraperSites, CONTROL_LIST_DEFAULT_SCRAPER) self.addOfflineScrapersToList() # Artwork # Media Types self.updateMediaTypes() # Browse Games optionMain = self.selectedRomCollection.imagePlacingMain.name try: optionMain = config.imagePlacingDict[optionMain] except IndexError: pass self.selectItemInList(optionMain, CONTROL_LIST_IMAGEPLACING_MAIN) optionInfo = self.selectedRomCollection.imagePlacingInfo.name try: optionInfo = config.imagePlacingDict[optionInfo] except IndexError: pass self.selectItemInList(optionInfo, CONTROL_LIST_IMAGEPLACING_INFO)
def __init__(self, *args, **kwargs): log.info('init Edit RC Basic') self.gui = kwargs["gui"] self.romCollections = self.gui.config.romCollections self.doModal()
def updateDB(self, gdb, gui, romCollections, isRescrape): self.gdb = gdb self._gui = gui log.info("Start Update DB") #at start, check if we need to create any artwork directories if not helper.createArtworkDirectories(romCollections): #32010: Error: Could not create artwork directory. return False, util.localize(32010) log.info("Iterating Rom Collections") rccount = 1 # always do full reimports when in rescrape-mode enableFullReimport = isRescrape or __addon__.getSetting(util.SETTING_RCB_ENABLEFULLREIMPORT).upper() == 'TRUE' log.info("enableFullReimport: {0}".format(enableFullReimport)) continueUpdate = True # Added variable to allow user to continue on errors ignoreErrors = False for romCollection in list(romCollections.values()): # timestamp1 = time.clock() # check if import was canceled if not continueUpdate: log.info("Game import canceled") break # prepare Header for ProgressDialog # 32122 = Importing Rom Collection progDialogRCHeader = util.localize(32122) + " (%i / %i): %s" % ( rccount, len(romCollections), romCollection.name) rccount += 1 log.info("current Rom Collection: {0}".format(romCollection.name)) # Read settings for current Rom Collection log.info("ignoreOnScan: {0}".format(romCollection.ignoreOnScan)) if romCollection.ignoreOnScan: log.info("current Rom Collection will be ignored.") # self.scrapeResultsFile.write('Rom Collection will be ignored.\n') continue log.info("update is allowed for current rom collection: {0}".format(romCollection.allowUpdate)) log.info("max folder depth: {0}".format(romCollection.maxFolderDepth)) files = self.getRomFilesByRomCollection(romCollection, enableFullReimport) if len(files) == 0: log.info(u"No files found for rom collection {0}, skipping".format(romCollection.name)) continue log.info(u"Found {0} game files for rom collection {1}".format(len(files), romCollection.name)) # itemCount is used for percentage in ProgressDialogGUI self._gui.itemCount = len(files) + 1 successfulFiles = 0 lastgamename = '' lastGameId = None for fileidx, filename in enumerate(files): try: #Give kodi a chance to interrupt the process #HACK: we should use monitor.abortRequested() or monitor.waitForAbort() #but for some reason only xbmc.abortRequested returns True if monitor.abortRequested(): log.info("Kodi requests abort. Cancel Update.") break log.info("Scraping for %s" % filename) gamenameFromFile = romCollection.getGamenameFromFilename(filename) # check if we are handling one of the additional disks of a multi rom game isMultiRomGame = (gamenameFromFile == lastgamename) lastgamename = gamenameFromFile if isMultiRomGame: # Add this entry as a file under the game ID and move on log.info("Detected %s as a multirom game (previous game was %s)" % (filename, lastgamename)) if lastGameId is None: log.error("Game detected as multi rom game, but lastGameId is None.") continue fileType = FileType() fileType.id, fileType.name, fileType.parent = 0, "rcb_rom", "game" self.insertFile(filename, lastGameId, fileType, None, None, None) self.gdb.commit() del fileType continue log.info("Start scraping info for game: %s" % gamenameFromFile) # 32123 = Importing Game msg = "%s: %s" %(util.localize(32123), gamenameFromFile) continueUpdate = self._gui.writeMsg(msg, fileidx + 1) if not continueUpdate: log.info("Game import canceled by user") break # check if this file already exists in DB continueUpdate, isUpdate, gameId = self.checkRomfileAlreadyExists(filename, enableFullReimport) if not continueUpdate: continue foldername = self.getFoldernameFromRomFilename(filename) results, artScrapers = self.useSingleScrapers(romCollection, filename, gamenameFromFile, progDialogRCHeader, fileidx + 1) if len(results) == 0: # lastgamename = "" results = None # Variables to process Art Download Info self._guiDict.update({'dialogHeaderKey': progDialogRCHeader, 'gameNameKey': gamenameFromFile, 'scraperSiteKey': artScrapers, 'fileCountKey': (fileidx + 1)}) del artScrapers #Give kodi a chance to interrupt the process #HACK: we should use monitor.abortRequested() or monitor.waitForAbort() #but for some reason only xbmc.abortRequested returns True if monitor.abortRequested(): log.info("Kodi requests abort. Cancel Update.") break # Add 'gui' and 'dialogDict' parameters to function lastGameId = self.insertGameFromDesc(results, gamenameFromFile, romCollection, [filename], foldername, isUpdate, gameId) del results, foldername if lastGameId is not None: log.info("Successfully added %s" % gamenameFromFile) successfulFiles += 1 # Check if all first 10 games have errors - Modified to allow user to continue on errors if fileidx > 9 and successfulFiles == 0 and not ignoreErrors: #32124 = Continue #32125 = Continue and Ignore Errors #32126 = Cancel #32127 = First 10 games could not be imported. options = [util.localize(32124), util.localize(32125), util.localize(32126)] answer = xbmcgui.Dialog().select(util.localize(32127), options) if answer == 1: # Continue and ignore errors ignoreErrors = True elif answer == 2: # Cancel #32128 = Import canceled. #32129 = Please check kodi.log for details. message = "%s[CR]%s" % (util.localize(32128), util.localize(32129)) xbmcgui.Dialog().ok(util.SCRIPTNAME, message) continueUpdate = False break except ScraperExceededAPIQuoteException: #32128 = Import canceled. #32043 = API quota for current scraper exceeded. xbmcgui.Dialog().ok(util.localize(32128), util.localize(32043)) # Abort the scraping entirely break except Exception as exc: log.warn(u"An error occurred while adding game %s: %s" % (gamenameFromFile, exc)) self.missingDescFile.add_entry(gamenameFromFile) continue # timestamp2 = time.clock() # diff = (timestamp2 - timestamp1) * 1000 # print "load %i games in %d ms" % (self.getListSize(), diff) self._gui.writeMsg("Done.", self._gui.itemCount) log.info("Update finished") return True, ''
def prepare_solomode(self, romCollection, cmd): log.info("AbstractLauncher.prepare_solomode()") return cmd
def useSingleScrapers(self, romCollection, romFile, gamenameFromFile, progDialogRCHeader, fileCount): """Scrape site for game metadata Args: romCollection: romFile: gamenameFromFile: progDialogRCHeader: fileCount: Returns: dict for the game result: {'SearchKey': ['Chrono Trigger'], 'Publisher': ['Squaresoft'], 'Description': ["The millennium. A portal is opened. The chain of time is broken...], 'Players': ['1'], 'Platform': ['Super Nintendo (SNES)'], 'Game': ['Chrono Trigger'], 'Filetypeboxfront': ['http://thegamesdb.net/banners/boxart/original/front/1255-1.jpg'], 'Filetypeboxback': ['http://thegamesdb.net/banners/boxart/original/back/1255-1.jpg'], 'Filetypescreenshot': ['http://thegamesdb.net/banners/screenshots/1255-1.jpg', 'http://thegamesdb.net/banners/screenshots/1255-2.jpg', 'http://thegamesdb.net/banners/screenshots/1255-3.jpg', 'http://thegamesdb.net/banners/screenshots/1255-4.jpg', 'http://thegamesdb.net/banners/screenshots/1255-5.jpg'], 'Filetypefanart': ['http://thegamesdb.net/banners/fanart/original/1255-1.jpg', 'http://thegamesdb.net/banners/fanart/original/1255-10.jpg', 'http://thegamesdb.net/banners/fanart/original/1255-11.jpg', 'http://thegamesdb.net/banners/fanart/original/1255-2.jpg', 'http://thegamesdb.net/banners/fanart/original/1255-3.jpg', 'http://thegamesdb.net/banners/fanart/original/1255-4.jpg', 'http://thegamesdb.net/banners/fanart/original/1255-5.jpg', 'http://thegamesdb.net/banners/fanart/original/1255-6.jpg', 'http://thegamesdb.net/banners/fanart/original/1255-7.jpg', 'http://thegamesdb.net/banners/fanart/original/1255-8.jpg', 'http://thegamesdb.net/banners/fanart/original/1255-9.jpg'], 'Genre': ['Role-Playing'], 'Developer': ['Squaresoft']} dict for artwork urls: {'Filetypefanart': 'thegamesdb.net', 'Filetypeboxback': 'thegamesdb.net', 'Filetypescreenshot': 'thegamesdb.net', 'Filetypeboxfront': 'thegamesdb.net'} Note - this only contains entries for artwork that was found (i.e. is not empty list) """ gameresult = {} artScrapers = {} scraperSite = None #search for default scraper if there are more than one for site in romCollection.scraperSites: if site.default: scraperSite = site break #if no default site was found, just use the first one if not scraperSite: if len(romCollection.scraperSites) >= 1: scraperSite = romCollection.scraperSites[0] try: #first check if a local nfo file is available nfoscraper = NFO_Scraper() nfofile = nfoscraper.get_nfo_path(gamenameFromFile, romCollection.name, romFile) if xbmcvfs.exists(nfofile) and __addon__.getSetting(util.SETTING_RCB_PREFERLOCALNFO).upper() == 'TRUE': log.info("Found local nfo file. Using this to scrape info.") newscraper = nfoscraper else: newscraper = AbstractScraper().get_scraper_by_name(scraperSite.name) #set path to desc file (only useful for offline scrapers) newscraper.path = scraperSite.path log.info("Using scraper: %s" % newscraper.name) # 32123 = Importing Game # 32131 = downloading info msg = "%s: %s[CR]%s: %s" %(util.localize(32123), gamenameFromFile, newscraper.name, util.localize(32131)) self._gui.writeMsg(msg, fileCount) results = newscraper.search(gamenameFromFile, romCollection.name) log.debug(u"Searching for %s - found %s results: %s" % (gamenameFromFile, len(results), results)) except ScraperExceededAPIQuoteException as ke: # API key is invalid - we need to stop scraping log.error("Scraper exceeded API key, stopping scraping") raise except Exception as e: log.error("Error searching for %s using scraper %s - %s %s" % ( gamenameFromFile, scraperSite.name, type(e), e)) return gameresult, artScrapers if results == []: log.warn("No search results found for %s using scraper %s" % (gamenameFromFile, scraperSite.name)) return gameresult, artScrapers matched = Matcher().getBestResults(results, gamenameFromFile) if matched is None: log.error("No matches found for %s, skipping" % gamenameFromFile) return gameresult, artScrapers log.debug("After matching: %s" % matched) try: retrievedresult = newscraper.retrieve(matched['id'], romCollection.name) log.debug(u"Retrieving %s - found %s" % (matched['id'], retrievedresult)) except Exception as e: # FIXME TODO Catch exceptions specifically log.error("Error retrieving %s - %s %s" % (matched['id'], type(e), e)) return gameresult, artScrapers # Update the gameresult with any new fields gameresult = self.addNewElements(gameresult, retrievedresult) # Find Filetypes and Scrapers for Art Download # FIXME TODO The following is kept to keep artwork downloading working as it currently is. We already have # the URLs and so could handle/download here, rather than deferring if len(gameresult) > 0: for path in romCollection.mediaPaths: thumbKey = 'Filetype' + path.fileType.name if len(self.resolveParseResult(gameresult, thumbKey)) > 0: if (thumbKey in artScrapers) == 0: artScrapers[thumbKey] = scraperSite.name log.debug(u"After scraping, result = %s, artscrapers = %s" % (gameresult, artScrapers)) return gameresult, artScrapers
def build_cmd(self, romCollection, gameRow, roms, emuParams, part_to_repeat_in_emuparams): log.info("AbstractLauncher.build_cmd()") return "", "", ""
def resolvePath(self, paths, gamename, gamenameFromFile, foldername, romCollectionName, publisher, developer): resolvedFiles = [] for path in paths: files = [] log.info("resolve path: %s" % path) if path.find("%GAME%") > -1: pathnameFromFile = path.replace("%GAME%", gamenameFromFile) log.info("resolved path from rom file name: %s" % pathnameFromFile) files = self.getFilesByWildcard(pathnameFromFile) if len(files) == 0: files = self.getFilesByGameNameIgnoreCase(pathnameFromFile) if gamename != gamenameFromFile and len(files) == 0: pathnameFromGameName = path.replace("%GAME%", gamename) log.info("resolved path from game name: %s" % pathnameFromGameName) files = self.getFilesByWildcard(pathnameFromGameName) if len(files) == 0: files = self.getFilesByGameNameIgnoreCase(pathnameFromGameName) if gamename != foldername and len(files) == 0: pathnameFromFolder = path.replace("%GAME%", foldername) log.info("resolved path from rom folder name: %s" % pathnameFromFolder) files = self.getFilesByWildcard(pathnameFromFolder) if len(files) == 0: files = self.getFilesByGameNameIgnoreCase(pathnameFromFolder) # ODO could be done only once per RomCollection if path.find("%ROMCOLLECTION%") > -1 and romCollectionName is not None and len(files) == 0: pathnameFromRomCollection = path.replace("%ROMCOLLECTION%", romCollectionName) log.info("resolved path from rom collection name: {0}".format(pathnameFromRomCollection)) files = self.getFilesByWildcard(pathnameFromRomCollection) if path.find("%PUBLISHER%") > -1 and publisher is not None and len(files) == 0: pathnameFromPublisher = path.replace("%PUBLISHER%", publisher) log.info("resolved path from publisher name: %s" % pathnameFromPublisher) files = self.getFilesByWildcard(pathnameFromPublisher) if path.find("%DEVELOPER%") > -1 and developer is not None and len(files) == 0: pathnameFromDeveloper = path.replace("%DEVELOPER%", developer) log.info("resolved path from developer name: %s" % pathnameFromDeveloper) files = self.getFilesByWildcard(pathnameFromDeveloper) if path.find("%GAME%") == -1 & path.find("%ROMCOLLECTION%") == -1 & path.find( "%PUBLISHER%") == -1 & path.find("%DEVELOPER%") == -1: pathnameFromStaticFile = path log.info("using static defined media file from path: %s" % pathnameFromStaticFile) files = self.getFilesByWildcard(pathnameFromStaticFile) if len(files) == 0: log.warn("No files found for game '%s' at path '%s'. Make sure that file names are matching." % ( gamename, path)) for f in files: if xbmcvfs.exists(f): resolvedFiles.append(f) return resolvedFiles
def replace_gamecmd(self, gameRow, emuParams): log.info("AbstractLauncher.replace_gamecmd()") return ""
def download_thumb(self, thumburl, destfilename): log.info("begin download_thumb using requests module: thumburl = %s" % thumburl) # Download file to tmp folder tmp = util.joinPath(util.getTempDir(), os.path.basename(destfilename)) log.info("download_thumb: start downloading to temp file: %s" % tmp) response = requests.get(thumburl, headers=WebScraper._headers, stream=True) log.info("download_thumb: status code = %s" % response.status_code) if response.status_code != 200: log.info("download_thumb: invalid response status code. Can't download image.") return with open(tmp, 'wb') as f: response.raw.decode_content = True shutil.copyfileobj(response.raw, f) log.info("download_thumb: copy from temp file to final destination: %s" % destfilename) # Copy from the tmp folder to the target location xbmcvfs.copy(tmp, destfilename) xbmcvfs.delete(tmp) log.info("end download_thumb")
def prepareMultiRomCommand(self, emuParams): log.info("AbstractLauncher.prepareMultiRomCommand()") return "", ""
def getThumbFromOnlineSource(self, gamedescription, fileType, fileName, artworkurls): log.info("Get thumb from online source") try: # maybe we got a thumb url from desc parser thumbKey = 'Filetype' + fileType log.info("using key: %s" % thumbKey) thumbUrl = self.resolveParseResult(gamedescription, thumbKey) if thumbUrl == '': return True, artworkurls artworkurls[fileType] = thumbUrl log.info("Get thumb from url: %s" % thumbUrl) rootExtFile = os.path.splitext(fileName) rootExtUrl = os.path.splitext(thumbUrl) files = [] if len(rootExtUrl) == 2 and len(rootExtFile) != 0: fileName = rootExtFile[0] + rootExtUrl[1] gameName = rootExtFile[0] + ".*" files = self.getFilesByWildcard(gameName) del rootExtFile, rootExtUrl if len(files) > 0: log.info("File already exists. Won't download again.") return True, artworkurls log.info("File %s does not exist, starting download" % fileName) # Dialog Status Art Download # Update progress dialog to state we are downloading art try: #32123 = Importing Game #32210 = downloading artwork msg = "%s: %s[CR]%s: %s" % (util.localize(32123), self._guiDict["gameNameKey"], self._guiDict["scraperSiteKey"][thumbKey], util.localize(32210)) self._gui.writeMsg(msg, self._guiDict["fileCountKey"]) except KeyError: log.warn("Unable to retrieve key from GUI dict") try: self.download_thumb(thumbUrl, fileName) except Exception as exc: log.error("Could not create file: '%s'. Error message: '%s'" % (fileName, exc)) # xbmcgui.Dialog().ok(util.localize(32012), util.localize(32011)) return False, artworkurls log.info("Download finished.") except Exception as exc: log.warn("Error in getThumbFromOnlineSource: %s" % exc) return True, artworkurls
from builtins import str from builtins import range from builtins import object import os, shutil from sqlite3 import dbapi2 as sqlite from util import Logutil as log from util import * import util log.info("Loading sqlite3 as DB engine") class GameDataBase(object): def __init__(self, databaseDir): self.dataBasePath = os.path.join(databaseDir, 'MyGames.db') #use scripts home for reading SQL files self.sqlDir = os.path.join(util.RCBHOME, 'resources', 'database') def connect(self): print (self.dataBasePath) self.connection = sqlite.connect(self.dataBasePath, check_same_thread=False) # Use row factory so we can retrieve values by column name self.connection.row_factory = sqlite.Row self.cursor = self.connection.cursor() #set cache size to 20000 pages (default is 2000) self.cursor.execute("PRAGMA cache_size = 20000")
def delete(self, gameId): log.info("Delete Files with gameId %s" % str(gameId)) self.deleteObjectByQuery(self.deleteQuery, (gameId,))
def __executePostCommand(self, postcmd): # post launch command if postcmd.strip() != '' and postcmd.strip() != 'call': log.info("Got to POST: " + postcmd.strip()) os.system(postcmd)
def onClick(self, controlID): if controlID == 5101: # Close window button self.close() elif controlID == 5110: # Import games self.close() self.gui.updateDB() elif controlID == 5121: # Rescrape single games self.close() if self.selectedGame is None: xbmcgui.Dialog().ok(util.SCRIPTNAME, util.localize(32013), util.localize(32014)) return romCollectionId = self.selectedGame.getProperty('romCollectionId') romCollection = self.gui.config.romCollections[str(romCollectionId)] files = File(self.gui.gdb).getRomsByGameId(self.selectedGame.getProperty('gameId')) filename = files[0][0] romCollection.romPaths = (filename,) romCollections = {} romCollections[romCollection.id] = romCollection self.gui.rescrapeGames(romCollections) elif controlID == 5122: # Rescrape selection self.close() romCollections = {} listSize = self.gui.getListSize() for i in range(0, listSize): listItem = self.gui.getListItem(i) romCollectionId = listItem.getProperty('romCollectionId') try: romCollection = romCollections[str(romCollectionId)] except: romCollection = self.gui.config.romCollections[str(romCollectionId)] romCollection.romPaths = [] files = File(self.gui.gdb).getRomsByGameId(listItem.getProperty('gameId')) try: filename = files[0][0] romCollection.romPaths.append(filename) romCollections[romCollection.id] = romCollection except: log.info("Error getting filename for romCollectionId: {0}".format(romCollectionId)) self.gui.rescrapeGames(romCollections) #self.gui.updateDB() elif controlID == 5111: # Add Rom Collection self.close() statusOk, errorMsg = wizardconfigxml.ConfigXmlWizard().addRomCollection(self.gui.config) if statusOk is False: xbmcgui.Dialog().ok(util.SCRIPTNAME, util.localize(32001), errorMsg) log.info("Error updating config.xml: {0}".format(errorMsg)) return #update self.config statusOk, errorMsg = self.gui.config.readXml() if statusOk is False: xbmcgui.Dialog().ok(util.SCRIPTNAME, util.localize(32002), errorMsg) log.info("Error reading config.xml: {0}".format(errorMsg)) return #import Games self.gui.updateDB() elif controlID == 5112: # Edit Rom Collection self.close() constructorParam = "720p" editRCdialog = dialogeditromcollection.EditRomCollectionDialog("script-RCB-editromcollection.xml", util.getAddonInstallPath(), util.getConfiguredSkin(), constructorParam, gui=self.gui) del editRCdialog self.gui.config = Config(None) self.gui.config.readXml() elif controlID == 5113: # Edit Game Command self.close() if(self.selectedGame == None): xbmcgui.Dialog().ok(util.SCRIPTNAME, util.localize(32015), util.localize(32014)) return origCommand = self.selectedGame.getProperty('gameCmd') command = xbmcgui.Dialog().input(util.localize(32135), defaultt=origCommand, type=xbmcgui.INPUT_ALPHANUM) if command != origCommand: log.info("Updating game '{0}' with command '{1}'".format(self.selectedGame.getLabel(), command)) Game(self.gui.gdb).update(('gameCmd',), (command,), self.selectedGame.getProperty('gameId'), True) self.gui.gdb.commit() elif controlID == 5118: # (Un)Mark as Favorite self.close() if self.selectedGame is None: xbmcgui.Dialog().ok(util.SCRIPTNAME, util.localize(32016), util.localize(32014)) return isFavorite = '1' if self.selectedGame.getProperty('isfavorite') == '1': isFavorite = '0' log.info("Updating game '{0}' set isFavorite = {1}".format(self.selectedGame.getLabel(), isFavorite)) Game(self.gui.gdb).update(('isfavorite',), (isFavorite,), self.selectedGame.getProperty('gameId'), True) self.gui.gdb.commit() if isFavorite == '0': isFavorite = '' self.selectedGame.setProperty('isfavorite', str(isFavorite)) elif controlID == 5119: # (Un)Mark as Favorite self.close() if self.selectedGame is None: xbmcgui.Dialog().ok(util.SCRIPTNAME, util.localize(32016), util.localize(32014)) return isFavorite = '1' if self.selectedGame.getProperty('isfavorite') == '1': isFavorite = '0' listSize = self.gui.getListSize() for i in range(0, listSize): listItem = self.gui.getListItem(i) log.info("Updating game '{0}' set isfavorite = {1}".format(listItem.getLabel(), isFavorite)) Game(self.gui.gdb).update(('isfavorite',), (isFavorite,), listItem.getProperty('gameId'), True) listItem.setProperty('isfavorite', str(isFavorite)) self.gui.gdb.commit() #HACK: removing favorites does not update the UI. So do it manually. if isFavorite == 0: self.gui.loadViewState() elif controlID == 5120: # Export nfo files self.close() nfowriter.NfoWriter().exportLibrary(self.gui.gdb, self.gui.config.romCollections) elif controlID == 5114: # Delete Rom self.close() pos = self.gui.getCurrentListPosition() if pos == -1: xbmcgui.Dialog().ok(util.SCRIPTNAME, util.localize(32017), util.localize(32018)) return dialog = xbmcgui.Dialog() if dialog.yesno(util.localize(32510), util.localize(32136)): gameID = self.selectedGame.getProperty('gameId') self.gui.deleteGame(gameID) self.gui.showGames() if pos > 0: pos = pos - 1 self.gui.setFilterSelection(self.gui.CONTROL_GAMES_GROUP_START, pos) else: self.gui.setFilterSelection(self.gui.CONTROL_GAMES_GROUP_START, 0) elif controlID == 5115: # Remove Rom Collection self.close() constructorParam = "720p" removeRCDialog = dialogdeleteromcollection.RemoveRCDialog("script-RCB-removeRC.xml", util.getAddonInstallPath(), util.getConfiguredSkin(), constructorParam, gui=self.gui) rDelStat = removeRCDialog.getDeleteStatus() if rDelStat: selectedRCId = removeRCDialog.getSelectedRCId() rcDelStat = removeRCDialog.getRCDeleteStatus() self.gui.deleteRCGames(selectedRCId, rcDelStat, rDelStat) del removeRCDialog elif controlID == 5116: # Clean DB self.close() self.gui.cleanDB() elif controlID == 5223: # Open Settings self.close() self.gui.Settings.openSettings() elif controlID == 5224: # Set gameclient self.close() if not helper.isRetroPlayerSupported(): log.info("This RetroPlayer branch does not support selecting gameclients.") return if self.selectedGame is None or self.gameRow is None: xbmcgui.Dialog().ok(util.SCRIPTNAME, util.localize(32015), util.localize(32014)) return #HACK: use alternateGameCmd to store gameclient information origGameClient = self.selectedGame.getProperty('alternateGameCmd') gameclient = '' romCollectionId = self.selectedGame.getProperty('romCollectionId') romCollection = self.gui.config.romCollections[str(romCollectionId)] success, selectedcore = helper.selectlibretrocore(romCollection.name) if success: gameclient = selectedcore else: log.info("No libretro core was chosen. Won't update game command.") return if gameclient != origGameClient: log.info("Updating game '{0}' with gameclient '{1}'".format(self.selectedGame.getLabel(), gameclient)) Game(self.gui.gdb).update(('alternateGameCmd',), (gameclient,), self.selectedGame.getProperty('gameId'), True) self.gui.gdb.commit()
def launch(self, romCollection, gameRow, cmd, roms, listitem): log.info("Cmd_Launcher.launch()") self.__executeCommand(romCollection, cmd)
def prepare(self, romCollection, gameRow): log.info("AbstractLauncher.prepare()") # Remember viewstate self.gui.saveViewState(False) filenameRows = File(self.gdb).getRomsByGameId( gameRow[DataBaseObject.COL_ID]) log.info("files for current game: " + str(filenameRows)) # handle savestates saveStateParams = self.checkGameHasSaveStates(romCollection, gameRow, filenameRows) # ask for disc number if multidisc game diskName = self._selectdisc(romCollection, filenameRows, self.calledFromSkin) # params could be: {-%I% %ROM%} # we have to repeat the part inside the brackets and replace the %I% with the current index emuParams, part_to_repeat_in_emuparams = self.prepareMultiRomCommand( romCollection.emulatorParams) # insert game specific command emuParams = self.replace_gamecmd(gameRow, emuParams) #iterate rom files fileindex = int(0) roms = [] archive_handler = ArchiveHandler() for fileNameRow in filenameRows: rom = fileNameRow[0] log.info("rom: " + rom) rom = self._copylocal(romCollection, rom) if (archive_handler.is_archive(rom)): # Don't extract zip files in case of savestate handling and when called From skin if (not romCollection.doNotExtractZipFiles and saveStateParams == '' and not self.calledFromSkin): extracted_roms = archive_handler.extract_archive( romCollection, rom, emuParams) roms.extend(extracted_roms) precmd, postcmd, cmd = self.build_cmd(romCollection, gameRow, roms, emuParams, part_to_repeat_in_emuparams) cmd = self.replace_diskname(romCollection, cmd, diskName) cmd = self.prepare_solomode(romCollection, cmd) self.__update_launchcount(gameRow) log.info("cmd: " + cmd) log.info("precmd: " + precmd) log.info("postcmd: " + postcmd) return precmd, postcmd, cmd, roms