source: telemeta/models/dublincore.py @ 305c6d0

cremcrem2devdev2diademsdj1.6feature/breadcrumbsfeature/ts-0.5feature/ts-0.5.4feature/writecacheformagenericinstru_searchlamlam2mapsv3mergenlivemultiproductionrelease/1.4.4sabiodsecurityserversocialstoragetelecastertestvideo
Last change on this file since 305c6d0 was 305c6d0, checked in by yomguy <yomguy@…>, 3 years ago

fix dc domain with site.domain parsing

  • Property mode set to 100644
File size: 10.0 KB
Line 
1# -*- coding: utf-8 -*-
2# Copyright (C) 2007 Samalyse SARL
3
4# This software is a computer program whose purpose is to backup, analyse,
5# transcode and stream any audio content with its metadata over a web frontend.
6
7# This software is governed by the CeCILL  license under French law and
8# abiding by the rules of distribution of free software.  You can  use,
9# modify and/ or redistribute the software under the terms of the CeCILL
10# license as circulated by CEA, CNRS and INRIA at the following URL
11# "http://www.cecill.info".
12
13# As a counterpart to the access to the source code and  rights to copy,
14# modify and redistribute granted by the license, users are provided only
15# with a limited warranty  and the software's author,  the holder of the
16# economic rights,  and the successive licensors  have only  limited
17# liability.
18
19# In this respect, the user's attention is drawn to the risks associated
20# with loading,  using,  modifying and/or developing or reproducing the
21# software by the user in light of its specific status of free software,
22# that may mean  that it is complicated to manipulate,  and  that  also
23# therefore means  that it is reserved for developers  and  experienced
24# professionals having in-depth computer knowledge. Users are therefore
25# encouraged to load and test the software's suitability as regards their
26# requirements in conditions enabling the security of their systems and/or
27# data to be ensured and,  more generally, to use and operate it in the
28# same conditions as regards security.
29
30# The fact that you are presently reading this means that you have had
31# knowledge of the CeCILL license and that you accept its terms.
32#
33# Author: Olivier Guilyardi <olivier@samalyse.com>
34
35from telemeta.models.core import Duration
36from telemeta.models.media import MediaItem, MediaCollection
37from django.contrib.sites.models import Site
38from django.conf import settings
39
40
41class Resource(object):
42    "Represent a Dublin Core resource"
43
44    def __init__(self, *args):
45        self.elements = []
46        self.add(*args)
47
48    def flatten(self):
49        """Convert the resource to a dictionary with element names as keys.
50
51        Warnings:
52        - refinements are lost during this conversion,
53        - if there are several occurences of the same element, only the first is
54        used, others are lost.
55        - all values are converted to strings
56        """
57        result = {}
58        for element in self.elements:
59            if not result.has_key(element.name):
60                result[element.name] = unicode(element.value)
61        return result
62
63    def to_list(self):
64        """Convert the resource to unqualified dublin core, as a list of the form:
65           [(key, value), ...]"""
66        result = []
67        for element in self.elements:
68            result.append((element.name, unicode(element.value)))
69        return result
70
71    def add(self, *elements):
72        for e in elements:
73            if isinstance(e, Element):
74                if not e in self.elements:
75                    self.elements.append(e)
76            else:
77                try:
78                    iter(e)
79                except TypeError: 
80                    raise Exception("add() only accepts elements or sequences of elements")
81
82                self.add(*e)
83
84    def __unicode__(self):
85        dump = u''
86        for e in self.elements:
87            key = unicode(e.name)
88            if e.refinement:
89                key += u'.' + unicode(e.refinement)
90            dump += u'%s:\t%s\n' % (key, unicode(e.value))
91        return dump           
92           
93
94class Element(object):
95    "Represent a Dublin Core element"
96
97    def __init__(self, name, value=None, refinement=None, related=None):
98        self.name = name
99        self.value = value
100        self.refinement = refinement
101        self.related = related
102
103    def __eq__(self, other):
104        return self.name == other.name and self.value == other.value and self.refinement == self.refinement
105
106    def __ne__(self, other):
107        return not (self == other)
108
109    @staticmethod
110    def multiple(name, values, refinement=None):
111        elements = []
112        if values:
113            for v in values:
114                elements.append(Element(name, v, refinement))
115        return elements
116
117class Date(Element):
118    "Dublin Core date element formatted according to W3C-DTF or DCMI Period"
119
120    def __init__(self, start, end=None, refinement=None):
121        value = ''
122        if start:
123            value = start
124        elif end:
125            value = end
126        else:
127            value = ''
128        if isinstance(value, long):
129            # start is a year
130            value = unicode(value) + '-01-01T00:00:00Z'
131        elif value:
132            value = value.strftime('%Y-%m-%dT%H:%M:%SZ')
133           
134        super(Date, self).__init__('date', value, refinement)           
135
136def media_access_rights(media):
137    if media.public_access == 'full':
138        return 'public'
139    if media.public_access == 'metadata':
140        return 'restricted'
141    return 'private'
142
143def media_identifier(media):
144    sites = Site.objects.all()
145    domain = sites[0].domain
146    return 'http://' + domain + '/' + media.element_type + 's/' + unicode(media.id)
147
148def express_collection(collection):
149    "Express a collection as a Dublin Core resource"
150
151    if collection.collector:
152        creator = (Element('creator', collection.collector), 
153                   Element('contributor', collection.creator))
154    else:                       
155        creator = Element('creator', collection.creator)
156
157    duration = max(collection.approx_duration, collection.computed_duration())
158    parts = []
159    for item in collection.items.all():
160        id = media_identifier(item)
161        if id:
162            parts.append(Element('relation', id, 'hasPart', item))
163
164    resource = Resource(
165        Element('identifier',       media_identifier(collection), related=collection),
166        Element('type',             'Collection'),
167        Element('title',            collection.title),
168        Element('title',            collection.alt_title),
169        creator,
170        Element('contributor',      collection.metadata_author),
171        Element.multiple('subject', settings.TELEMETA_SUBJECTS),
172        Element('publisher',        collection.publisher),
173        Element('publisher',        settings.TELEMETA_ORGANIZATION),
174        Date(collection.recorded_from_year, collection.recorded_to_year, refinement='created'),
175        Date(collection.year_published, refinement='issued'),
176        Element('rights',           collection.legal_rights, 'license'),
177        Element('rights',           media_access_rights(collection), 'accessRights'),
178        Element('format',           duration, 'extent'),
179        Element('format',           collection.physical_format, 'medium'),
180        #FIXME: audio mime types are missing,
181        parts
182    )
183
184    return resource
185
186def express_item(item):
187    "Express a media item as a Dublin Core resource"
188
189    if item.collector:
190        creator = (Element('creator', item.collector),
191                   Element('contributor', item.collection.creator))
192    elif item.collection.collector:                   
193        creator = (Element('creator', item.collection.collector),
194                   Element('contributor', item.collection.creator))
195    else:
196        creator = Element('creator', item.collection.creator)
197       
198    if item.recorded_from_date:
199        date = Date(item.recorded_from_date, item.recorded_to_date, refinement='created')
200    else:
201        date = Date(item.collection.recorded_from_year, item.collection.recorded_to_year, refinement='created'),
202       
203    if item.title:
204        title = item.title
205    else:
206        title = item.collection.title
207        if item.track:
208            title += u' - ' + item.track
209
210    resource = Resource(
211        Element('identifier',       media_identifier(item), related=item),
212        Element('type',             'Sound'),
213        Element('title',            title),
214        Element('title',            item.alt_title),
215        creator,
216        Element('contributor',      item.collection.metadata_author),
217        Element.multiple('subject', settings.TELEMETA_SUBJECTS),
218        Element.multiple('subject', item.keywords()),
219        Element('description',      item.context_comment, 'abstract'),
220        Element('publisher',        item.collection.publisher),
221        Element('publisher',        settings.TELEMETA_ORGANIZATION),
222        date,
223        Date(item.collection.year_published, refinement='issued'),
224        Element.multiple('coverage', item.location and item.location.fullnames(), 'spatial'),
225        Element('coverage',         item.location_comment, 'spatial'),
226        Element('rights',           item.collection.legal_rights, 'license'),
227        Element('rights',           media_access_rights(item.collection), 'accessRights'),
228   
229        Element('format',           max(item.approx_duration, item.computed_duration()), 'extent'),
230        Element('format',           item.collection.physical_format, 'medium'),
231        #FIXME: audio mime types are missing,
232        Element('relation',         media_identifier(item.collection), 'isPartOf', item.collection)
233    )
234
235    return resource
236   
237def express_resource(res):
238    if isinstance(res, MediaItem):
239        return express_item(res)
240    elif isinstance(res, MediaCollection):
241        return express_collection(res)
242
243    raise Exception("Invalid resource type")       
244
245def lookup_resource(media_id):
246    try:
247        type, code = media_id.split(':', 1)
248    except ValueError:
249        raise MalformedMediaIdentifier("Media identifier must be in type:code format")
250   
251    if (type == 'collection'):
252        try:
253            return MediaCollection.objects.get(code=code)
254        except MediaCollection.DoesNotExist:
255            return None
256    elif (type == 'item'):
257        try:
258            return MediaItem.objects.get(code=code)
259        except MediaItem.DoesNotExist:
260            try:
261                return MediaItem.objects.get(old_code=code)
262            except MediaItem.DoesNotExist:
263                return None
264    else:
265        raise MalformedMediaIdentifier("No such type in media identifier: " + type)
266   
267class MalformedMediaIdentifier(Exception):
268    pass
Note: See TracBrowser for help on using the repository browser.