xbmcbackup/resources/lib/vfs.py

292 lines
8.0 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-11-25 22:48:42 +01:00
import xbmc
import xbmcvfs
import xbmcgui
from dropbox 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
2019-11-25 22:56:59 +01:00
class Vfs:
root_path = None
2019-11-25 22:45:41 +01:00
def __init__(self, rootString):
self.set_root(rootString)
2019-11-25 22:33:34 +01:00
def clean_path(self, path):
2019-11-25 22:19:57 +01:00
# fix slashes
path = path.replace("\\", "/")
2019-12-30 17:17:58 +01:00
2019-11-25 22:19:57 +01:00
# check if trailing slash is included
if(path[-1:] != '/'):
path = path + '/'
2019-12-30 17:17:58 +01:00
return path
def set_root(self, rootString):
old_root = self.root_path
self.root_path = self.clean_path(rootString)
2012-11-05 18:13:48 +01:00
2019-11-25 22:19:57 +01:00
# return the old root
2012-11-05 18:13:48 +01:00
return old_root
2019-11-25 22:33:34 +01:00
2019-11-25 22:45:41 +01:00
def listdir(self, directory):
return {}
2019-11-25 22:45:41 +01:00
def mkdir(self, directory):
return True
2019-11-25 22:45:41 +01:00
def put(self, source, dest):
return True
2012-11-02 21:59:40 +01:00
2019-11-25 22:45:41 +01:00
def rmdir(self, directory):
2012-11-02 21:59:40 +01:00
return True
2019-11-25 22:45:41 +01:00
def rmfile(self, aFile):
2014-08-01 20:12:43 +02:00
return True
2019-11-25 22:45:41 +01:00
def exists(self, aFile):
2012-11-02 21:59:40 +01:00
return True
2019-11-25 22:33:34 +01:00
2019-11-25 22:45:41 +01:00
def rename(self, aFile, newName):
return True
2019-11-25 22:33:34 +01:00
def cleanup(self):
return True
2019-11-25 22:33:34 +01:00
def fileSize(self, filename):
return 0 # result should be in KB
2019-11-25 22:56:59 +01:00
2012-11-02 21:59:40 +01:00
class XBMCFileSystem(Vfs):
2019-11-25 22:45:41 +01:00
def listdir(self, directory):
2012-11-02 21:59:40 +01:00
return xbmcvfs.listdir(directory)
2019-11-25 22:45:41 +01:00
def mkdir(self, directory):
return xbmcvfs.mkdir(xbmc.translatePath(directory))
2012-11-02 21:59:40 +01:00
2019-11-25 22:45:41 +01:00
def put(self, source, dest):
return xbmcvfs.copy(xbmc.translatePath(source), xbmc.translatePath(dest))
2019-11-25 22:33:34 +01:00
2019-11-25 22:45:41 +01:00
def rmdir(self, directory):
return xbmcvfs.rmdir(directory, True)
2012-11-02 21:59:40 +01:00
2019-11-25 22:45:41 +01:00
def rmfile(self, aFile):
2014-08-01 20:12:43 +02:00
return xbmcvfs.delete(aFile)
2019-11-25 22:45:41 +01:00
def rename(self, aFile, newName):
return xbmcvfs.rename(aFile, newName)
2019-11-25 22:45:41 +01:00
def exists(self, aFile):
2012-11-02 21:59:40 +01:00
return xbmcvfs.exists(aFile)
def fileSize(self, filename):
f = xbmcvfs.File(filename)
result = f.size() / 1024 # bytes to kilobytes
f.close()
return result
2019-11-25 22:56:59 +01:00
class ZipFileSystem(Vfs):
zip = None
2019-11-25 22:33:34 +01:00
2019-11-25 22:45:41 +01:00
def __init__(self, rootString, mode):
self.root_path = ""
2019-11-25 22:45:41 +01:00
self.zip = zipfile.ZipFile(rootString, mode=mode, compression=zipfile.ZIP_DEFLATED, allowZip64=True)
2019-11-25 22:33:34 +01:00
2019-11-25 22:45:41 +01:00
def listdir(self, directory):
return [[], []]
2019-11-25 22:33:34 +01:00
2019-11-25 22:45:41 +01:00
def mkdir(self, directory):
2019-11-25 22:19:57 +01:00
# self.zip.write(directory[len(self.root_path):])
2014-08-01 19:57:55 +02:00
return False
2019-11-25 22:33:34 +01:00
2019-11-25 22:45:41 +01:00
def put(self, source, dest):
2019-11-25 22:33:34 +01:00
2019-11-25 22:45:41 +01:00
aFile = xbmcvfs.File(xbmc.translatePath(source), 'r')
2019-11-25 22:33:34 +01:00
2019-11-25 22:45:41 +01:00
self.zip.writestr(dest, aFile.readBytes())
2019-11-25 22:33:34 +01:00
return True
2019-11-25 22:33:34 +01:00
2019-11-25 22:45:41 +01:00
def rmdir(self, directory):
2014-08-01 19:57:55 +02:00
return False
2019-11-25 22:33:34 +01:00
2019-11-25 22:45:41 +01:00
def exists(self, aFile):
2014-08-01 19:57:55 +02:00
return False
2019-11-25 22:33:34 +01:00
def cleanup(self):
self.zip.close()
2019-11-25 22:33:34 +01:00
2019-11-25 22:45:41 +01:00
def extract(self, aFile, path):
2019-11-25 22:19:57 +01:00
# extract zip file to path
2019-11-25 22:45:41 +01:00
self.zip.extract(aFile, path)
2019-11-25 22:33:34 +01:00
def listFiles(self):
return self.zip.infolist()
2019-11-25 22:56:59 +01:00
class DropboxFileSystem(Vfs):
2019-11-25 22:56:59 +01:00
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 = ''
2019-11-25 22:33:34 +01:00
2019-11-25 22:45:41 +01:00
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:
2019-11-25 22:19:57 +01:00
# tell the user to go back and run the authorizer
2019-11-25 22:45:41 +01:00
xbmcgui.Dialog().ok(utils.getString(30010), utils.getString(30105))
sys.exit()
2019-11-25 22:45:41 +01:00
def listdir(self, directory):
directory = self._fix_slashes(directory)
2019-11-25 22:33:34 +01:00
2019-11-25 22:56:59 +01:00
if(self.client is not None and self.exists(directory)):
files = []
dirs = []
metadata = self.client.files_list_folder(directory)
for aFile in metadata.entries:
2019-11-25 22:45:41 +01:00
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)
2019-11-25 22:45:41 +01:00
return [dirs, files]
else:
2019-11-25 22:45:41 +01:00
return [[], []]
2019-11-25 22:45:41 +01:00
def mkdir(self, directory):
2013-03-04 17:22:09 +01:00
directory = self._fix_slashes(directory)
2019-11-25 22:56:59 +01:00
if(self.client is not None):
2019-11-25 22:19:57 +01:00
# sort of odd but always return true, folder create is implicit with file upload
return True
else:
return False
2019-11-25 22:45:41 +01:00
def rmdir(self, directory):
2013-03-04 17:22:09 +01:00
directory = self._fix_slashes(directory)
2019-11-25 22:56:59 +01:00
if(self.client is not None and self.exists(directory)):
2019-11-25 22:19:57 +01:00
# dropbox is stupid and will refuse to do this sometimes, need to delete recursively
2019-11-25 22:45:41 +01:00
dirs, files = self.listdir(directory)
2019-11-25 22:33:34 +01:00
2014-07-29 15:43:34 +02:00
for aDir in dirs:
self.rmdir(aDir)
2019-11-25 22:19:57 +01:00
# finally remove the root directory
self.client.files_delete(directory)
2019-11-25 22:33:34 +01:00
2014-08-01 20:12:43 +02:00
return True
else:
return False
2019-11-25 22:45:41 +01:00
def rmfile(self, aFile):
2014-08-01 20:12:43 +02:00
aFile = self._fix_slashes(aFile)
2019-11-25 22:33:34 +01:00
2019-11-25 22:56:59 +01:00
if(self.client is not None and self.exists(aFile)):
self.client.files_delete(aFile)
2014-08-01 20:12:43 +02:00
return True
else:
return False
2019-11-25 22:45:41 +01:00
def exists(self, aFile):
2013-03-04 17:22:09 +01:00
aFile = self._fix_slashes(aFile)
2019-11-25 22:33:34 +01:00
2019-11-25 22:56:59 +01:00
if(self.client is not None):
2019-11-25 22:19:57 +01:00
# can't list root metadata
if(aFile == ''):
return True
2019-11-25 22:33:34 +01:00
try:
2019-11-25 22:56:59 +01:00
self.client.files_get_metadata(aFile)
2019-11-25 22:19:57 +01:00
# if we make it here the file does exist
return True
except:
return False
else:
return False
2019-11-25 22:45:41 +01:00
def put(self, source, dest, retry=True):
2013-03-04 17:22:09 +01:00
dest = self._fix_slashes(dest)
2019-11-25 22:33:34 +01:00
2019-11-25 22:56:59 +01:00
if(self.client is not None):
2019-11-25 22:19:57 +01:00
# open the file and get its size
2019-11-25 22:45:41 +01:00
f = open(source, 'rb')
f_size = os.path.getsize(source)
2019-11-25 22:33:34 +01:00
try:
if(f_size < self.MAX_CHUNK):
2019-11-25 22:19:57 +01:00
# use the regular upload
2019-11-25 22:56:59 +01:00
self.client.files_upload(f.read(), dest, mode=WriteMode('overwrite'))
else:
2019-11-25 22:19:57 +01:00
# start the upload session
upload_session = self.client.files_upload_session_start(f.read(self.MAX_CHUNK))
2019-11-25 22:45:41 +01:00
upload_cursor = UploadSessionCursor(upload_session.session_id, f.tell())
2019-11-25 22:33:34 +01:00
while(f.tell() < f_size):
2019-11-25 22:19:57 +01:00
# check if we should finish the upload
if((f_size - f.tell()) <= self.MAX_CHUNK):
2019-11-25 22:19:57 +01:00
# upload and close
2019-11-25 22:45:41 +01:00
self.client.files_upload_session_finish(f.read(self.MAX_CHUNK), upload_cursor, CommitInfo(dest, mode=WriteMode('overwrite')))
else:
2019-11-25 22:19:57 +01:00
# upload a part and store the offset
2019-11-25 22:45:41 +01:00
self.client.files_upload_session_append_v2(f.read(self.MAX_CHUNK), upload_cursor)
upload_cursor.offset = f.tell()
2019-11-25 22:33:34 +01:00
2019-11-25 22:56:59 +01:00
# if no errors we're good!
return True
except Exception as anError:
utils.log(str(anError))
2019-11-25 22:33:34 +01:00
2019-11-25 22:19:57 +01:00
# if we have an exception retry
if(retry):
2019-11-25 22:45:41 +01:00
return self.put(source, dest, False)
else:
2019-11-25 22:19:57 +01:00
# tried once already, just quit
return False
else:
return False
2012-11-06 18:37:39 +01:00
def fileSize(self, filename):
result = 0
aFile = self._fix_slashes(filename)
if(self.client is not None):
metadata = self.client.files_get_metadata(aFile)
result = metadata.size / 1024 # bytes to KB
return result
2019-11-25 22:45:41 +01:00
def get_file(self, source, dest):
2019-11-25 22:56:59 +01:00
if(self.client is not None):
2019-11-25 22:19:57 +01:00
# write the file locally
2019-11-25 22:56:59 +01:00
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
2019-11-25 22:45:41 +01:00
def _fix_slashes(self, filename):
result = filename.replace('\\', '/')
2019-11-25 22:19:57 +01:00
# root needs to be a blank string
if(result == '/'):
result = ""
2019-11-25 22:19:57 +01:00
# if dir ends in slash, remove it
if(result[-1:] == "/"):
result = result[:-1]
return result