xbmcbackup/resources/lib/vfs.py

264 lines
7.6 KiB
Python
Raw Normal View History

2019-08-28 22:37:56 +02:00
from __future__ import unicode_literals
import zipfile
import os.path
import sys
2019-08-27 22:01:24 +02:00
from kodi_six import xbmc, xbmcvfs, xbmcgui
import dropbox
2019-08-27 21:55:22 +02:00
from . import utils as utils
from dropbox.files import WriteMode,CommitInfo,UploadSessionCursor
from . authorizers import DropboxAuthorizer
class Vfs:
root_path = None
def __init__(self,rootString):
self.set_root(rootString)
def set_root(self,rootString):
2012-11-05 18:13:48 +01:00
old_root = self.root_path
self.root_path = rootString
2014-08-01 00:29:59 +02:00
#fix slashes
self.root_path = self.root_path.replace("\\","/")
#check if trailing slash is included
if(self.root_path[-1:] != "/"):
self.root_path = self.root_path + "/"
2012-11-05 18:13:48 +01:00
#return the old root
return old_root
def listdir(self,directory):
return {}
def mkdir(self,directory):
return True
2012-11-06 18:37:39 +01:00
def put(self,source,dest):
return True
2012-11-02 21:59:40 +01:00
def rmdir(self,directory):
2012-11-02 21:59:40 +01:00
return True
2014-08-01 20:12:43 +02:00
def rmfile(self,aFile):
return True
def exists(self,aFile):
2012-11-02 21:59:40 +01:00
return True
def rename(self,aFile,newName):
return True
def cleanup(self):
return True
2012-11-02 21:59:40 +01:00
class XBMCFileSystem(Vfs):
def listdir(self,directory):
2012-11-02 21:59:40 +01:00
return xbmcvfs.listdir(directory)
def mkdir(self,directory):
return xbmcvfs.mkdir(xbmc.translatePath(directory))
2012-11-02 21:59:40 +01:00
2012-11-06 18:37:39 +01:00
def put(self,source,dest):
return xbmcvfs.copy(xbmc.translatePath(source),xbmc.translatePath(dest))
2012-11-06 18:37:39 +01:00
def rmdir(self,directory):
2012-11-02 21:59:40 +01:00
return xbmcvfs.rmdir(directory,True)
2014-08-01 20:12:43 +02:00
def rmfile(self,aFile):
return xbmcvfs.delete(aFile)
def rename(self,aFile,newName):
return xbmcvfs.rename(aFile, newName)
def exists(self,aFile):
2012-11-02 21:59:40 +01:00
return xbmcvfs.exists(aFile)
class ZipFileSystem(Vfs):
zip = None
def __init__(self,rootString,mode):
self.root_path = ""
self.zip = zipfile.ZipFile(rootString,mode=mode,compression=zipfile.ZIP_DEFLATED,allowZip64=True)
def listdir(self,directory):
2014-08-01 19:57:55 +02:00
return [[],[]]
def mkdir(self,directory):
#self.zip.write(directory[len(self.root_path):])
2014-08-01 19:57:55 +02:00
return False
def put(self,source,dest):
aFile = xbmcvfs.File(xbmc.translatePath(source),'r')
2019-08-28 22:37:56 +02:00
self.zip.writestr(dest,aFile.readBytes())
return True
def rmdir(self,directory):
2014-08-01 19:57:55 +02:00
return False
def exists(self,aFile):
2014-08-01 19:57:55 +02:00
return False
def cleanup(self):
self.zip.close()
2014-08-01 19:57:55 +02:00
def extract(self,aFile,path):
2014-08-01 19:57:55 +02:00
#extract zip file to path
self.zip.extract(aFile,path)
def listFiles(self):
return self.zip.infolist()
class DropboxFileSystem(Vfs):
MAX_CHUNK = 50 * 1000 * 1000 #dropbox uses 150, reduced to 50 for small mem systems
client = None
2014-10-09 21:30:39 +02:00
APP_KEY = ''
APP_SECRET = ''
def __init__(self,rootString):
2013-03-04 17:22:09 +01:00
self.set_root(rootString)
authorizer = DropboxAuthorizer()
if(authorizer.isAuthorized()):
self.client = authorizer.getClient()
else:
#tell the user to go back and run the authorizer
2017-01-31 15:16:54 +01:00
xbmcgui.Dialog().ok(utils.getString(30010),utils.getString(30105))
sys.exit()
def listdir(self,directory):
directory = self._fix_slashes(directory)
if(self.client != None and self.exists(directory)):
files = []
dirs = []
metadata = self.client.files_list_folder(directory)
for aFile in metadata.entries:
if(isinstance(aFile,dropbox.files.FolderMetadata)):
2019-08-28 22:37:56 +02:00
dirs.append(aFile.name)
else:
2019-08-28 22:37:56 +02:00
files.append(aFile.name)
return [dirs,files]
else:
return [[],[]]
def mkdir(self,directory):
2013-03-04 17:22:09 +01:00
directory = self._fix_slashes(directory)
if(self.client != None):
#sort of odd but always return true, folder create is implicit with file upload
return True
else:
return False
def rmdir(self,directory):
2013-03-04 17:22:09 +01:00
directory = self._fix_slashes(directory)
if(self.client != None and self.exists(directory)):
2014-07-29 15:43:34 +02:00
#dropbox is stupid and will refuse to do this sometimes, need to delete recursively
dirs,files = self.listdir(directory)
for aDir in dirs:
self.rmdir(aDir)
#finally remove the root directory
self.client.files_delete(directory)
2014-08-01 20:12:43 +02:00
return True
else:
return False
2014-11-21 20:30:22 +01:00
def rmfile(self,aFile):
2014-08-01 20:12:43 +02:00
aFile = self._fix_slashes(aFile)
2014-11-21 20:30:22 +01:00
2014-08-01 20:12:43 +02:00
if(self.client != None and self.exists(aFile)):
self.client.files_delete(aFile)
2014-08-01 20:12:43 +02:00
return True
else:
return False
def exists(self,aFile):
2013-03-04 17:22:09 +01:00
aFile = self._fix_slashes(aFile)
2017-12-27 17:06:07 +01:00
if(self.client != None):
#can't list root metadata
if(aFile == ''):
return True
try:
meta_data = self.client.files_get_metadata(aFile)
#if we make it here the file does exist
return True
except:
return False
else:
return False
def put(self,source,dest,retry=True):
2013-03-04 17:22:09 +01:00
dest = self._fix_slashes(dest)
if(self.client != None):
#open the file and get its size
f = open(source,'rb')
f_size = os.path.getsize(source)
try:
if(f_size < self.MAX_CHUNK):
#use the regular upload
response = self.client.files_upload(f.read(),dest,mode=WriteMode('overwrite'))
else:
#start the upload session
upload_session = self.client.files_upload_session_start(f.read(self.MAX_CHUNK))
upload_cursor = UploadSessionCursor(upload_session.session_id,f.tell())
while(f.tell() < f_size):
#check if we should finish the upload
if((f_size - f.tell()) <= self.MAX_CHUNK):
#upload and close
self.client.files_upload_session_finish(f.read(self.MAX_CHUNK),upload_cursor,CommitInfo(dest,mode=WriteMode('overwrite')))
else:
#upload a part and store the offset
self.client.files_upload_session_append_v2(f.read(self.MAX_CHUNK),upload_cursor)
upload_cursor.offset = f.tell()
Update for Leia (#117) * updated addon.xml for Krypton * default log level is always debug now * added screenshots per krypton format * started new way of defining backup directories * reconfigured simple backup process * added an advanced backup editor and combined settings.xml scripts into a launcher * added strings for advanced editor * there was a function to do this * match excluded with regex * updated def for the addons set * directory has to end in slash to use exists() * added a backup set chooser on restore * added string for restore browser * utilize details to show root folder and icons * save non translated paths, better cross platform support * revert dropbox python 2.6 changes * start of #132 * can't have duplicate ids * updated strings * closes #132 * added a disclaimer for breaking changes * split backup and restore into separate functions * updated scripting to pass in list of sets to restore * beta version * added 2 min delay in startup - part of #147 * forgot to remove debug message * change to wait for abort in case someone tries to close Kodi * add retroplayer game saves to default file list * display restore points with most recent on top * remove length check, breaking change with this version means old archives are no longer compatible * format restore list according to regional settings * this function isn't used anymore, legacy of old file manager * use images folder as default * added note about compatibility * added utils function for regional date, use for scheduler notifications as well * add/remove include and exclude directories to a set * paths should have / at the end * show path relative to root * if in advanced mode allow jumping to editor from launch screen * check that path is within root folder of set * cannot have duplicate set names or rules regarding folders within a set * put strings in correct lang file * beta version bump * accidentally deleted string id * change exclude criteria. Regex was not matching in complex cases * make sure the dest folder (backup set root) exists before writing to it * modify select display to show recursive value for included folders * use a context menu here * added ability to toggle recursion of sub folders * beta 3 * added support doc * wrong branch * don't need this import anymore * don't need these imports * part of #133
2019-08-26 22:40:15 +02:00
#if no errors we're good!
return True
except Exception as anError:
utils.log(str(anError))
#if we have an exception retry
if(retry):
return self.put(source,dest,False)
else:
#tried once already, just quit
return False
else:
return False
2012-11-06 18:37:39 +01:00
def get_file(self,source,dest):
if(self.client != None):
#write the file locally
f = self.client.files_download_to_file(dest,source)
return True
2012-11-06 18:37:39 +01:00
else:
return False
2013-03-04 17:22:09 +01:00
def _fix_slashes(self,filename):
result = filename.replace('\\','/')
#root needs to be a blank string
if(result == '/'):
result = ""
#if dir ends in slash, remove it
if(result[-1:] == "/"):
result = result[:-1]
return result