~ubuntu-dev/ubuntu/lucid/coherence/lucid-201002101853

« back to all changes in this revision

Viewing changes to coherence/backends/fs_storage.py

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Quette
  • Date: 2008-03-05 13:43:01 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20080305134301-pg572ehbze3h7cii
Tags: 0.5.2-1
* New upstream release
* debian/control: depend on python-pkg-resources instead of
  python-setuptools for the runtime dependency (Closes: #468724)

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
 
22
22
from coherence.upnp.core.DIDLLite import classChooser, Container, Resource
23
23
from coherence.upnp.core.DIDLLite import DIDLElement
 
24
from coherence.upnp.core.DIDLLite import simple_dlna_tags
24
25
from coherence.upnp.core.soap_service import errorCode
25
26
 
26
27
from coherence.upnp.core import utils
29
30
from coherence.extern.inotify import IN_CREATE, IN_DELETE, IN_MOVED_FROM, IN_MOVED_TO, IN_ISDIR
30
31
from coherence.extern.inotify import IN_CHANGED
31
32
 
 
33
from coherence.extern.xdg import xdg_content
 
34
 
32
35
import louie
33
36
 
34
 
from coherence.extern.simple_plugin import Plugin
35
 
 
36
 
from coherence import log
37
 
 
38
 
class FSItem(log.Loggable):
 
37
from coherence.backend import BackendItem, BackendStore
 
38
 
 
39
class FSItem(BackendItem):
39
40
    logCategory = 'fs_item'
40
41
 
41
 
    def __init__(self, id, parent, path, mimetype, urlbase, UPnPClass,update=False):
42
 
        self.id = id
 
42
    def __init__(self, object_id, parent, path, mimetype, urlbase, UPnPClass,update=False):
 
43
        self.id = object_id
43
44
        self.parent = parent
44
45
        if parent:
45
46
            parent.add_child(self,update=update)
47
48
            self.location = unicode(path)
48
49
        else:
49
50
            if mimetype == 'item' and path is None:
50
 
                path = os.path.join(parent.get_path(),str(self.id))
 
51
                path = os.path.join(parent.get_path(),unicode(self.id))
51
52
            self.location = FilePath(unicode(path))
52
53
        self.mimetype = mimetype
53
54
        if urlbase[-1] != '/':
60
61
        else:
61
62
            parent_id = parent.get_id()
62
63
 
63
 
        self.item = UPnPClass(id, parent_id, self.get_name())
 
64
        self.item = UPnPClass(object_id, parent_id, self.get_name())
64
65
        if isinstance(self.item, Container):
65
66
            self.item.childCount = 0
66
67
        self.child_count = 0
71
72
            self.update_id = 0
72
73
            #self.item.searchable = True
73
74
            #self.item.searchClass = 'object'
74
 
            self.check_for_cover_art()
75
 
            if hasattr(self, 'cover'):
76
 
                _,ext =  os.path.splitext(self.cover)
77
 
                """ add the cover image extension to help clients not reacting on
78
 
                    the mimetype """
79
 
                self.item.albumArtURI = ''.join((urlbase,str(self.id),'?cover',ext))
 
75
            if(isinstance(self.location,FilePath) and
 
76
               self.location.isdir() == True):
 
77
                self.check_for_cover_art()
 
78
                if hasattr(self, 'cover'):
 
79
                    _,ext =  os.path.splitext(self.cover)
 
80
                    """ add the cover image extension to help clients not reacting on
 
81
                        the mimetype """
 
82
                    self.item.albumArtURI = ''.join((urlbase,str(self.id),'?cover',ext))
80
83
        else:
81
 
            if hasattr(parent, 'cover'):
82
 
                _,ext =  os.path.splitext(parent.cover)
83
 
                """ add the cover image extension to help clients not reacting on
84
 
                    the mimetype """
85
 
                self.item.albumArtURI = ''.join((urlbase,str(self.id),'?cover',ext))
86
 
 
87
 
            self.item.res = []
 
84
            if self.mimetype.startswith('audio/'):
 
85
                if hasattr(parent, 'cover'):
 
86
                    _,ext =  os.path.splitext(parent.cover)
 
87
                    """ add the cover image extension to help clients not reacting on
 
88
                        the mimetype """
 
89
                    self.item.albumArtURI = ''.join((urlbase,str(self.id),'?cover',ext))
88
90
 
89
91
            _,host_port,_,_,_ = urlsplit(urlbase)
90
92
            if host_port.find(':') != -1:
110
112
            res.size = size
111
113
            self.item.res.append(res)
112
114
 
 
115
 
 
116
            """ if this item is an image and we want to add a thumbnail for it
 
117
                we have to follow these rules:
 
118
 
 
119
                create a new Resource object, at least a 'http-get'
 
120
                and maybe an 'internal' one too
 
121
 
 
122
                for an JPG this looks like that
 
123
 
 
124
                res = Resource(url_for_thumbnail,
 
125
                        'http-get:*:image/jpg:%s'% ';'.join(simple_dlna_tags+('DLNA.ORG_PN=JPEG_TN',)))
 
126
                res.size = size_of_thumbnail
 
127
                self.item.res.append(res)
 
128
 
 
129
                and for a PNG the Resource creation is like that
 
130
 
 
131
                res = Resource(url_for_thumbnail,
 
132
                        'http-get:*:image/png:%s'% ';'.join(simple_dlna_tags+('DLNA.ORG_PN=PNG_TN',)))
 
133
 
 
134
                if not hasattr(self.item, 'attachments'):
 
135
                    self.item.attachments = {}
 
136
                self.item.attachments[key] = utils.StaticFile(filename_of_thumbnail)
 
137
            """
 
138
 
 
139
            if self.mimetype in ('image/jpeg', 'image/png'):
 
140
                path = self.get_path()
 
141
                thumbnail = os.path.join(os.path.dirname(path),'.thumbs',os.path.basename(path))
 
142
                if os.path.exists(thumbnail):
 
143
                    mimetype,_ = mimetypes.guess_type(thumbnail, strict=False)
 
144
                    if mimetype in ('image/jpeg','image/png'):
 
145
                        if mimetype == 'image/jpeg':
 
146
                            dlna_pn = 'DLNA.ORG_PN=JPEG_TN'
 
147
                        else:
 
148
                            dlna_pn = 'DLNA.ORG_PN=PNG_TN'
 
149
 
 
150
                        hash_from_path = str(id(thumbnail))
 
151
                        new_res = Resource(self.url+'?attachment='+hash_from_path,
 
152
                            'http-get:*:%s:%s' % (mimetype, ';'.join(simple_dlna_tags+(dlna_pn,))))
 
153
                        new_res.size = os.path.getsize(thumbnail)
 
154
                        self.item.res.append(new_res)
 
155
                        if not hasattr(self.item, 'attachments'):
 
156
                            self.item.attachments = {}
 
157
                        self.item.attachments[hash_from_path] = utils.StaticFile(thumbnail)
 
158
 
 
159
 
113
160
            try:
114
161
                # FIXME: getmtime is deprecated in Twisted 2.6
115
162
                self.item.date = datetime.fromtimestamp(self.location.getmtime())
134
181
                the mimetype """
135
182
            self.item.albumArtURI = ''.join((urlbase,str(self.id),'?cover',ext))
136
183
 
137
 
        self.item.res = []
138
 
 
139
184
        _,host_port,_,_,_ = urlsplit(urlbase)
140
185
        if host_port.find(':') != -1:
141
186
            host,port = tuple(host_port.split(':'))
173
218
            or png if the jpg search fails, and take the first one
174
219
            that comes around
175
220
        """
176
 
        jpgs = [i.path for i in self.location.children() if i.splitext()[1] in ('.jpg', '.JPG')]
177
221
        try:
178
 
            self.cover = jpgs[0]
179
 
        except IndexError:
180
 
            pngs = [i.path for i in self.location.children() if i.splitext()[1] in ('.png', '.PNG')]
 
222
            jpgs = [i.path for i in self.location.children() if i.splitext()[1] in ('.jpg', '.JPG')]
181
223
            try:
182
 
                self.cover = pngs[0]
 
224
                self.cover = jpgs[0]
183
225
            except IndexError:
184
 
                return
 
226
                pngs = [i.path for i in self.location.children() if i.splitext()[1] in ('.png', '.PNG')]
 
227
                try:
 
228
                    self.cover = pngs[0]
 
229
                except IndexError:
 
230
                    return
 
231
        except UnicodeDecodeError:
 
232
            self.warning("UnicodeDecodeError - there is something wrong with a file located in %r", self.location.path)
185
233
 
186
234
    def remove(self):
187
235
        #print "FSItem remove", self.id, self.get_name(), self.parent
272
320
    def __repr__(self):
273
321
        return 'id: ' + str(self.id) + ' @ ' + self.location.basename()
274
322
 
275
 
class FSStore(log.Loggable,Plugin):
 
323
class FSStore(BackendStore):
276
324
    logCategory = 'fs_store'
277
325
 
278
326
    implements = ['MediaServer']
279
327
 
280
 
    wmc_mapping = {'4':1000, '8':1000}
281
 
 
282
328
    def __init__(self, server, **kwargs):
 
329
        BackendStore.__init__(self)
283
330
        self.next_id = 1000
284
331
        self.name = kwargs.get('name','my media')
285
 
        self.content = kwargs.get('content','tests/content')
 
332
        self.content = kwargs.get('content',None)
 
333
        if self.content != None:
 
334
                if isinstance(self.content,basestring):
 
335
                    self.content = [self.content]
 
336
                l = []
 
337
                for a in self.content:
 
338
                    l += a.split(',')
 
339
                self.content = l
 
340
        else:
 
341
            self.content = xdg_content()
 
342
        if self.content == None:
 
343
            self.content = 'tests/content'
286
344
        if not isinstance( self.content, list):
287
345
            self.content = [self.content]
288
346
        self.urlbase = kwargs.get('urlbase','')
307
365
            parent = self.store[id] = FSItem( id, parent, 'media', 'root', self.urlbase, UPnPClass, update=True)
308
366
 
309
367
        for path in self.content:
 
368
            if isinstance(path,(list,tuple)):
 
369
                path = path[0]
310
370
            if self.ignore_file_pattern.match(path):
311
371
                continue
312
372
            self.walk(path, parent, self.ignore_file_pattern)
351
411
            containers.append(parent)
352
412
        while len(containers)>0:
353
413
            container = containers.pop()
354
 
            for child in container.location.children():
355
 
                if ignore_file_pattern.match(child.basename()) != None:
356
 
                    continue
357
 
                new_container = self.append(child.path,container)
358
 
                if new_container != None:
359
 
                    containers.append(new_container)
 
414
            try:
 
415
                for child in container.location.children():
 
416
                    if ignore_file_pattern.match(child.basename()) != None:
 
417
                        continue
 
418
                    new_container = self.append(child.path,container)
 
419
                    if new_container != None:
 
420
                        containers.append(new_container)
 
421
            except UnicodeDecodeError:
 
422
                self.warning("UnicodeDecodeError - there is something wrong with a file located in %r", container.get_path())
360
423
 
361
424
    def create(self, mimetype, path, parent):
362
425
        UPnPClass = classChooser(mimetype)
384
447
 
385
448
    def append(self,path,parent):
386
449
        #print "append", path
387
 
        mimetype,_ = mimetypes.guess_type(path, strict=False)
388
 
        if mimetype == None:
389
 
            if os.path.isdir(path) or os.path.islink(path):
390
 
                mimetype = 'directory'
391
 
        if mimetype == None:
392
 
            return None
393
 
 
394
 
        id = self.create(mimetype,path,parent)
395
 
 
396
 
        if mimetype == 'directory':
397
 
            if self.inotify is not None:
398
 
                mask = IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO | IN_CHANGED
399
 
                self.inotify.watch(path, mask=mask, auto_add=False, callbacks=(self.notify,id))
400
 
            return self.store[id]
 
450
        try:
 
451
            mimetype,_ = mimetypes.guess_type(path, strict=False)
 
452
            if mimetype == None:
 
453
                if os.path.isdir(path) or os.path.islink(path):
 
454
                    mimetype = 'directory'
 
455
            if mimetype == None:
 
456
                return None
 
457
 
 
458
            id = self.create(mimetype,path,parent)
 
459
 
 
460
            if mimetype == 'directory':
 
461
                if self.inotify is not None:
 
462
                    mask = IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO | IN_CHANGED
 
463
                    self.inotify.watch(path, mask=mask, auto_add=False, callbacks=(self.notify,id))
 
464
                return self.store[id]
 
465
        except OSError, msg:
 
466
            """ seems we have some permissions issues along the content path """
 
467
            self.warning("path %r isn't accessible, error %r", path, msg)
401
468
 
402
469
        return None
403
470
 
526
593
        return {'TransferID': transfer_id}
527
594
 
528
595
    def upnp_CreateObject(self, *args, **kwargs):
529
 
        ContainerID = int(kwargs['ContainerID'])
 
596
        if kwargs['ContainerID'] == 'DLNA.ORG_AnyContainer':
 
597
            """ for the moment """
 
598
            return failure.Failure(errorCode(712))
 
599
        else:
 
600
            ContainerID = kwargs['ContainerID']
530
601
        Elements = kwargs['Elements']
531
602
 
532
603
        parent_item = self.get_by_id(ContainerID)