Index: telemeta/htdocs/timeside/js/player.js
===================================================================
--- telemeta/htdocs/timeside/js/player.js	(revision 8868a6906f90181bdda0b55163556ab9d6571a53)
+++ telemeta/htdocs/timeside/js/player.js	(revision 91bae444089bd20819a896a75ec912463cdd0ea7)
@@ -30,5 +30,5 @@
 //playerDiv, sound, durationInMsec, visualizers, markerMap);
 Timeside.classes.Player = Timeside.classes.TimesideClass.extend({
-    
+
     //sound duration is in milliseconds because the soundmanager has that unit,
     //player (according to timeside syntax) has durations in seconds
@@ -64,5 +64,5 @@
 
         var onReadyWithImage = configObject.onReadyWithImage;
-        
+
         if(typeof onReadyWithImage === 'function'){
             var onReadyWithImageNamespace = 'imgRefreshed.temp_'+new Date().getTime(); //get an unique namespace
@@ -110,5 +110,5 @@
                 if(sMan.canPlayURL(soundOptions.url)){ //this actually checks only if the url is well formed, not if the file is there
                     //check if we specified a valid sound duration, otherwise the sound must be loaded
-                    
+
                     sound = sMan.createSound(soundOptions);
                 }else{
@@ -160,10 +160,10 @@
         this.playState = 0; //0: not playing, 1: loading, 2:buffering, 3 playing (sound heard)
         //container is the div #player
-       
+
         this.getContainer = function(){
             return container;
         };
-        
-        
+
+
 
         var sd = this.toSec(soundDurationInMsec);
@@ -171,11 +171,11 @@
             return sd;
         };
-        
+
         this.soundPosition =  sound.position ? this.toSec(sound.position) : 0;
- 
-       
-        
+
+
+
         //
-        
+
         //initializing markermap and markerui
         var map = new Timeside.classes.MarkerMap();
@@ -191,5 +191,5 @@
             }
         }
-       
+
         //build the innerHTML as array, then join it. This is usually faster than string concatenation in some browsers.
         //Note that the player image (see below) is not created now, however, if it was, it should be given a src
@@ -221,5 +221,5 @@
 
         container.html(html.join(''));
-        
+
         var control = container.find('.ts-control');
 
@@ -421,9 +421,9 @@
         var oldSoundPosition = this.soundPosition;
         this.soundPosition = newPositionInSeconds;
-        
+
         //resume playing if it was playing:
         if(wasPlaying){
             var player = this;
-            
+
             //delay a little bit the play resume, this might avoid fast pointer repositioning
             //(it should not be the case, but it happens. why??)
@@ -446,5 +446,5 @@
     //markerCrossedOffsetMargin : 0.5,
     play : function(){
-        
+
         if(this.soundErrorMsg){
             alert(this.soundErrorMsg);
@@ -459,5 +459,5 @@
             return false;
         }
-        
+
 
         var fireOnMarkerPosition = function(seconds){}; //does nothing by default
@@ -496,5 +496,5 @@
                             data.nextMarkerTimeInterval = marker ? [offs-margin, offs+margin] : undefined;
                             player.fire('markerCrossed',data);
-                            
+
                             if(idx<len){
                                 intervalUpperBound =  offs+margin;
@@ -514,5 +514,5 @@
         var bufferingString = this.msgs.buffering;
         var loadingString = this.msgs.loading;
-        
+
         var updateWaitBar = this.setWait;
         //building immediately data events to be passed instead of bulding them in the loop whileplaying
@@ -548,7 +548,7 @@
             this.fire('playStateChanged',loadData);
         }
-        
+
         var playOptions = {
-            
+
             position: sPosInMsec,
             whileplaying: function(){
@@ -556,5 +556,5 @@
                 var sPos = this.position;
                 var buffering = this.isBuffering || typeof sPos != 'number' || sPos < sPosInMsec;
-                
+
                 //var buffering = this.isBuffering; //this refers to the soundmanager sound obj
                 //Now, what are we doing here below? we could simply check whether is buffering or not..
@@ -600,5 +600,5 @@
             },
             onfinish: function() {
-                
+
                 //whileplaying is NOT called onsinfish. We must update the pointer:
                 //note that for small length sounds (wg, 5 secs) the pointer shifts abruptly from the last
@@ -680,5 +680,5 @@
     setWait: function(msg){
         var wait = undefined;
-      
+
         wait = this.getWaitElement();
         if(!wait || msg === undefined){
@@ -690,5 +690,5 @@
 
         var visible = wait.css('display') != 'none';
-        
+
         if(msg && !visible){
             wait.show();
@@ -728,9 +728,9 @@
         },100);
     },
-    
+
     resize: function() {
         var height;
         var container = this.getContainer();
-        
+
         var wave = container.find('.ts-wave');
 
@@ -773,5 +773,5 @@
         var imageC = container.find('.ts-image-container');
         var image = imageC.find('.ts-image');
-        
+
 
         var size = this.getImageSize();
@@ -785,7 +785,7 @@
             return;
         }
-        
+
         var player= this;
-        
+
         if(imageNotYetCreated){
             image = this.$J('<img/>');
@@ -824,5 +824,5 @@
         this.fire('imgRefreshing');
         image.attr('src', imgSrc);
-       
+
     },
     getImageSize: function(){
@@ -880,5 +880,5 @@
             }
         }
-        
+
         if(idx< len){
             offset = markers[idx].offset;
@@ -1007,7 +1007,7 @@
         //        map.clear();
         //        ruler.clear();
-       
+
         var rulerAdd = ruler.add;
-            
+
         if(markers){
             //add markers to the map. No listeners associated to it (for the moment)
@@ -1021,5 +1021,5 @@
             });
         }
-        
+
         //the function above calls map.add:
         //add bindings when adding a marker:
@@ -1044,5 +1044,5 @@
 
         //and now add a binding to the map when we move a marker:
-          
+
         map.bind('move', function(data){
             var from = data.fromIndex;
Index: telemeta/htdocs/timeside/js/timeside.js
===================================================================
--- telemeta/htdocs/timeside/js/timeside.js	(revision 8868a6906f90181bdda0b55163556ab9d6571a53)
+++ telemeta/htdocs/timeside/js/timeside.js	(revision 91bae444089bd20819a896a75ec912463cdd0ea7)
@@ -90,5 +90,5 @@
  * (Inspired by base2 and Prototype)
  */
- 
+
 /*
  * In few words: the lightest and most-comprehensive way to implement inhertance and OOP in javascript. Usages can be found below.
@@ -119,5 +119,5 @@
  *       }
  *       this.alert = function(){   //another public method, !!!WARNING: this will be put in the MyClass scope (NOT in the prototype)
- *           alert('ok');           
+ *           alert('ok');
  *       }
  *   },
@@ -132,5 +132,5 @@
  *  }
  *  alert: function(){                  //override a method
- *      this._super();                  //call the super method, ie alerts 'no'. WARNING: However, as long as there is an alert written 
+ *      this._super();                  //call the super method, ie alerts 'no'. WARNING: However, as long as there is an alert written
  *                                      //in the init method of the superclass (see above), THAT method will be called
  *  }
@@ -210,5 +210,5 @@
         // Populate our constructed prototype object
         Class.prototype = prototype;
-        
+
         // Enforce the constructor to be what we expect
         Class.constructor = Class;
@@ -234,5 +234,5 @@
         this.listenersMap={};
     },
-    
+
     cssPrefix : 'ts-', //actually almost uneuseful, still here for backward compatibility with old code (TODO: remove?)
     $J : jQuery, //reference to jQuery for faster lookup inside methods
@@ -266,5 +266,5 @@
             };
         }
-        
+
         if(listenersMap.hasOwnProperty(eventType)){
             listenersMap[eventType].push(callback);
@@ -343,5 +343,5 @@
         }
     },
-    
+
     /*
      *formats (ie returns a string representation of) a time which is in the form seconds,milliseconds (eg 07.6750067)
@@ -364,5 +364,5 @@
             formatArray = ['mm','ss'];
         }
-        
+
         //marker offset is in float format second.decimalPart
         var pInt = parseInt;
@@ -376,5 +376,5 @@
         var seconds = pInt(time);
         time-=seconds;
-        
+
         //here below the function to format a number
         //ceilAsPowerOfTen is the ceil specifiedas integer indicating the relative power of ten
@@ -476,5 +476,5 @@
     //3) each(m,n,callback) iterates over the elements from m (inclusive) to n-1 (inclusive) executing callback
 
-    //NOTE: writing   each : function(startInclusive, endExclusive, callback) throws an error in chrome, as the last 
+    //NOTE: writing   each : function(startInclusive, endExclusive, callback) throws an error in chrome, as the last
     //argument (even if it is a function) is a number. Why?????
     //Anyway, we write the function arguments as empty
@@ -513,5 +513,5 @@
             callback(i,me[i]);
         }
-    
+
     },
 
@@ -696,5 +696,5 @@
             Timeside.utils.flashFailed = true;
             //end('SoundManager error. If your browser does not support HTML5, Flash player (version '+soundManager.flashVersion+'+) must be installed.\nIf flash is installed, try to:\n - Reload the page\n - Empty the cache (see browser preferences/options/tools) and reload the page\n - Restart the browser');
-            
+
             //and load all anyway:
             loadAll();
Index: telemeta/management/commands/telemeta-cleanup.py
===================================================================
--- telemeta/management/commands/telemeta-cleanup.py	(revision 91bae444089bd20819a896a75ec912463cdd0ea7)
+++ telemeta/management/commands/telemeta-cleanup.py	(revision 91bae444089bd20819a896a75ec912463cdd0ea7)
@@ -0,0 +1,33 @@
+from optparse import make_option
+from django.conf import settings
+from django.core.management.base import BaseCommand, CommandError
+from telemeta.models import *
+from telemeta.util.unaccent import unaccent
+import logging
+import codecs
+
+class Command(BaseCommand):
+    help = "Cleanup DB : multiple analyses, data cache, export cache, etc.."
+    args = "None"
+
+    def handle(self, *args, **options):
+
+        items = MediaItem.objects.all()
+        a_counter = 0
+
+        print 'Cleaning multiple analyses per item...'
+        for item in items:
+
+            analyses = MediaItemAnalysis.objects.filter(item=item)
+            ids = []
+            for analysis in analyses:
+                id = analysis.analyzer_id
+                if id in ids:
+                    print 'item : ' + item.code + ' analyzer_id : ' + id
+                    analysis.delete()
+                    a_counter += 1
+                else:
+                    ids.append(id)
+
+        print "Done, cleaned %s analyses" % str(a_counter)
+
