def createCustomList(self, current_path): customlist = [] current_path = os.path.realpath(current_path) currentMountPoint = self.mountpoint(current_path) currentRelPath = current_path[len(currentMountPoint):] if current_path != "" and currentRelPath != config.MVC.movie_pathlimit.value: customlist.append(MovieCache.getInstance().getMovie( os.path.join(current_path, ".."))) # Insert these entries always at last if current_path == os.path.realpath(config.MVC.movie_homepath.value): if config.MVC.movie_trashcan_enable.value and config.MVC.movie_trashcan_show.value: customlist.append(MovieCache.getInstance().getMovie( config.MVC.movie_trashcan_path.value)) if config.MVC.bookmarks.value: bookmarks = self.getBookmarks() if bookmarks: for bookmark in bookmarks: customlist.append( MovieCache.getInstance().newMovieEntry( directory=os.path.dirname(bookmark), filetype=TYPE_ISDIR, path=bookmark, filename=os.path.basename(bookmark), ext=cmtBM, name=os.path.basename(bookmark))) return customlist
def recEvent(self, timer): # StateWaiting=0, StatePrepared=1, StateRunning=2, StateEnded=3 from MovieCache import MovieCache if timer and not timer.justplay: #print("MVC: RecordingsControl: recEvent: timer.Filename: %s, timer.state: %s" % (timer.Filename, timer.state)) if timer.state == TimerEntry.StatePrepared: # #print("MVC: RecordingsControl: recEvent: timer.StatePrepared") pass elif timer.state == TimerEntry.StateRunning: #print("MVC: RecordingsControl: recEvent: REC START for: " + timer.Filename) DelayedFunction(250, MovieCache.getInstance().loadDatabaseFile, timer.Filename) DelayedFunction(500, self.reloadList) elif timer.state == TimerEntry.StateEnded or timer.state == TimerEntry.StateWaiting: #print("MVC: RecordingsControl: recEvent: REC END for: " + timer.Filename) MovieCache.getInstance().update(timer.Filename, psize=os.path.getsize(timer.Filename)) DelayedFunction(500, self.reloadList) # [Cutlist.Workaround] Initiate the Merge DelayedFunction(500, self.mergeCutListAfterRecording, timer.Filename) if hasattr(timer, "fixMoveCmd"): #print("MVC: RecordingsControl: recEvent: file had been moved while recording was in progress, moving left over files...") mvcTasker.shellExecute(timer.fixMoveCmd) if config.MVC.timer_autoclean.value: DelayedFunction(2000, self.timerCleanup) # postpone to avoid crash in basic timer delete by user
def execFileOpCopy(self, c, path, target_path): print("MVC: FileOps: execFileOpCopy: path: %s, target_path: %s" % (path, target_path)) MovieCache.getInstance().copy(path, target_path) path, _ext = os.path.splitext(path) c.append('cp "' + path + '."* "' + target_path + '/"') source_path = os.path.dirname(path) dest_path = target_path print("MVC: FileOps: execFileOpCopy: c: %s" % (c)) return c, source_path, dest_path
def MVCStartup(): print("MVC: plugin: +++") print("MVC: plugin: +++ MVC: " + VERSION + " starts...") print("MVC: plugin: +++") loadLCDSkin() setEPGLanguage() MovieCache.getInstance() RecordingsControl() Trashcan()
def check4ActiveRecordings(self): from MovieCache import MovieCache, IDX_PATH #print("MVC: RecordingsControl: check4ActiveRecordings") for timer in NavigationInstance.instance.RecordTimer.timer_list: # check if file is in cache if timer.Filename and timer.isRunning() and not timer.justplay: afile = MovieCache.getInstance().getFile(timer.Filename) if not afile[IDX_PATH]: #print("MVC: RecordingsControl: check4ActiveRecordings: loadDatabaseFile: " + timer.Filename) MovieCache.getInstance().loadDatabaseFile(timer.Filename)
def createTrashcan(self): try: os.makedirs(config.MVC.movie_trashcan_path.value) MovieCache.getInstance().loadDatabaseDir( config.MVC.movie_trashcan_path.value) self.reloadList() except Exception as e: config.MVC.movie_trashcan_enable.value = False self.checkHideMiniTV_beforeFullscreen() self.session.open( MessageBox, _("Trashcan creation failed. Check mounts and permissions!"), MessageBox.TYPE_ERROR) print("MVC: Trashcan: createTrashcan: exception:\n" + str(e))
def getSize(self): if self.__filetype == TYPE_ISFILE: size = self.__size else: if config.MVC.directories_info.value or config.MVC.movie_trashcan_info.value: _count, size = MovieCache.getInstance().getCountSize(self.path) return size
def getDateText(path, info_value, filetype, ext): datetext = "" count, size = MovieCache.getInstance().getCountSize(path) counttext = "%d" % count size /= (1024 * 1024 * 1024) # GB sizetext = "%.0f GB" % size if size >= 1024: sizetext = "%.1f TB" % size / 1024 #print("MVC: MovieCenterGUI: getValues: count: %s, size: %s" % (count, size)) if info_value == "C": datetext = "(%s)" % counttext if info_value == "S": datetext = "(%s)" % sizetext if info_value == "CS": datetext = "(%s/%s)" % (counttext, sizetext) if info_value == "D": if ext == cmtTrash: datetext = _("trashcan") elif config.MVC.directories_ontop.value: datetext = _("Collection") elif filetype == TYPE_ISLINK: datetext = _("Link") else: datetext = _("Directory") #print("MVC: MovieCenterGUI: getValues: datetext: %s" % (datetext)) return count, datetext
def execFileOpDelete(self, c, path, file_type): print("MVC: FileOps: execFileOpDelete: path: %s, file_type: %s" % (path, file_type)) MovieCache.getInstance().delete(path) # name.ts if file_type == "file": cover_path = self.getCoverPath(path) c.append('rm -f "' + cover_path + '"') # name.jpg or different movie dir path, _ext = os.path.splitext(path) c.append('rm -f "' + path + '."*') # name.* elif file_type == "dir": c.append('rm -rf "' + path + '"') elif file_type == "link": c.append('rm -f "' + path + '"') source_path = os.path.dirname(path) dest_path = None print("MVC: FileOps: execFileOpDelete: c: %s" % c) return c, source_path, dest_path
def bqtListFolders(self): movie_homepath = os.path.realpath(config.MVC.movie_homepath.value) dirs = MovieCache.getInstance().getDirList(movie_homepath) dirlist = [] for adir in dirs: dirlist.append(adir[IDX_PATH]) dirlist.sort() return dirlist
def trashcanExists(self): trashcan_exists = False afile = MovieCache.getInstance().getFile( config.MVC.movie_trashcan_path.value) if config.MVC.movie_trashcan_enable.value and afile[ MOVIE_IDX_PATH] != "": trashcan_exists = True return trashcan_exists
def execFileOpMove(self, c, path, target_path, file_type): print("MVC: FileOps: execFileOpMove: path: %s, target_path: %s, file_type: %s" % (path, target_path, file_type)) MovieCache.getInstance().move(path, target_path) path, _ext = os.path.splitext(path) if file_type == "file": if target_path == config.MVC.movie_trashcan_path.value: c.append('touch "' + path + '."*') c.append('mv "' + path + '."* "' + target_path + '/"') elif file_type == "dir": if target_path == config.MVC.movie_trashcan_path.value: c.append('touch "' + path) c.append('mv "' + path + '" "' + target_path + '"') elif file_type == "link": if target_path == config.MVC.movie_trashcan_path.value: c.append('touch "' + path) c.append('mv "' + path + '" "' + target_path + '"') source_path = os.path.dirname(path) dest_path = target_path print("MVC: FileOps: execFileOpMove: c: %s" % c) return c, source_path, dest_path
def reloadInternal(self, current_path): #print("MVC: MovieCenterGUI: reloadInternal: current_path: " + current_path) customlist, subdirlist, filelist = [], [], [] resetlist = True nextSort = None # Create listings if not os.path.splitext(current_path)[1]: # Read subdirectories and filenames subdirlist, filelist = self.createDirList(current_path) customlist = self.createCustomList(current_path) elif os.path.splitext(current_path)[1] in plyAll: # Found file #print("MVC: MovieCenterGUI: reloadInternal: file/recording found") filelist = [] filelist.append(MovieCache.getInstance().getFile(current_path)) resetlist = False current_path = None else: # Found virtual directory # No changes done return False # Add custom entries and sub directories to the list tmplist = customlist + subdirlist + filelist self.currentSelectionCount = 0 self.selectionList = None if current_path: self.current_path = current_path if self.returnSort: # Restore sorting mode self.actualSort = self.returnSort self.returnSort = None if nextSort: # Backup the actual sorting mode if self.returnSort is None: self.returnSort = self.actualSort # Set new sorting mode self.actualSort = nextSort if resetlist: self.list = [] else: tmplist = self.list + tmplist self.list = self.doListSort(tmplist) return self.list
def __readCutFile(self, path): from MovieCache import MovieCache, IDX_CUTS if path: #print("MVC: CutList: __readCutFile: reading cut_list from cache: " + os.path.splitext(path)[0]) filedata = MovieCache.getInstance().getFile(os.path.splitext(path)[0]) data = filedata[IDX_CUTS] cut_list = unpackCutList(data) #print("MVC: CutList: __readCutFile: cut_list: " + str(cut_list)) else: cut_list = [] #print("MVC: CutList: __readCutFile: no path specified") return cut_list
def __writeCutFile(self, path, cut_list): from MovieCache import MovieCache #print("MVC: CutList: __writeCutFile: %s, cut_list: %s" % (path, cut_list)) if path: data = packCutList(cut_list) writeCutsFile(path, data) # update file in cache #print("MVC: CutList: __writeCutFile: cut_list: " + str(cut_list)) #print("MVC: CutList: __writeCutFile: updating cut_list in cache: " + os.path.splitext(path)[0]) MovieCache.getInstance().update(os.path.splitext(path)[0], pcuts=data) # [Cutlist.Workaround] # Always make a backup-copy when recording, it will be merged with enigma-cutfile after recording if DO_CUTLIST_WORKAROUND: ts_path, __ = os.path.splitext(path) from RecordingsControl import RecordingsControl recording = RecordingsControl.getRecording(ts_path, True) if recording: path += ".save" #print("MVC: CutList: __writeCutFile: creating backup file: " + path) writeCutsFile(path, data)
def purgeTrashcan(self, empty_trash=False): print("MVC: Trashcan: purge: empty_trash: %s" % (empty_trash)) now = localtime() if not self.trashcanExists: self.createTrashcan() if os.path.realpath( config.MVC.movie_trashcan_path.value) in os.path.realpath( config.MVC.movie_homepath.value): config.MVC.movie_trashcan_enable.value = False AddPopup( _("Skipping trashcan cleanup") + "\n" + _("Movie Home path is equal to or a subfolder of the trashcan" ), MessageBox.TYPE_INFO, 0, "MVC_TRASHCAN_CLEANUP_SKIPPED_ID") return delete_list = [] filelist = MovieCache.getInstance().getFileList( [config.MVC.movie_trashcan_path.value]) for afile in filelist: service = afile[MOVIE_IDX_SERVICE] path = service.getPath() # Only check media files ext = os.path.splitext(path)[1] if ext in extMedia and os.path.exists(path): if empty_trash or now > localtime( os.stat(path).st_mtime + 24 * 60 * 60 * int(config.MVC.movie_trashcan_limit.value)): print("MVC: Trashcan: purge: path: " + path) delete_list.append(service) if len(delete_list) > 0: print("MVC: Trashcan: deleting files...") self.execFileOp("delete", delete_list) else: print("MVC: Trashcan: purge: nothing to delete")
def MVCShutdown(): print("MVC: plugin: ---") print("MVC: plugin: --- MVC: Shutdown") print("MVC: plugin: ---") MovieCache.getInstance().close()
def execFileOp(self, op, selection_list, target_path=None): def changeOwner(c, service, target_path): if self.mountpoint(target_path) != self.mountpoint(config.MVC.movie_homepath.value): # CIFS to HDD is ok! # need to change file ownership to match target filesystem file creation tfile = "\"" + target_path + "/owner_test" + "\"" path = service.getPath().replace("'", "\'") sfile = "\"" + path + ".\"*" c.append("touch %s;ls -l %s | while read flags i owner group crap;do chown $owner:$group %s;done;rm %s" % (tfile, tfile, sfile, tfile)) return c self.returnService = self.getNextSelectedService(self.getCurrent(), selection_list) if self.returnService: print("MVC: FileOps: execFileOp: returnService: " + str(self.returnService.toString())) else: print("MVC: FileOps: execFileOp: op: %s" % (op)) print("MVC: FileOps: execFileOp: target_path: " + target_path) print("MVC: FileOps: execFileOp: selection_list: %s" % (selection_list)) cmd = [] association = [] source_path = None dest_path = None delete_ops = ["delete", "delete_dir", "delete_link"] move_ops = ["move", "move_dir", "move_link"] if target_path: target_path = os.path.normpath(target_path) for service in selection_list: if service.getPath(): c = [] if op in delete_ops: file_type = ["file", "dir", "link"][delete_ops.index(op)] # direct delete from the trashcan or network mount (no copy to trashcan from different mountpoint) print("MVC: FileOps: execFileOp: delete: directDelete") c, source_path, dest_path = self.execFileOpDelete(c, service.getPath(), file_type) cmd.append(c) self["list"].highlightService(True, "del", service) if config.MVC.movie_hide_del.value: self.removeService(service) self.setReturnCursor() association.append((self.deleteCallback, service)) elif op in move_ops: file_type = ["file", "dir", "link"][move_ops.index(op)] if os.path.dirname(service.getPath()) != target_path: free = 0 size = 0 if file_type != "file": _count, size = MovieCache.getInstance().getCountSize(service.getPath()) free = self.getMountPointSpaceFree(target_path) print("MVC: FileOps: move_dir: size: %s, free: %s" % (size, free)) if free >= size: c = changeOwner(c, service, target_path) c, source_path, dest_path = self.execFileOpMove(c, service.getPath(), target_path, file_type) cmd.append(c) association.append((self.moveCallback, service)) self["list"].highlightService(True, "move", service) if config.MVC.movie_hide_mov.value: self.removeService(service) self.setReturnCursor() if file_type == "file": self.moveTimerPath(service, target_path) else: print("MVC: FileOps: move_dir: not enough space left: size: %s, free: %s" % (size, free)) elif op == "copy": if os.path.dirname(service.getPath()) != target_path: c = changeOwner(c, service, target_path) c, source_path, dest_path = self.execFileOpCopy(c, service.getPath(), target_path) cmd.append(c) association.append((self.copyCallback, service)) # put in a callback for this particular movie self["list"].highlightService(True, "copy", service) if cmd: print("MVC: FileOps: execFileOp: cmd: %s" % cmd) association.append((self.initCursor, False)) # Set new Cursor position association.append((self.postFileOp, source_path, dest_path)) # Sync = True: Run script for one file do association and continue with next file mvcTasker.shellExecute(cmd, association, True) # first move, then delete if expiration limit is 0 self["list"].resetSelection() self.getMountPointsSpaceUsedPercent()
def __init__(self, service): self.path = service and service.getPath() _dirname, filetype, _path, _filename, _ext, name, date, length, description, extended_description, service_reference, size, cuts, tags = MovieCache.getInstance().getFile(self.path) self.__filetype = filetype self.__date = str2date(date) self.__name = name self.__eventname = name self.__mtime = int(mktime(self.__date.timetuple())) self.__shortdescription = description self.__extendeddescription = extended_description self.__length = length self.__rec_ref_str = service_reference self.__size = size self.__tags = tags self.__cut_list = unpackCutList(cuts) self.__id = 0
def createDirList(self, path): filelist = MovieCache.getInstance().getFileList([path]) subdirlist = MovieCache.getInstance().getDirList([path]) return subdirlist, filelist
def reloadCutListFromFile(self): from MovieCache import MovieCache data = readCutsFile(self.cut_file) MovieCache.getInstance().update(os.path.splitext(self.cut_file)[0], pcuts=data) self.cut_list = verifyCutList(unpackCutList(data)) return self.cut_list
def reloadListWithoutCache(self): # reload files and directories for current path without using cache MovieCache.getInstance().reloadDatabase() self.reloadList(self.current_path)
def deleteFileCutList(self): from MovieCache import MovieCache data = "" MovieCache.getInstance().update(os.path.splitext(self.cut_file)[0], pcuts=data) deleteCutsFile(self.cut_file)