From: olivier <> Date: Fri, 18 May 2007 19:17:37 +0000 (+0000) Subject: - added collection playlists in m3u and xspf formats X-Git-Tag: 1.1~935 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=879d772cce6420403d442244c40f0f81e894fd19;p=telemeta.git - added collection playlists in m3u and xspf formats - embedded flash mp3 player in both collection and item displays. Remark: there are two players available, you can switch them in the templates - other fixes --- diff --git a/telemeta/htdocs/css/telemeta.css b/telemeta/htdocs/css/telemeta.css index b21658f7..caaaad4e 100644 --- a/telemeta/htdocs/css/telemeta.css +++ b/telemeta/htdocs/css/telemeta.css @@ -36,16 +36,16 @@ a img { border: none; } #quick_search_pattern { } -.item_visualization { +.item_visualization, #collection_player { clear: right; float: right; padding: 1ex; margin-top: 1em; + margin-left: 1em; } .item_visualization select { width: 200px; } .item_visualization img { width: 300px; border: solid 1px black; } - /* Styles for tabular listings (stolen from trac) */ table.listing { clear: both; diff --git a/telemeta/htdocs/js/swfobject.js b/telemeta/htdocs/js/swfobject.js new file mode 100755 index 00000000..e7edd42c --- /dev/null +++ b/telemeta/htdocs/js/swfobject.js @@ -0,0 +1,8 @@ +/** + * SWFObject v1.5: Flash Player detection and embed - http://blog.deconcept.com/swfobject/ + * + * SWFObject is (c) 2007 Geoff Stearns and is released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + */ +if(typeof deconcept=="undefined"){var deconcept=new Object();}if(typeof deconcept.util=="undefined"){deconcept.util=new Object();}if(typeof deconcept.SWFObjectUtil=="undefined"){deconcept.SWFObjectUtil=new Object();}deconcept.SWFObject=function(_1,id,w,h,_5,c,_7,_8,_9,_a){if(!document.getElementById){return;}this.DETECT_KEY=_a?_a:"detectflash";this.skipDetect=deconcept.util.getRequestParameter(this.DETECT_KEY);this.params=new Object();this.variables=new Object();this.attributes=new Array();if(_1){this.setAttribute("swf",_1);}if(id){this.setAttribute("id",id);}if(w){this.setAttribute("width",w);}if(h){this.setAttribute("height",h);}if(_5){this.setAttribute("version",new deconcept.PlayerVersion(_5.toString().split(".")));}this.installedVer=deconcept.SWFObjectUtil.getPlayerVersion();if(!window.opera&&document.all&&this.installedVer.major>7){deconcept.SWFObject.doPrepUnload=true;}if(c){this.addParam("bgcolor",c);}var q=_7?_7:"high";this.addParam("quality",q);this.setAttribute("useExpressInstall",false);this.setAttribute("doExpressInstall",false);var _c=(_8)?_8:window.location;this.setAttribute("xiRedirectUrl",_c);this.setAttribute("redirectUrl","");if(_9){this.setAttribute("redirectUrl",_9);}};deconcept.SWFObject.prototype={useExpressInstall:function(_d){this.xiSWFPath=!_d?"expressinstall.swf":_d;this.setAttribute("useExpressInstall",true);},setAttribute:function(_e,_f){this.attributes[_e]=_f;},getAttribute:function(_10){return this.attributes[_10];},addParam:function(_11,_12){this.params[_11]=_12;},getParams:function(){return this.params;},addVariable:function(_13,_14){this.variables[_13]=_14;},getVariable:function(_15){return this.variables[_15];},getVariables:function(){return this.variables;},getVariablePairs:function(){var _16=new Array();var key;var _18=this.getVariables();for(key in _18){_16[_16.length]=key+"="+_18[key];}return _16;},getSWFHTML:function(){var _19="";if(navigator.plugins&&navigator.mimeTypes&&navigator.mimeTypes.length){if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","PlugIn");this.setAttribute("swf",this.xiSWFPath);}_19="0){_19+="flashvars=\""+_1c+"\"";}_19+="/>";}else{if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","ActiveX");this.setAttribute("swf",this.xiSWFPath);}_19="";_19+="";var _1d=this.getParams();for(var key in _1d){_19+="";}var _1f=this.getVariablePairs().join("&");if(_1f.length>0){_19+="";}_19+="";}return _19;},write:function(_20){if(this.getAttribute("useExpressInstall")){var _21=new deconcept.PlayerVersion([6,0,65]);if(this.installedVer.versionIsValid(_21)&&!this.installedVer.versionIsValid(this.getAttribute("version"))){this.setAttribute("doExpressInstall",true);this.addVariable("MMredirectURL",escape(this.getAttribute("xiRedirectUrl")));document.title=document.title.slice(0,47)+" - Flash Player Installation";this.addVariable("MMdoctitle",document.title);}}if(this.skipDetect||this.getAttribute("doExpressInstall")||this.installedVer.versionIsValid(this.getAttribute("version"))){var n=(typeof _20=="string")?document.getElementById(_20):_20;n.innerHTML=this.getSWFHTML();return true;}else{if(this.getAttribute("redirectUrl")!=""){document.location.replace(this.getAttribute("redirectUrl"));}}return false;}};deconcept.SWFObjectUtil.getPlayerVersion=function(){var _23=new deconcept.PlayerVersion([0,0,0]);if(navigator.plugins&&navigator.mimeTypes.length){var x=navigator.plugins["Shockwave Flash"];if(x&&x.description){_23=new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/,"").replace(/(\s+r|\s+b[0-9]+)/,".").split("."));}}else{if(navigator.userAgent&&navigator.userAgent.indexOf("Windows CE")>=0){var axo=1;var _26=3;while(axo){try{_26++;axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+_26);_23=new deconcept.PlayerVersion([_26,0,0]);}catch(e){axo=null;}}}else{try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");}catch(e){try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");_23=new deconcept.PlayerVersion([6,0,21]);axo.AllowScriptAccess="always";}catch(e){if(_23.major==6){return _23;}}try{axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");}catch(e){}}if(axo!=null){_23=new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));}}}return _23;};deconcept.PlayerVersion=function(_29){this.major=_29[0]!=null?parseInt(_29[0]):0;this.minor=_29[1]!=null?parseInt(_29[1]):0;this.rev=_29[2]!=null?parseInt(_29[2]):0;};deconcept.PlayerVersion.prototype.versionIsValid=function(fv){if(this.majorfv.major){return true;}if(this.minorfv.minor){return true;}if(this.rev=0;i--){_2f[i].style.display="none";for(var x in _2f[i]){if(typeof _2f[i][x]=="function"){_2f[i][x]=function(){};}}}};if(deconcept.SWFObject.doPrepUnload){if(!deconcept.unloadSet){deconcept.SWFObjectUtil.prepUnload=function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){};window.attachEvent("onunload",deconcept.SWFObjectUtil.cleanupSWFs);};window.attachEvent("onbeforeunload",deconcept.SWFObjectUtil.prepUnload);deconcept.unloadSet=true;}}if(!document.getElementById&&document.all){document.getElementById=function(id){return document.all[id];};}var getQueryParamValue=deconcept.util.getRequestParameter;var FlashObject=deconcept.SWFObject;var SWFObject=deconcept.SWFObject; \ No newline at end of file diff --git a/telemeta/htdocs/swf/mp3player.swf b/telemeta/htdocs/swf/mp3player.swf new file mode 100755 index 00000000..70fca8c2 Binary files /dev/null and b/telemeta/htdocs/swf/mp3player.swf differ diff --git a/telemeta/htdocs/swf/xspf_player.swf b/telemeta/htdocs/swf/xspf_player.swf new file mode 100644 index 00000000..f03790a4 Binary files /dev/null and b/telemeta/htdocs/swf/xspf_player.swf differ diff --git a/telemeta/htdocs/swf/xspf_player_slim.swf b/telemeta/htdocs/swf/xspf_player_slim.swf new file mode 100644 index 00000000..24b36c9d Binary files /dev/null and b/telemeta/htdocs/swf/xspf_player_slim.swf differ diff --git a/telemeta/models.py b/telemeta/models.py index f2d47579..689dde5b 100644 --- a/telemeta/models.py +++ b/telemeta/models.py @@ -11,6 +11,7 @@ from django.db import models from django.db.models import Q from django.core.exceptions import ObjectDoesNotExist from django.core import validators +from django.conf import settings import telemeta from telemeta.core import * @@ -127,6 +128,14 @@ class MediaCollection(models.Model, MediaCore): ) return resource + def has_mediafile(self): + "Tell wether this collection has any media files attached to its items" + items = self.items.all() + for item in items: + if item.file: + return True + return False + def __str__(self): #return self.title return self.id @@ -215,6 +224,17 @@ class MediaItem(models.Model, MediaCore): ) return resource + def get_duration(self): + if self.file: + import wave + media = wave.open(settings.MEDIA_ROOT + "/" + self.file, "rb") + duration = media.getnframes() / media.getframerate() + media.close() + else: + duration = 0 + + return duration + def __str__(self): return self.title diff --git a/telemeta/templates/base.html b/telemeta/templates/base.html index 7ed55b94..0fb1e10e 100644 --- a/telemeta/templates/base.html +++ b/telemeta/templates/base.html @@ -4,6 +4,7 @@ Telemeta {% block extra_style %}{% endblock %} +{% block extra_javascript %}{% endblock %} {% load i18n %} diff --git a/telemeta/templates/base_xspf.xml b/telemeta/templates/base_xspf.xml new file mode 100644 index 00000000..af4166b6 --- /dev/null +++ b/telemeta/templates/base_xspf.xml @@ -0,0 +1,9 @@ + + +{% block listinfo %}{% endblock %} + + {% block tracklist %}{% endblock %} + + + + diff --git a/telemeta/templates/collection.m3u b/telemeta/templates/collection.m3u new file mode 100644 index 00000000..e648141f --- /dev/null +++ b/telemeta/templates/collection.m3u @@ -0,0 +1,3 @@ +#EXTM3U{% load telemeta_utils %}{% for item in collection.items.all %} +#EXTINF:{{ item.get_duration }},{{ item.title }} +http://{{ host }}{% url telemeta-item-export item.id|urlencode,"MP3" %} {% endfor %} diff --git a/telemeta/templates/collection_detail.html b/telemeta/templates/collection_detail.html index f5526883..eb4e2eac 100644 --- a/telemeta/templates/collection_detail.html +++ b/telemeta/templates/collection_detail.html @@ -1,6 +1,10 @@ {% extends "base.html" %} {% load telemeta_utils %} +{% block extra_javascript %} + +{% endblock %} + {% block submenu %} Dublin Core @@ -8,6 +12,36 @@ {% block content %} {% if object %} + {% if object.has_mediafile %} +
+

Listen to this collection + (M3U, + XSPF)

+ {% if 0 %} {# Use 1/0 for alternate player #} + + + + + {% else %} + +

+ Get Flash to see this player. +

+ + {% endif %} +
+ {% endif %} +

Collection: {{ object.title }}

    {% for field in object.to_dict|tolist %} @@ -18,16 +52,23 @@ {% endifnotequal %} {% endfor %}
+

Items

-
    - {% for item in object.items.all %} -
  • {{ item.creator }} - {{ item.title }} - View - Edit -
  • - {% endfor %} -
+ {% with object.items.all as items %} + {% if items %} +
    + {% for item in items %} +
  • {{ item.creator }} - {{ item.title }} + View + Edit +
  • + {% endfor %} +
+ {% else %} +

No items

+ {% endif %} + {% endwith %} {% else %}

No such collection

{% endif %} diff --git a/telemeta/templates/collection_xspf.xml b/telemeta/templates/collection_xspf.xml new file mode 100644 index 00000000..da067d4a --- /dev/null +++ b/telemeta/templates/collection_xspf.xml @@ -0,0 +1,23 @@ +{% extends "base_xspf.xml" %} +{% load telemeta_utils %} + +{% block listinfo %} +{% with collection.to_dublincore.flatten as dc %} + {{ dc.creator }} + {{ dc.title }} + http://{{ host }}{% url telemeta-collection-detail collection.id|urlencode %} +{% endwith %} +{% endblock %} + +{% block tracklist %} +{% for item in collection.items.all %} + + {{ item.title }} + mp3 + http://{{ host }}{% url telemeta-item-export item.id|urlencode,"MP3" %} + {{ item.get_duration|mul:1000 }} + http://{{ host }}{% url telemeta-item-detail item.id|urlencode %} + +{% endfor %} +{% endblock %} + diff --git a/telemeta/templates/mediaitem_detail.html b/telemeta/templates/mediaitem_detail.html index c483853a..aeabc635 100644 --- a/telemeta/templates/mediaitem_detail.html +++ b/telemeta/templates/mediaitem_detail.html @@ -1,6 +1,10 @@ {% extends "base.html" %} {% load telemeta_utils %} +{% block extra_javascript %} + +{% endblock %} + {% block submenu %} Dublin Core @@ -8,7 +12,31 @@ {% block content %} {% if item %} + {% if item.file %}
+ {% if 0 %} {# Use 1/0 for alternate player #} + + + +
+ {% else %} + +

+ Get Flash to see this player. +

+ + {% endif %} +
-

Item: {{ item.title }}

-
    - {% for field in item.to_dict|tolist %} - {% ifnotequal field.name "id" %} - {% ifnotequal field.name "title" %} - {% ifnotequal field.name "file" %} - -
  • {{ field.name }} : - {% ifequal field.name "collection" %} - - {{ field.value }} - {% else %} - {{ field.value }} - {% endifequal %} -
  • - - {% endifnotequal %} - {% endifnotequal %} - {% endifnotequal %} - {% endfor %} -
- Download: - {% for format in export_formats %} - {{ format }} - {% endfor %} + {% endif %} + +

Item: {{ item.title }}

+
    + {% for field in item.to_dict|tolist %} + {% ifnotequal field.name "id" %} + {% ifnotequal field.name "title" %} + {% ifnotequal field.name "file" %} + +
  • {{ field.name }} : + {% ifequal field.name "collection" %} + + {{ field.value }} + {% else %} + {{ field.value }} + {% endifequal %} +
  • + + {% endifnotequal %} + {% endifnotequal %} + {% endifnotequal %} + {% endfor %} +
+ Download: + {% for format in export_formats %} + {{ format }} + {% endfor %} {% else %}

No such item

{% endif %} diff --git a/telemeta/templates/mediaitem_xspf.xml b/telemeta/templates/mediaitem_xspf.xml new file mode 100644 index 00000000..38293f54 --- /dev/null +++ b/telemeta/templates/mediaitem_xspf.xml @@ -0,0 +1,13 @@ +{% extends "base_xspf.xml" %} +{% load telemeta_utils %} + +{% block tracklist %} + + {{ item.title }} + mp3 + http://{{ host }}{% url telemeta-item-export item.id|urlencode,"MP3" %} + {{ item.get_duration|mul:1000 }} + http://{{ host }}{% url telemeta-item-detail item.id|urlencode %} + +{% endblock %} + diff --git a/telemeta/templatetags/telemeta_utils.py b/telemeta/templatetags/telemeta_utils.py index e52bb213..d2dcfa37 100644 --- a/telemeta/templatetags/telemeta_utils.py +++ b/telemeta/templatetags/telemeta_utils.py @@ -16,4 +16,9 @@ def tolist(dict): list.append({'name': k, 'value': v}) return list +@register.filter +def mul(value, arg): + "Multiply a numeric value" + return value * arg + diff --git a/telemeta/urls.py b/telemeta/urls.py index ed316240..c22bf1fa 100644 --- a/telemeta/urls.py +++ b/telemeta/urls.py @@ -39,12 +39,16 @@ urlpatterns = patterns('', url(r'^items/(?P' + i_ex + ')/dc/xml/$', web_view.item_detail, {'format': 'dublin_core_xml'}, name="telemeta-item-dublincore-xml"), - url(r'^items/(?P' + i_ex + ')/download/(?P[0-9A-Z]+)/$', + url(r'^items/(?P' + i_ex + ')/download.(?P[0-9A-Z]+)$', web_view.item_export, name="telemeta-item-export"), url(r'^items/(?P' + i_ex + ')/visualize/(?P[0-9a-z]+)/$', web_view.item_visualize, name="telemeta-item-visualize"), + url(r'^items/(?P' + i_ex + ')/item_xspf.xml$', + web_view.item_playlist, + dict(template="mediaitem_xspf.xml", mimetype="application/xspf+xml"), + name="telemeta-item-xspf"), # collections url(r'^collections/$', 'django.views.generic.list_detail.object_list', @@ -62,6 +66,14 @@ urlpatterns = patterns('', 'django.views.generic.list_detail.object_detail', dict(all_collections, template_name="collection_detail_dc.html"), name="telemeta-collection-dublincore"), + url(r'^collections/(?P' + c_ex + ')/collection_xspf.xml$', + web_view.collection_playlist, + dict(template="collection_xspf.xml", mimetype="application/xspf+xml"), + name="telemeta-collection-xspf"), + url(r'^collections/(?P' + c_ex + ')/collection.m3u$', + web_view.collection_playlist, + dict(template="collection.m3u", mimetype="audio/mpegurl"), + name="telemeta-collection-m3u"), # search url(r'^search/$', web_view.quick_search, name="telemeta-quicksearch"), @@ -93,4 +105,8 @@ urlpatterns = patterns('', {'document_root': './telemeta/htdocs/css'}), (r'^images/(?P.*)$', 'django.views.static.serve', {'document_root': './telemeta/htdocs/images'}), + (r'^js/(?P.*)$', 'django.views.static.serve', + {'document_root': './telemeta/htdocs/js'}), + (r'^swf/(?P.*)$', 'django.views.static.serve', + {'document_root': './telemeta/htdocs/swf'}), ) diff --git a/telemeta/views/web.py b/telemeta/views/web.py index 2b938999..a59cf912 100644 --- a/telemeta/views/web.py +++ b/telemeta/views/web.py @@ -190,6 +190,24 @@ class WebView(Component): record.save() return self.edit_enumeration(request, enumeration_id) + + def collection_playlist(self, request, collection_id, template, mimetype): + collection = MediaCollection.objects.get(id__exact=collection_id) + if not collection: + raise Http404 + + template = loader.get_template(template) + context = Context({'collection': collection, 'host': request.META['HTTP_HOST']}) + return HttpResponse(template.render(context), mimetype=mimetype) + + def item_playlist(self, request, item_id, template, mimetype): + item = MediaItem.objects.get(id__exact=item_id) + if not item: + raise Http404 + + template = loader.get_template(template) + context = Context({'item': item, 'host': request.META['HTTP_HOST']}) + return HttpResponse(template.render(context), mimetype=mimetype)