Browse Source

add support for dynamicly changing file systems.. we will now notice

when directories and files change size, and update the proper
information..

hmm.. just realized we may still need to checkUpdate on all the
children we return, and that's better than always checkUpdate'ing
on add...

[git-p4: depot-paths = "//depot/": change = 766]
replace/4e84fdb41ea781c7a8f872baa423e8b3be4045a7
John-Mark Gurney 19 years ago
parent
commit
1d01658bb7
3 changed files with 168 additions and 3 deletions
  1. +11
    -1
      ContentDirectory.py
  2. +155
    -0
      FSStorage.py
  3. +2
    -2
      pymediaserv

+ 11
- 1
ContentDirectory.py View File

@@ -23,7 +23,7 @@ from twisted.python import log
from twisted.web import resource, static

from elementtree.ElementTree import Element, SubElement, tostring
from upnp import UPnPPublisher
from upnp import UPnPPublisher, errorCode
from DIDLLite import DIDLElement, Container, Movie, Resource, MusicTrack

import traceback
@@ -56,6 +56,8 @@ class ContentDirectoryControl(UPnPPublisher, dict):
self.delItem(i)
assert len(self.children[id]) == 0
del self.children[id]
# Remove from parent
self.children[self[id].parentID].remove(self[id])
del self[id]

def getchildren(self, item):
@@ -121,6 +123,14 @@ class ContentDirectoryControl(UPnPPublisher, dict):
didl = DIDLElement()
result = {}

# check to see if object needs to be updated
if ObjectID in self and hasattr(self[ObjectID], 'checkUpdate'):
self[ObjectID].checkUpdate()

# return error code if we don't exist
if ObjectID not in self:
raise errorCode(701)

try:
if BrowseFlag == 'BrowseDirectChildren':
ch = self.getchildren(ObjectID)[StartingIndex: StartingIndex + RequestedCount]


+ 155
- 0
FSStorage.py View File

@@ -0,0 +1,155 @@
#!/usr/bin/env python

import errno
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

mimedict = static.loadMimeTypes()

def statcmp(a, b, cmpattrs = [ 'st_ino', 'st_dev', 'st_size', 'st_mtime', ]):
if a is None or b is None:
return False

for i in cmpattrs:
if getattr(a, i) != getattr(b, i):
return False
return True

class FSObject(object):
def __init__(self, path):
self.FSpath = path
self.pstat = None

def checkUpdate(self):
# need to handle no such file or directory
# push it up? but still need to handle disappearing
try:
nstat = os.stat(self.FSpath)
if statcmp(self.pstat, nstat):
return

self.pstat = nstat
self.doUpdate()
except OSError, x:
log.msg('OSError: %s' % x)
if x.errno in (errno.ENOENT, errno.ENOTDIR, errno.EPERM, ):
# We can't access it anymore, delete it
self.cd.delItem(self.id)
else:
raise x
except:
import traceback
print traceback.print_exc()

def doUpdate(self):
raise NotImplementedError

class FSItem(FSObject, Item):
def __init__(self, *args, **kwargs):
FSObject.__init__(self, kwargs['path'])
del kwargs['path']
urlbase = kwargs['urlbase']
del kwargs['urlbase']
mimetype = kwargs['mimetype']
del kwargs['mimetype']
Item.__init__(self, *args, **kwargs)
self.url = '%s%s' % (urlbase, self.FSpath)
self.mimetype = mimetype

def doUpdate(self):
self.res = Resource(self.url, 'http-get:*:%s:*' % self.mimetype)
self.res.size = os.path.getsize(fpath)

class FSVideoItem(FSItem, VideoItem):
pass

class FSAudioItem(FSItem, AudioItem):
pass

class FSTextItem(FSItem, TextItem):
pass

class FSImageItem(FSItem, ImageItem):
pass

mimetoklass = {
'application/ogg': FSAudioItem,
'video': FSVideoItem,
'audio': FSAudioItem,
'text': FSTextItem,
'image': FSImageItem,
}

def dofileadd(cd, parent, urlbase, path, name):
fn, ext = os.path.splitext(name)
ext = ext.lower()
try:
mt = mimedict[ext]
except KeyError:
log.msg('no mime-type for: %s' % name)
return

ty = mt.split('/')[0]
if mimetoklass.has_key(mt):
klass = mimetoklass[mt]
elif mimetoklass.has_key(ty):
klass = mimetoklass[ty]
else:
raise KeyError, 'no item for mt: %s' % mt

return cd.addItem(parent, klass, name, urlbase = urlbase,
path = os.path.join(path, name), mimetype = mt)

class FSDirectory(StorageFolder, FSObject):
def __init__(self, *args, **kwargs):
path = kwargs['path']
del kwargs['path']
urlbase = kwargs['urlbase']
del kwargs['urlbase']
StorageFolder.__init__(self, *args, **kwargs)
FSObject.__init__(self, path)

# mapping from path to objectID
self.pathObjmap = {}
self.urlbase = urlbase

def doUpdate(self):
# We need to rescan this dir, and see if our children has
# changed any.
log.msg('doUpdate: %s, path: %s' % (self.title, self.FSpath))
children = sets.Set(os.listdir(self.FSpath))
for i in self.pathObjmap:
if i not in children:
# delete
self.cd.delItem(self.pathObjmap[i])

log.msg('doUpdate: %s, children: %s' % (self.title, children))
for i in children:
fname = os.path.join(self.FSpath, i)
if i in self.pathObjmap:
continue

# new object
if os.path.isdir(fname):
# new dir
nf = self.cd.addContainer(self.id, i, klass = FSDirectory, path = fname, urlbase = self.urlbase)
elif os.path.isfile(fname):
# new file
nf = dofileadd(self.cd, self.id, self.urlbase, self.FSpath, i)
else:
nf = None
log.msg('skipping: %s' % fname)

if nf is not None:
self.pathObjmap[i] = nf
log.msg('i: %s, nf: %s' % (i, nf))
self.cd[nf].checkUpdate()

# sort our children
log.msg('doUpdate: %s, sorting: %s' % (self.title, list.__str__(self)))
self.sort(lambda x, y: cmp(x.title, y.title))
log.msg('sorted')

+ 2
- 2
pymediaserv View File

@@ -6,6 +6,7 @@
# Copyright 2006 John-Mark Gurney <gurney_j@resnet.uroegon.edu>

from DIDLLite import TextItem, AudioItem, VideoItem, ImageItem, Resource, StorageFolder
from FSStorage import FSDirectory
import os
import os.path
import random
@@ -84,8 +85,6 @@ medianode.contentTypes.update( {
'.mp4': 'video/mpeg',
'.ogm': 'application/ogg',
'.vob': 'video/mpeg',
'.mp3': 'audio/mpeg',
'.ogg': 'audio/x-ogg',
})
root.putChild('media', medianode)

@@ -124,6 +123,7 @@ def addFSPath(cds, parent, dpath):
except KeyError:
pass

cds.addContainer('0', 'media', klass = FSDirectory, path = 'media', urlbase = urlbase)
addFSPath(cds, '0', 'media')

site = server.Site(root)


Loading…
Cancel
Save