diff --git a/plugins/FilePack/FilePackPlugin.py b/plugins/FilePack/FilePackPlugin.py new file mode 100644 index 00000000..dfaf68ad --- /dev/null +++ b/plugins/FilePack/FilePackPlugin.py @@ -0,0 +1,87 @@ +import time +import json +import os +import re + +from Plugin import PluginManager +from Translate import Translate +from Config import config +from util import helper + + +# Keep archive open for faster reponse times for large sites +archive_cache = {} +def closeArchive(archive_path): + if archive_path in archive_cache: + archive_cache[archive_path].close() + del archive_cache[archive_path] + +def openArchive(archive_path, path_within): + if archive_path not in archive_cache: + if archive_path.endswith("tar.gz"): + import tarfile + archive_cache[archive_path] = tarfile.open(archive_path, "r:gz") + elif archive_path.endswith("tar.bz2"): + import tarfile + archive_cache[archive_path] = tarfile.open(archive_path, "r:bz2") + else: + import zipfile + archive_cache[archive_path] = zipfile.ZipFile(archive_path) + helper.timer(5, lambda: closeArchive(archive_path)) # Close after 5 sec + + archive = archive_cache[archive_path] + + if archive_path.endswith(".zip"): + return archive.open(path_within) + else: + return archive.extractfile(path_within) + + +@PluginManager.registerTo("UiRequest") +class UiRequestPlugin(object): # 1.87 + def actionSiteMedia(self, path, header_length=True): + if ".zip/" in path or ".tar.gz/" in path or ".tar.bz2/" in path: + path_parts = self.parsePath(path) + file_path = "%s/%s/%s" % (config.data_dir, path_parts["address"], path_parts["inner_path"]) + match = re.match("^(.*\.(?:tar.gz|tar.bz2|zip))/(.*)", file_path) + archive_path, path_within = match.groups() + if not os.path.isfile(archive_path): + site = self.server.site_manager.get(path_parts["address"]) + if not site: + self.error404(path) + result = site.needFile(site.storage.getInnerPath(archive_path), priority=5) # Wait until file downloads + if not result: + return self.error404(path) + try: + file = openArchive(archive_path, path_within) + content_type = self.getContentType(file_path) + self.sendHeader(200, content_type=content_type) + return self.streamFile(file) + except Exception, err: + self.log.debug("Error opening archive file: %s" % err) + return self.error404(path) + + return super(UiRequestPlugin, self).actionSiteMedia(path, header_length=header_length) + + def streamFile(self, file): + while 1: + try: + block = file.read(60 * 1024) + if block: + yield block + else: + raise StopIteration + except StopIteration: + file.close() + break + + +@PluginManager.registerTo("SiteStorage") +class SiteStoragePlugin(object): + def isFile(self, inner_path): + if ".zip/" in inner_path or ".tar.gz/" in inner_path or ".tar.bz2/" in inner_path: + match = re.match("^(.*\.(?:tar.gz|tar.bz2|zip))/(.*)", inner_path) + inner_archive_path, path_within = match.groups() + return super(SiteStoragePlugin, self).isFile(inner_archive_path) + else: + return super(SiteStoragePlugin, self).isFile(inner_path) diff --git a/plugins/FilePack/__init__.py b/plugins/FilePack/__init__.py new file mode 100644 index 00000000..ab07a1ff --- /dev/null +++ b/plugins/FilePack/__init__.py @@ -0,0 +1 @@ +import FilePackPlugin \ No newline at end of file