Browse Source

make DIDLLite's a real object so we can use them

in weakref's...

make looking into zip files work!  we don't support subdirs yet, but
I am able to play an avi and mp3 files at the root...

import the ZipStorage module into pymediaserv, we'll probably want
a modules dir, and a config file on what ones to import..

[git-p4: depot-paths = "//depot/": change = 809]
v0.3
John-Mark Gurney 18 years ago
parent
commit
ad85fe4c23
4 changed files with 170 additions and 34 deletions
  1. +1
    -1
      DIDLLite.py
  2. +7
    -4
      FSStorage.py
  3. +159
    -29
      ZipStorage.py
  4. +3
    -0
      pymediaserv

+ 1
- 1
DIDLLite.py View File

@@ -32,7 +32,7 @@ class Resource:

return root

class Object:
class Object(object):
"""The root class of the entire content directory class heirachy."""

klass = 'object'


+ 7
- 4
FSStorage.py View File

@@ -10,6 +10,7 @@ import itertools
import os
import sets
import stat

from DIDLLite import StorageFolder, Item, VideoItem, AudioItem, TextItem, ImageItem, Resource
from twisted.web import static
from twisted.python import log
@@ -97,8 +98,9 @@ def defFS(path, fobj):

def dofileadd(cd, parent, path, name):
klass = None
fsname = os.path.join(path, name)
try:
fobj = open(path)
fobj = open(fsname)
except:
fobj = None
for i in itertools.chain(klassfuns, ( defFS, )):
@@ -108,12 +110,13 @@ def dofileadd(cd, parent, path, name):
except:
pass

klass, kwargs = i(os.path.join(path, name), fobj)
klass, kwargs = i(fsname, fobj)
if klass is not None:
break
except:
import traceback
traceback.print_exc()
#import traceback
#traceback.print_exc(file=log.logfile)
pass

if klass is None:
return


+ 159
- 29
ZipStorage.py View File

@@ -4,33 +4,165 @@
# $Id$
#

import itertools
import os.path
import sets
import time
import zipfile

import FileDIDL
from DIDLLite import StorageFolder, Item, VideoItem, AudioItem, TextItem, ImageItem, Resource
from FSStorage import FSObject, registerklassfun

def isatpath(f, p):
if f[:len(p)] != p:
# First part of path doesn't match, it's not
return False

slash = f[len(p):].find('/')
if slash != -1 and slash != len(f) - len(p) + 1:
# Another path component, skip it, as long as it's not the char
return False
from twisted.python import threadable, log
from twisted.spread import pb
from twisted.web import http
from twisted.web import server
from twisted.web import resource

def inserthierdict(d, name, obj):
if not name:
return
i = name.find('/')
if i == -1:
d[name] = obj
return

dname = name[:i]
rname = name[i + 1:]
# remaining path components
try:
inserthierdict(d[dname], rname, obj)
except KeyError:
d[dname] = {}
inserthierdict(d[dname], rname, obj)

def buildNameHier(names, objs):
ret = {}
for n, o in itertools.izip(names, objs):
inserthierdict(ret, n, o)

return ret

class ZipFileTransfer(pb.Viewable):
def __init__(self, zf, name, request):
self.zf = zf
self.size = zf.getinfo(name).file_size
self.iter = zf.readiter(name)
self.request = request
self.written = 0
request.registerProducer(self, 0)

def resumeProducing(self):
if not self.request:
return
# get data and write to request.
try:
data = self.iter.next()
if data:
self.written += len(data)
# this .write will spin the reactor, calling
# .doWrite and then .resumeProducing again, so
# be prepared for a re-entrant call
self.request.write(data)
except StopIteration:
if self.request:
self.request.unregisterProducer()
self.request.finish()
self.request = None

def pauseProducing(self):
pass

def stopProducing(self):
# close zipfile
self.request = None

# Remotely relay producer interface.

def view_resumeProducing(self, issuer):
self.resumeProducing()

def view_pauseProducing(self, issuer):
self.pauseProducing()

def view_stopProducing(self, issuer):
self.stopProducing()

synchronized = ['resumeProducing', 'stopProducing']

threadable.synchronize(ZipFileTransfer)

class ZipResource(resource.Resource):
# processors = {}

isLeaf = True

def __init__(self, zf, name, mt):
resource.Resource.__init__(self)
self.zf = zf
self.zi = zf.getinfo(name)
self.name = name
self.mt = mt

def getFileSize(self):
return self.zi.file_size

def render(self, request):
request.setHeader('content-type', self.mt)

# We could possibly send the deflate data directly!
if None and self.encoding:
request.setHeader('content-encoding', self.encoding)

if request.setLastModified(time.mktime(list(self.zi.date_time) +
[ 0, 0, -1])) is http.CACHED:
return ''

request.setHeader('content-length', str(self.getFileSize()))
if request.method == 'HEAD':
return ''

# return data
ZipFileTransfer(self.zf, self.name, request)
# and make sure the connection doesn't get closed
return server.NOT_DONE_YET

class ZipItem(Item):
'''An item in the zip file'''

# otherwise, it is at this level
endtrim = len(f)
if slash:
endtrip -= 1
def __init__(self, *args, **kwargs):
self.zo = kwargs['zo']
del kwargs['zo']
self.zf = kwargs['zf']
del kwargs['zf']
self.name = kwargs['name']
del kwargs['name']
self.zi = self.zf.getinfo(self.name)
self.mimetype = kwargs['mimetype']
del kwargs['mimetype']
kwargs['content'] = ZipResource(self.zf, self.name,
self.mimetype)
Item.__init__(self, *args, **kwargs)
self.url = '%s/%s' % (self.cd.urlbase, self.id)

def checkUpdate(self):
self.doUpdate()
return self.zo.checkUpdate()

return f[len(p):endtrim]
def doUpdate(self):
log.msg('doUpdate:', `self`, self.name)
self.res = Resource(self.url, 'http-get:*:%s:*' % self.mimetype)
self.res.size = self.zi.file_size
Item.doUpdate(self)

class ZipChildDir(StorageFolder):
class ZipChildDir(ZipItem, StorageFolder):
'''This is to represent a child dir of the zip file.'''

class ZipFile(FSObject, StorageFolder):
def __init__(self):
raise NotImplementedError

class ZipObject(FSObject, StorageFolder):
def __init__(self, *args, **kwargs):
'''If a zip argument is passed it, use that as the zip archive.'''
path = kwargs['path']
@@ -42,20 +174,12 @@ class ZipFile(FSObject, StorageFolder):
# mapping from path to objectID
self.pathObjmap = {}

def getdirents(path):
'''Returns the list of entires for the path, '' is the root path.'''
lst = self.zip.namelist()
if path:
path += '/'

return filter(lambda x, p = path: isatpath(x, p), lst)

def doUpdate(self):
# open the zipfile as necessary.
self.zip = zipfile.ZipFile(self.FSpath)
hier = buildNameHier(self.zip.namelist(), self.zip.infolist())

allzipfiles = sets.Set(self.zip.namelist())
children = sets.Set(getdirents(''))
children = sets.Set(hier.keys())
for i in self.pathObjmap.keys():
if i not in children:
# delete
@@ -67,17 +191,23 @@ class ZipFile(FSObject, StorageFolder):
continue

# new object
if i not in allzipfiles:
if isinstance(hier[i], dict):
# must be a dir
self.pathObjmap[i] = self.cd.addItem(self.id,
ZipChildDir, i, self, i)
else:
ZipChild(self, i)
klass, mt = FileDIDL.buildClassMT(ZipItem, i)
self.pathObjmap[i] = self.cd.addItem(self.id,
klass, i, zf = self.zip, zo = self,
name = i, mimetype = mt)

def detectzipfile(path, fobj):
try:
z = zipfile.ZipFile(fobj)
log.msg(`z`)
except:
return None, None

return ZipFile, {}
return ZipObject, { 'path': path }

registerklassfun(detectzipfile)

+ 3
- 0
pymediaserv View File

@@ -8,6 +8,9 @@
# $Id$
#

# Modules to import, maybe config file or something?
import ZipStorage

from DIDLLite import TextItem, AudioItem, VideoItem, ImageItem, Resource, StorageFolder
from FSStorage import FSDirectory
import os


Loading…
Cancel
Save