@@ -20,32 +20,37 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import os
+from threading import Lock
+from cStringIO import StringIO
class ConcatenatedFileReader:
def __init__(self, filenames):
self.files = [(f, os.path.getsize(f)) for f in filenames]
self.current_filename = None
self.current_file = None
+ self.rwlock = Lock()
def read(self, offset, size):
- buffer = ""
+ buffer = StringIO()
ptr = offset
- while (len(buffer) < size):
- (filename, file_offset) = self.filename_from_offset(ptr)
- if filename:
- if (self.current_filename != filename):
- if self.current_file:
- self.current_file.close()
- self.current_filename = filename
- self.current_file = open(filename, 'r')
- self.current_file.seek(file_offset)
- buffer += self.current_file.read(size - len(buffer))
- ptr = offset + len(buffer)
- else:
- break
- return buffer
+ with self.rwlock:
+ while (buffer.tell() < size):
+ (filename, file_offset) = self.filename_from_offset(ptr)
+ if filename:
+ if (self.current_filename != filename):
+ if self.current_file:
+ self.current_file.close()
+ self.current_filename = filename
+ self.current_file = open(filename, 'r')
+ self.current_file.seek(file_offset)
+ buffer.write(self.current_file.read(size - buffer.tell()))
+ ptr = offset + buffer.tell()
+ else:
+ break
+ return buffer.getvalue()
- def release(self):
+ def __del__(self):
+ # print "CFR::DEL"
if self.current_file:
self.current_file.close()
Only in vdrnfofs-0.6.tyger1//vdrnfofs: concatenated_file_reader.py~
@@ -26,6 +26,7 @@
from concatenated_file_reader import *
from vdr import *
+from threading import Lock
class NodeAttributes(fuse.Stat):
def __init__(self):
@@ -40,40 +41,90 @@
self.st_mtime = 0
self.st_ctime = 0
+
class MpgNode:
+ cachesize = 20
+ cachelock = Lock()
+ cache = []
+
+ @classmethod
+ def create(cls, path, cache):
+ if not cache:
+ return cls(path)
+ with cls.cachelock:
+ index = next((i for i in xrange(len(cls.cache)-1, -1, -1) if cls.cache[i].key == path), None)
+ if index is not None:
+ # print "%s HIT" % cls.__name__
+ node = cls.cache.pop(index)
+ else:
+ # print "%s MISS" % cls.__name__
+ node = cls(path)
+ if len(cls.cache) > cls.cachesize:
+ del cls.cache[0]
+ cls.cache.append(node)
+ # print "%s cache size: %d" %(cls.__name__, len(cls.cache))
+ return node
+
def __init__(self, path):
+ # print "MpgNode::init %s" % path
+ self.key = path
self.path = os.path.normpath(path)
self.mpeg_files = glob.glob(path + '/[0-9]*.vdr')
if not self.mpeg_files:
self.mpeg_files = glob.glob(path + '/[0-9]*.ts')
self.mpeg_files.sort()
- self.file_system_name = os.path.basename(os.path.abspath(path + '/..')) + '_' + os.path.basename(path) + '.mpg'
+ self.file_system_name ="%s_%s.mpg" % (os.path.basename(os.path.abspath(path + '/..')), os.path.basename(path))
self.reader = ConcatenatedFileReader(self.mpeg_files)
-
- def size(self):
size = 0
for file in self.mpeg_files:
size += os.path.getsize(file)
- return size
+ self.filesize = size
- def read(self, offset, size):
- return self.reader.read(offset, size)
+ def size(self):
+ # print "MpgNode::size"
+ return self.filesize
- def release(self):
- return self.reader.release()
+ def read(self, offset, size):
+ # print "MpgNode::read %d" % offset
+ return self.reader.read(offset, size)
def get_stat(self):
+ # print "MpgNode::get_stat"
attr = NodeAttributes()
- attr.st_mode = stat.S_IFREG | 644
+ attr.st_mode = stat.S_IFREG | 0444
attr.st_nlink = 1
- attr.st_size = self.size()
+ attr.st_size = self.filesize
return attr
class NfoNode:
+ cachesize = 20
+ cachelock = Lock()
+ cache = []
+
+ @classmethod
+ def create(cls, path, cache):
+ if not cache:
+ return cls(path)
+ with cls.cachelock:
+ index = next((i for i in xrange(len(cls.cache)-1, -1, -1) if cls.cache[i].key == path), None)
+ if index is not None:
+ # print "%s HIT" % cls.__name__
+ node = cls.cache.pop(index)
+ else:
+ # print "%s MISS" % cls.__name__
+ node = cls(path)
+ if len(cls.cache) > cls.cachesize:
+ del cls.cache[0]
+ cls.cache.append(node)
+ # print "%s cache size: %d" %(cls.__name__, len(cls.cache))
+ return node
+
def __init__(self, path):
+ # print "NfoNode::init %s" % path
+ self.key = path
self.path = os.path.normpath(path)
- self.file_system_name = os.path.basename(os.path.abspath(path + '/..')) + '_' + os.path.basename(path) + '.nfo'
+ self.file_system_name ="%s_%s.nfo" % (os.path.basename(os.path.abspath(path + '/..')), os.path.basename(path))
if os.path.exists(path + '/info.vdr'):
info_vdr = InfoVdr(path + '/info.vdr')
elif os.path.exists(path + '/info'):
@@ -86,39 +137,75 @@
<plot>%s</plot>
</movie>
""" % (info_vdr['T'], info_vdr['D'])
+ self.contentsize = len(self.nfo_content)
def size(self):
- return len(self.nfo_content)
+ return self.contentsize
def read(self, offset, size):
+ # print "NfoNode::read %s" % offset
return self.nfo_content[offset:offset+size]
def get_stat(self):
+ # print "NfoNode::get_stat"
attr = NodeAttributes()
- attr.st_mode = stat.S_IFREG | 644
+ attr.st_mode = stat.S_IFREG | 0444
attr.st_nlink = 1
- attr.st_size = self.size()
+ attr.st_size = self.contentsize
return attr
class DirNode:
+ cachesize = 100
+ cachelock = Lock()
+ cache = []
+
+ @classmethod
+ def create(cls, path, cache):
+ if not cache:
+ return cls(path)
+ with cls.cachelock:
+ index = next((i for i in xrange(len(cls.cache)-1, -1, -1) if cls.cache[i].key == path), None)
+ if index is not None:
+ # print "%s HIT" % cls.__name__
+ node = cls.cache.pop(index)
+ else:
+ # print "%s MISS" % cls.__name__
+ node = cls(path)
+ if len(cls.cache) > cls.cachesize:
+ del cls.cache[0]
+ cls.cache.append(node)
+ # print "%s cache size: %d" %(cls.__name__, len(cls.cache))
+ return node
+
def __init__(self, path):
+ # print "DirNode::init %s" % path
+ self.key = path
self.path = os.path.normpath(path)
self.file_system_name = os.path.basename(path)
self.cache = []
+ self.mysize = None
def content(self):
+ # print "DirNode::content %s" % self.path
if not self.cache:
+ # print "without cache"
for entry in os.listdir(self.path):
- entry = self.path + '/' + entry
+ entry = "/".join((self.path, entry))
if self.is_sub_folder(entry):
- self.cache.append(DirNode(entry))
+ self.cache.append(DirNode.create(entry, True))
for recording in glob.glob(entry + '/*.rec'):
if os.path.exists(recording + '/info.vdr') or os.path.exists(recording + '/info'):
- self.cache.append(MpgNode(recording))
- self.cache.append(NfoNode(recording))
+ self.cache.append(MpgNode(recording)) # DONT CACHE!
+ self.cache.append(NfoNode(recording)) # DONT CACHE!
return self.cache
+ def size(self):
+ # print "DirNode::size"
+ if not self.mysize:
+ self.mysize = len(self.content())
+ return self.mysize
+
def is_sub_folder(self, dir):
if not os.path.isdir(dir):
return False
@@ -130,7 +217,8 @@
return False
def get_stat(self):
+ # print "DirNode::get_stat"
attr = NodeAttributes()
- attr.st_mode = stat.S_IFDIR | 0755
- attr.st_nlink = 2 + len(self.content())
+ attr.st_mode = stat.S_IFDIR | 0555
+ attr.st_nlink = 2 + self.size()
return attr
Only in vdrnfofs-0.6.tyger1//vdrnfofs: filesystemnodes.py~
@@ -29,30 +29,32 @@
from concatenated_file_reader import *
from vdr import *
from filesystemnodes import *
+from traceback import format_exc
fuse.fuse_python_api = (0, 2)
-def get_node(video, path):
+def get_node(video, path, cache=False):
virtual_path, virtual_file_extension = os.path.splitext(path)
if virtual_file_extension in ['.mpg', '.nfo']:
p = virtual_path.rfind('_')
if p > 0:
- video_path = video + '/' + virtual_path[0:p] + '/' + virtual_path[p+1:]
+ video_path = "%s/%s/%s" % (video, virtual_path[0:p], virtual_path[p+1:])
if not os.path.isdir(video_path):
return None
elif virtual_file_extension == '.mpg':
- return MpgNode(video_path)
+ return MpgNode.create(video_path, cache)
elif virtual_file_extension == '.nfo':
- return NfoNode(video_path)
+ return NfoNode.create(video_path, cache)
else:
- if os.path.isdir(video + '/' + path):
- return DirNode(video + path)
+ dir_path = video + path
+ if os.path.isdir(dir_path):
+ return DirNode.create(dir_path, cache)
return None
class VdrNfoFsFile:
def __init__(self, path, flags, *mode):
self.path = path
- self.node = get_node(VdrNfoFsFile.video_root, path)
+ self.node = get_node(VdrNfoFsFile.video_root, path, True)
def read(self, size, offset):
try:
@@ -60,10 +62,10 @@
return -errno.ENOENT
return self.node.read(offset, size)
except:
- syslog.syslog('VdrFuseFs: Unexpected error for read(%s)' % self.path)
+ syslog.syslog('VdrFuseFs: Unexpected error for read(%s): ' % (self.path, format_exc()))
- def release(self, flags):
- self.node.release()
+# def release(self, flags):
+ # print "VdrNfoFsFile::release %s" % self.node.key
# def write(self, buf, offset):
# return 0
@@ -90,24 +92,26 @@
self.video = ""
def getattr(self, path):
+ # print "VNF::getattr"
try:
- node = get_node(self.video, path)
+ node = get_node(self.video, path, False)
if node:
+ # print "got node %s" % node.key
return node.get_stat()
return -errno.ENOENT
except:
- syslog.syslog('VdrFuseFs: Unexpected error for getattr(%s): %s' % path)
+ syslog.syslog('VdrFuseFs: Unexpected error for getattr(%s): %s' % (path, format_exc()))
def readdir(self, path, offset):
try:
yield fuse.Direntry('.')
yield fuse.Direntry('..')
- node = get_node(self.video, path)
+ node = get_node(self.video, path, True)
if node:
for item in node.content():
yield fuse.Direntry(item.file_system_name)
except:
- syslog.syslog('VdrFuseFs: Unexpected error for readdir(%s)' % path)
+ syslog.syslog('VdrFuseFs: Unexpected error for readdir(%s): %s' % (path, format_exc()))
def main(self, *a, **kw):
VdrNfoFsFile.video_root = self.video
Only in vdrnfofs-0.6.tyger1//vdrnfofs: vdrnfofs.py~
@@ -23,10 +23,10 @@
def __init__(self, filename = None):
self.values = {'T' : 'Unknown', 'D': 'No Description'}
if filename:
- file = open(filename, 'r')
- for line in file:
- line = line.rstrip("\r\n")
- self.values[line[0]] = line[2:]
+ with open(filename, 'r') as file:
+ for line in file:
+ line = line.rstrip("\r\n")
+ self.values[line[0]] = line[2:]
def __getitem__(self, key):
return self.values[key] if self.values.has_key(key) else ''
Only in vdrnfofs-0.6.tyger1//vdrnfofs: vdr.py~