]> git.parisson.com Git - telemeta.git/commitdiff
fix collection edit, separate item_analyze method
authoryomguy <yomguy@parisson.com>
Mon, 7 Feb 2011 16:39:33 +0000 (17:39 +0100)
committeryomguy <yomguy@parisson.com>
Mon, 7 Feb 2011 16:39:33 +0000 (17:39 +0100)
telemeta/core.py
telemeta/templates/telemeta_default/collection_detail.html
telemeta/templates/telemeta_default/mediaitem_detail_edit.html
telemeta/urls.py
telemeta/web/base.py

index c7e7e2211ac81506dd3975db77c635dee775c413..4c3c17bb47aa19f1300ff580ede0aa6af286ecb4 100644 (file)
@@ -1,14 +1,20 @@
 # -*- coding: utf-8 -*-
 #
 # Copyright (C) 2007 Samalyse SARL
+# Copyright (C) 2003-2005 Edgewall Software
+# Copyright (C) 2003-2004 Jonas Borgström <jonas@edgewall.com>
+# Copyright (C) 2004-2005 Christopher Lenz <cmlenz@gmx.de>
 # All rights reserved.
 #
 # This software is licensed as described in the file COPYING, which
 # you should have received as part of this distribution. 
 #
-# Author: Olivier Guilyardi <olivier@samalyse.com>
+# Author: Jonas Borgström <jonas@edgewall.com>
+#         Christopher Lenz <cmlenz@gmx.de>
+#         Olivier Guilyardi <olivier@samalyse.com>
 
-__all__ = ['TelemetaError']
+__all__ = ['Component', 'ExtensionPoint', 'implements', 'Interface',
+           'TelemetaError']
 
 
 class TelemetaError(Exception):
@@ -21,3 +27,168 @@ class TelemetaError(Exception):
 #        self.title = title
 #        self.show_traceback = show_traceback
 
+class Interface(object):
+    """Marker base class for extension point interfaces."""
+
+
+class ExtensionPoint(property):
+    """Marker class for extension points in components."""
+
+    def __init__(self, interface):
+        """Create the extension point.
+        
+        @param interface: the `Interface` subclass that defines the protocol
+            for the extension point
+        """
+        property.__init__(self, self.extensions)
+        self.interface = interface
+        self.__doc__ = 'List of components that implement `%s`' % \
+                       self.interface.__name__
+
+    def extensions(self, component):
+        """Return a list of components that declare to implement the extension
+        point interface."""
+        extensions = ComponentMeta._registry.get(self.interface, [])
+        return filter(None, [component.compmgr[cls] for cls in extensions])
+
+    def __repr__(self):
+        """Return a textual representation of the extension point."""
+        return '<ExtensionPoint %s>' % self.interface.__name__
+
+
+class ComponentMeta(type):
+    """Meta class for components.
+    
+    Takes care of component and extension point registration.
+    """
+    _components = []
+    _registry = {}
+
+    def __new__(cls, name, bases, d):
+        """Create the component class."""
+
+        d['_implements'] = _implements[:]
+        del _implements[:]
+
+        new_class = type.__new__(cls, name, bases, d)
+        if name == 'Component':
+            # Don't put the Component base class in the registry
+            return new_class
+
+        # Only override __init__ for Components not inheriting ComponentManager
+        if True not in [issubclass(x, ComponentManager) for x in bases]:
+            # Allow components to have a no-argument initializer so that
+            # they don't need to worry about accepting the component manager
+            # as argument and invoking the super-class initializer
+            init = d.get('__init__')
+            if not init:
+                # Because we're replacing the initializer, we need to make sure
+                # that any inherited initializers are also called.
+                for init in [b.__init__._original for b in new_class.mro()
+                             if issubclass(b, Component)
+                             and '__init__' in b.__dict__]:
+                    break
+            def maybe_init(self, compmgr, init=init, cls=new_class):
+                if cls not in compmgr.components:
+                    compmgr.components[cls] = self
+                    if init:
+                        init(self)
+            maybe_init._original = init
+            new_class.__init__ = maybe_init
+
+        if d.get('abstract'):
+            # Don't put abstract component classes in the registry
+            return new_class
+
+        ComponentMeta._components.append(new_class)
+        for interface in d.get('_implements', []):
+            ComponentMeta._registry.setdefault(interface, []).append(new_class)
+        for base in [base for base in bases if hasattr(base, '_implements')]:
+            for interface in base._implements:
+                ComponentMeta._registry.setdefault(interface, []).append(new_class)
+
+        return new_class
+
+
+_implements = []
+
+def implements(*interfaces):
+    """Can be used in the class definiton of `Component` subclasses to declare
+    the extension points that are extended.
+    """
+    _implements.extend(interfaces)
+
+
+class Component(object):
+    """Base class for components.
+
+    Every component can declare what extension points it provides, as well as
+    what extension points of other components it extends.
+    """
+    __metaclass__ = ComponentMeta
+
+    def __new__(cls, *args, **kwargs):
+        """Return an existing instance of the component if it has already been
+        activated, otherwise create a new instance.
+        """
+        # If this component is also the component manager, just invoke that
+        if issubclass(cls, ComponentManager):
+            self = super(Component, cls).__new__(cls)
+            self.compmgr = self
+            return self
+
+        # The normal case where the component is not also the component manager
+        compmgr = args[0]
+        self = compmgr.components.get(cls)
+        if self is None:
+            self = super(Component, cls).__new__(cls)
+            self.compmgr = compmgr
+            compmgr.component_activated(self)
+        return self
+
+
+class ComponentManager(object):
+    """The component manager keeps a pool of active components."""
+
+    def __init__(self):
+        """Initialize the component manager."""
+        self.components = {}
+        self.enabled = {}
+        if isinstance(self, Component):
+            self.components[self.__class__] = self
+
+    def __contains__(self, cls):
+        """Return wether the given class is in the list of active components."""
+        return cls in self.components
+
+    def __getitem__(self, cls):
+        """Activate the component instance for the given class, or return the
+        existing the instance if the component has already been activated."""
+        if cls not in self.enabled:
+            self.enabled[cls] = self.is_component_enabled(cls)
+        if not self.enabled[cls]:
+            return None
+        component = self.components.get(cls)
+        if not component:
+            if cls not in ComponentMeta._components:
+                raise TelemetaError, 'Component "%s" not registered' % cls.__name__
+            try:
+                component = cls(self)
+            except TypeError, e:
+                raise TelemetaError, 'Unable to instantiate component %r (%s)' \
+                                 % (cls, e)
+        return component
+
+    def component_activated(self, component):
+        """Can be overridden by sub-classes so that special initialization for
+        components can be provided.
+        """
+
+    def is_component_enabled(self, cls):
+        """Can be overridden by sub-classes to veto the activation of a
+        component.
+
+        If this method returns False, the component with the given class will
+        not be available.
+        """
+        return True
index cf87ccdfeaceafa39887adfe7afb178f57a3bc6f..daad1e77d5e4b3fccfbee2d198c8abab60ee05d0 100644 (file)
 {% if collection %}\r
 \r
 {% block submenu %}\r
-    <div><a href="{% url telemeta-collection-dublincore collection.public_id %}">Dublin Core</a></div>\r
+    <div>\r
+    <a href="{% url telemeta-collection-detail-edit collection.public_id %}"><button>EDIT</button></a>\r
+    <a href="{% url telemeta-collection-dublincore collection.public_id %}">Dublin Core</a>\r
+    </div>\r
 {% endblock %}\r
 \r
 {% block content %}\r
index d505c7785495ba6afb3e545208ba312cf3dd8059..1d099886a15a54445388ba79692e1fc0bd800f36 100644 (file)
 {% endblock %}\r
 {% block extra_javascript %}\r
 \r
-<script src="{% url telemeta-js "wz_jsgraphics.js" %}" type="text/javascript"></script>\r
-<script src="{% url telemeta-js "soundmanager2.js" %}" type="text/javascript"></script>\r
-<script src="{% url telemeta-timeside "src/timeside.js" %}" type="text/javascript"></script>\r
-<script src="{% url telemeta-js "player.js" %}" type="text/javascript"></script>\r
-\r
-<script type="text/javascript">\r
-soundManager.url = '{% url telemeta-swf "./" %}';\r
-soundManager.flashVersion = 9;\r
-soundManager.useMovieStar = true; // enable MP4/M4A/AAC\r
-soundManager.debugMode = false;\r
-set_player_image_url('{% url telemeta-item-visualize item.public_id,visualizer_id,"WIDTH","HEIGHT" %}');\r
-load_player({{ item.approx_duration.as_seconds }});\r
-</script>\r
 \r
 {% endblock %}\r
 \r
@@ -38,105 +25,14 @@ load_player({{ item.approx_duration.as_seconds }});
 {% block content %}\r
 \r
 <h3>Item : {{ item }}</h3>\r
-<div class="{% if item.file %}with-rightcol{% endif %}">\r
-\r
-{% if item.file %}\r
-    <div id="player_maximized" class="ts-skin-lab">\r
-        <a href="#" class="toggle">Minimize</a>\r
-        <div class="wazing"></div>\r
-    </div>\r
-    <div id="rightcol">\r
-        <div id="player_minimized" class="ts-skin-lab">\r
-        <a href="#" class="toggle">Maximize</a>\r
-        <div class="wazing"></div>\r
-        <div id="player" class="ts-player">\r
-            <div class="ts-viewer">\r
-                <div class="ts-wave">\r
-                    <div class="ts-image-container">\r
-                        <a href="{% url telemeta-item-export item.public_id,"mp3" %}">\r
-                        <img class="ts-image" src="{% url telemeta-item-visualize item.public_id,visualizer_id,360,130 %}"\r
-                          alt="" /></a>\r
-                    </div>\r
-                </div>\r
-            </div>\r
-        </div>\r
-        </div>\r
-\r
-        <div class="item_visualization">\r
-            <form id="visualizer_id_form" method="get" action="#">\r
-                <!--\r
-                <select name="visualizer_id" onchange="this.form.submit()">\r
-                    {% for v in visualizers %}\r
-                    <option value="{{ v.id }}" {% ifequal v.id visualizer_id %} selected="selected" {% endifequal %}>\r
-                    {{v.name}}</option>\r
-                    {% endfor %}\r
-                </select>\r
-                -->\r
-                <select id="visualizer_id" name="visualizer_id">\r
-                    {% for v in visualizers %}\r
-                    <option value="{% url telemeta-item-visualize item.public_id,v.id,"WIDTH","HEIGHT" %}">\r
-                    {{v.name}}</option>\r
-                    {% endfor %}\r
-                </select>\r
-                <input type="submit" value="Set" />\r
-            </form>\r
-\r
-          <div class="analyzer">\r
-            <table width="100%">\r
-             <tr class="analyzer-title">\r
-              <td>Property</td>\r
-              <td>Value</td>\r
-              <td>Unit</td>\r
-             <tr>\r
-            {% for analyser in analysers %}\r
-             <tr class="analyzer-line">\r
-              <td>\r
-                {{ analyser.name }}\r
-              </td>\r
-              <td>\r
-                {{ analyser.value }}\r
-              </td>\r
-              <td>\r
-                {{ analyser.unit }}\r
-              </td>\r
-            </tr>\r
-            {% endfor %}\r
-           </table>\r
-         </div>\r
-<!--\r
-        <form method="get" action="#">\r
-            <p>&nbsp;Vamp plugin analysis</p>\r
-            <select name="vamp_id">\r
-            {% for plugin in vamp_plugins %}\r
-            <option value="{{ plugin }}" {% ifequal plugin vamp_id %} selected="selected" {% endifequal %}>\r
-            {{ plugin }}</option>\r
-            {% endfor %}\r
-            </select>\r
-            <input type="submit" value="Get" />\r
-        </form>\r
--->\r
-        </div>\r
-\r
-        {% if audio_export_enabled %}\r
-        <div class="exporter">\r
-            <p>{% trans "Download:" %}\r
-            {% for format in export_formats %}\r
-            <a href="{% url telemeta-item-export item.public_id,format.extension %}">{{ format.name }}</a>\r
-            {% endfor %}</p>\r
-        </div>\r
-        {% endif %}\r
-\r
-    </div>\r
-{% endif %}\r
 \r
 <div class="infos">\r
 <form method="POST" action="">{% csrf_token %}\r
-    {{ formset }}\r
+     {{ formset }}\r
 <button type="submit">SAVE</button>\r
 </form>\r
 </div>\r
 \r
-</div> <!-- with-rightcol -->\r
 \r
 {% endblock %}\r
 {% else %}\r
index 9e6b3a01368dbf5378ff794a768a3be17c00139c..0d9fb499d3b15f94a643b2a58e15734645c858f7 100644 (file)
@@ -108,6 +108,8 @@ urlpatterns = patterns('',
         web_view.collection_playlist, 
         dict(template="telemeta/collection.m3u", mimetype="audio/mpegurl"),
         name="telemeta-collection-m3u"),
+    url(r'^collections/(?P<public_id>[A-Za-z0-9._-]+)/edit/$', web_view.collection_detail_edit,
+        dict(template='telemeta/collection_detail_edit.html'), name="telemeta-collection-detail-edit"),
 
     # search
     url(r'^search/$', web_view.search, name="telemeta-search"),
index 6d9ffe42689c773d684ecd58812ee9bddc476113..2ae4af7dd04170ed79b82501f46ba3d0a6a6ea9d 100644 (file)
@@ -109,15 +109,24 @@ class WebView(object):
                     'items': items})
         return HttpResponse(template.render(context))
 
-    def collection_detail(self, request, public_id, template=''):
+    def collection_detail(self, request, public_id, template='telemeta/collection_detail.html'):
         collection = MediaCollection.objects.get(public_id=public_id)
         return render(request, template, {'collection': collection})
 
+    def collection_detail_edit(self, request, public_id, template='telemeta/collection_detail_edit.html'):
+        collection = MediaCollection.objects.get(public_id=public_id)
+        MediaCollectionFormSet = modelformset_factory(MediaCollection)
+        if request.method == 'POST':
+            formset = MediaCollectionFormSet(request.POST, request.FILES, queryset=MediaCollection.objects.filter(code=public_id))
+            if formset.is_valid():
+                formset.save()
+        else:
+            formset = MediaCollectionFormSet(queryset=MediaCollection.objects.filter(code=public_id))
+        return render(request, template, {'collection': collection, "formset": formset,})
 
     def item_detail(self, request, public_id, template='telemeta/mediaitem_detail.html'):
         """Show the details of a given item"""
         item = MediaItem.objects.get(public_id=public_id)
-        print 'ok'
         formats = []
         for encoder in self.encoders:
             formats.append({'name': encoder.format(), 'extension': encoder.file_extension()})
@@ -130,51 +139,8 @@ class WebView(object):
         else:
             grapher_id = 'waveform'
         
-        analyze_file = public_id + '.xml'
-        
-        if self.cache.exists(analyze_file):
-            analyzers = self.cache.read_analyzer_xml(analyze_file)
-            if not item.approx_duration:
-                for analyzer in analyzers:
-                    if analyzer['id'] == 'duration':
-                        value = analyzer['value']
-                        time = value.split(':')
-                        time[2] = time[2].split('.')[0]
-                        time = ':'.join(time)
-                        item.approx_duration = time
-                        item.save()
-        else:
-            analyzers = []
-            analyzers_sub = []
-            if item.file:
-                decoder  = timeside.decoder.FileDecoder(item.file.path)
-                pipe = decoder
-                
-                for analyzer in self.analyzers:
-                    subpipe = analyzer()
-                    analyzers_sub.append(subpipe)
-                    pipe = pipe | subpipe
-                    
-                pipe.run()
-                
-                mime_type = decoder.format()
-                analyzers.append({'name': 'Mime type', 'id': 'mime_type', 'unit': '', 'value': mime_type})
-                    
-                for analyzer in analyzers_sub:
-                    value = analyzer.result()
-                    if analyzer.id() == 'duration':
-                        approx_value = int(round(value))
-                        item.approx_duration = approx_value
-                        item.save()
-                        value = datetime.timedelta(0,value)
-                        
-                    analyzers.append({'name':analyzer.name(),
-                                      'id':analyzer.id(),
-                                      'unit':analyzer.unit(),
-                                      'value':str(value)})
-                  
-            self.cache.write_analyzer_xml(analyzers, analyze_file)
-            
+        analyzers = self.item_analyze(item)
+   
         return render(request, template, 
                     {'item': item, 'export_formats': formats, 
                     'visualizers': graphers, 'visualizer_id': grapher_id,'analysers': analyzers,  #FIXME analysers
@@ -184,7 +150,6 @@ class WebView(object):
     def item_detail_edit(self, request, public_id, template='telemeta/mediaitem_detail_edit.html'):
         """Show the details of a given item"""
         item = MediaItem.objects.get(public_id=public_id)
-        
         formats = []
         for encoder in self.encoders:
             formats.append({'name': encoder.format(), 'extension': encoder.file_extension()})
@@ -196,7 +161,25 @@ class WebView(object):
             grapher_id = request.REQUEST['grapher_id']
         else:
             grapher_id = 'waveform'
+            
+        analyzers = self.item_analyze(item)
+        
+        MediaItemFormSet = modelformset_factory(MediaItem)
+        if request.method == 'POST':
+            formset = MediaItemFormSet(request.POST, request.FILES, queryset=MediaItem.objects.filter(code=public_id))
+            if formset.is_valid():
+                formset.save()
+        else:
+            formset = MediaItemFormSet(queryset=MediaItem.objects.filter(code=public_id))
+        
+        return render(request, template, 
+                    {'item': item, 'export_formats': formats, 
+                    'visualizers': graphers, 'visualizer_id': grapher_id,'analysers': analyzers,  #FIXME analysers
+                    'audio_export_enabled': getattr(settings, 'TELEMETA_DOWNLOAD_ENABLED', True), "formset": formset, 
+                    })
         
+    def item_analyze(self, item):
+        public_id = item.public_id
         analyze_file = public_id + '.xml'
         
         if self.cache.exists(analyze_file):
@@ -241,24 +224,8 @@ class WebView(object):
                                       'value':str(value)})
                   
             self.cache.write_analyzer_xml(analyzers, analyze_file)
-            
-        MediaItemFormSet = modelformset_factory(MediaItem)
-        if request.method == 'POST':
-            formset = MediaItemFormSet(request.POST, request.FILES, queryset=MediaItem.objects.filter(code=public_id))
-            if formset.is_valid():
-                formset.save()
-                # do something.
-        else:
-            formset = MediaItemFormSet(queryset=MediaItem.objects.filter(code=public_id))
-        
-        return render(request, template, 
-                    {'item': item, 'export_formats': formats, 
-                    'visualizers': graphers, 'visualizer_id': grapher_id,'analysers': analyzers,  #FIXME analysers
-                    'audio_export_enabled': getattr(settings, 'TELEMETA_DOWNLOAD_ENABLED', True), "formset": formset, 
-                    })
+        return analyzers
         
-    def item_analyze(self):
-        pass
         
     def item_visualize(self, request, public_id, visualizer_id, width, height):
         item = MediaItem.objects.get(public_id=public_id)
@@ -606,10 +573,6 @@ class WebView(object):
     def logout(self, request):
         auth.logout(request)
         return redirect('telemeta-home')
-
-    @jsonrpc_method('telemeta.add_marker_test')
-    def add_marker_test(request,marker):
-        print "Received"
         
     @jsonrpc_method('telemeta.add_marker')
     def add_marker(request, marker):