chapters to annotations first step
authorcavaliet
Fri, 21 Mar 2014 15:21:15 +0100
changeset 24 dda5c321379a
parent 23 1d61b91b0b46
child 25 21840e43dcc8
chapters to annotations first step
src/spel/static/spel/js/spectacle.js
src/spel/templates/partial/spel_annotations.html
src/spel/templates/partial/spel_chapters.html
src/spel/views.py
--- a/src/spel/static/spel/js/spectacle.js	Fri Mar 21 11:22:42 2014 +0100
+++ b/src/spel/static/spel/js/spectacle.js	Fri Mar 21 15:21:15 2014 +0100
@@ -297,7 +297,10 @@
 		$('.annotation-results > div.searched-annot:visible').each(function(index){
 			bla.push({data: $(this).attr("data-start"), iri_id: $(this).attr("data-content") }); 
 		});
-		if(bla.length==0){ return; }
+		if(bla.length==0){
+			$(".chapter-results").removeClass("loader");
+			return;
+		}
 		$.post(
 			urlChapters,
 			{
@@ -313,5 +316,38 @@
 			$(".chapter-results").html('<p class="bg-danger">Erreur de chargement</p>');
 		});
 	});
+	
+	// Chapter to annotations management
+	$(".chapter-results").on("click", ".chapter-to-annot", function(){
+		// First we unselect chapter filters
+	    $('option', $('#mulsel4')).each(function(element) { $(this).removeAttr('selected').prop('selected', false); });
+	    $('#mulsel4').multiselect('refresh');
+	    // Then we request
+		$(".annot-results").html("<br/><br/>");
+		$(".annot-results").addClass("loader");
+		var bla = [];
+		$('.chapter-data').each(function(index){
+			bla.push({start: $(this).attr("data-start"), end: $(this).attr("data-end"), iri_id: $(this).attr("data-content") }); 
+		});
+		if(bla.length==0){
+			$(".annotation-results").removeClass("loader");
+			return;
+		}
+		$.post(
+			urlAnnotations,
+			{
+				chapters: JSON.stringify(bla), 
+				csrfmiddlewaretoken: csrf_token
+			}, 
+			function( html ) {
+				$(".annotation-results").removeClass("loader");
+				$(".annotation-results").html(html);
+			}
+		)
+		.fail(function() {
+			$(".annotation-results").removeClass("loader");
+			$(".annotation-results").html('<p class="bg-danger">Erreur de chargement</p>');
+		});
+	});
 
 });
--- a/src/spel/templates/partial/spel_annotations.html	Fri Mar 21 11:22:42 2014 +0100
+++ b/src/spel/templates/partial/spel_annotations.html	Fri Mar 21 15:21:15 2014 +0100
@@ -1,6 +1,9 @@
 {% load static %}
 {% load front_tags %}
 {% load spel_tags %}
+{% if chapter_annots %}
+<p class="btn-info info">Annotations correspondant aux chapitres :</p>
+{% endif %}
 <div class="row">
   <div class="col-md-8">
 	<ul class="list-inline annot-tag-list">
@@ -9,9 +12,11 @@
 	</ul>
 	<p><span class="nb-annotations-found">{{ nb_annotations }}</span> annotation(s) trouvée(s) sur {{ nb_contents }} vidéo(s)</p>
   </div>
+  {% if not chapter_annots %}
   <div class="col-md-4">
-    <button class="annot-to-chapter btn btn-primary multiline btn-sm">Chapitres correspondant aux annotations</button>
+    <button class="annot-to-chapter btn btn-primary multiline btn-xs">Chapitres correspondant aux annotations</button>
   </div>
+  {% endif %}
 </div>
 {% for res in results %}
   {% for s in res.list %}
--- a/src/spel/templates/partial/spel_chapters.html	Fri Mar 21 11:22:42 2014 +0100
+++ b/src/spel/templates/partial/spel_chapters.html	Fri Mar 21 15:21:15 2014 +0100
@@ -4,19 +4,29 @@
 {% if annot_chapters %}
 <p class="bg-primary info">Chapitres correspondant aux annotations :</p>
 {% endif %}
-<ul class="list-inline chapter-tag-list">
-    {% for t in annot_types %}<li class="small searched-tag type">{{ t|remove_tag_key }} <span class="glyphicon glyphicon-remove small"></span></li>{% endfor %}
-    {% for t in mod_scen %}<li class="small searched-tag modscen">{{ t|remove_tag_key }} <span class="glyphicon glyphicon-remove small"></span></li>{% endfor %}
-    {% for t in perso %}<li class="small searched-tag perso">{{ t|remove_tag_key }} <span class="glyphicon glyphicon-remove small"></span></li>{% endfor %}
-</ul>
-<p>{{ segments|length }} segment(s) trouvé(s)</p>
+<div class="row">
+  <div class="col-md-8">
+	<ul class="list-inline chapter-tag-list">
+	    {% for t in annot_types %}<li class="small searched-tag type">{{ t|remove_tag_key }} <span class="glyphicon glyphicon-remove small"></span></li>{% endfor %}
+	    {% for t in mod_scen %}<li class="small searched-tag modscen">{{ t|remove_tag_key }} <span class="glyphicon glyphicon-remove small"></span></li>{% endfor %}
+	    {% for t in perso %}<li class="small searched-tag perso">{{ t|remove_tag_key }} <span class="glyphicon glyphicon-remove small"></span></li>{% endfor %}
+	</ul>
+    <p>{{ segments|length }} segment(s) trouvé(s)</p>
+  </div>
+  {% if not annot_chapters %}
+  <div class="col-md-4">
+    <button class="chapter-to-annot btn btn-info multiline btn-xs">Annotations correspondant aux chapitres</button>
+  </div>
+  {% endif %}
+</div>
 <table class="table table-striped table-condensed tablesorter">
     <thead>
         <tr><th>Type</th><th>Ref texte</th><th>Titre de la vidéo</th><th>&nbsp;</th></tr>
     </thead>
     <tbody>
   {% for s in segments %}
-    <tr><td>{{ s.cutting_id }}</td><td>{{ s.tags|get_tags:"ref_text"|join:', ' }}</td><td>{% if annot_chapters %}{{ s.ct }}{% else %}{{ s.content.title }}{% endif %}</td>
+    <tr class="chapter-data" data-content="{{ s.iri_id }}" data-start="{{ s.start_ts }}" data-end="{{ s.start_ts|add:s.duration }}">
+        <td>{{ s.cutting_id }}</td><td>{{ s.tags|get_tags:"ref_text"|join:', ' }}</td><td>{% if annot_chapters %}{{ s.ct }}{% else %}{{ s.content.title }}{% endif %}</td>
         <td>
           <button type="button" class="popinfo btn btn-xs btn-default" data-trigger="hover" data-container="body" data-toggle="popover" data-placement="auto" 
                   data-content="<strong>Timecodes:</strong> {{ s.start_ts|str_duration }} - {{ s.start_ts|add:s.duration|str_duration }}<br/>{{ s.tags|get_tags:'group'|safe }}"><span class="glyphicon glyphicon-plus-sign"></span></button>
--- a/src/spel/views.py	Fri Mar 21 11:22:42 2014 +0100
+++ b/src/spel/views.py	Fri Mar 21 15:21:15 2014 +0100
@@ -179,6 +179,71 @@
         context = {"q":q, "searched_tags": type_inter_param.split(","), "results": results, "nb_contents": nb_contents, "nb_annotations": nb_segments}
         
         return self.render_to_response(context)
+    
+    def post(self, request):
+        chapters_param = request.POST.get("chapters", "[]")
+        grouped_chapters = []
+        for iri_id, items in groupby(json.loads(chapters_param), itemgetter('iri_id')):
+            # Get segments timecodes
+            s = [ {"start": int(i["start"]), "end": int(i["end"])} for i in items ]
+            grouped_chapters.append({ 'content': iri_id, 'list': s })
+        if len(grouped_chapters)==0:
+            return HttpResponse("")
+        
+        
+        # Request segment : we make a complex query impossible (?) to do with orm, even with Q, Sum and other stuffs.
+        # Here is a SQL example of what we want :
+        # select *
+        # from ldt_utils_segment 
+        # where cutting_id IN ('performance','discussion') 
+        # AND (
+        #   ( ldt_utils_segment.iri_id='CONTENT_ID_1' AND (
+        #     ( TIMECODE_START_1 < ldt_utils_segment.start_ts AND ldt_utils_segment.start_ts < TIMECODE_END_1 )
+        #      OR 
+        #     ( TIMECODE_START_2 < ldt_utils_segment.start_ts AND ldt_utils_segment.start_ts < TIMECODE_END_2 )
+        #   )) 
+        #   OR 
+        #   ( ldt_utils_segment.iri_id='CONTENT_ID_2' AND (
+        #     ( TIMECODE_START_3 < ldt_utils_segment.start_ts AND ldt_utils_segment.start_ts < TIMECODE_END_3 )
+        #   )) 
+        # )
+        
+        raw_query = "select id, iri_id, cutting_id, tags, start_ts, duration, title, abstract \nfrom ldt_utils_segment \nwhere cutting_id NOT IN ('performance','discussion') \nAND ("
+        for i, ga in enumerate(grouped_chapters):
+            if i>0:
+                raw_query += "\n  OR "
+            raw_query += "\n  ( ldt_utils_segment.iri_id='" + ga["content"] + "' AND ("
+            for j, tc in enumerate(ga["list"]):
+                if j>0:
+                    raw_query += "\n     OR "
+                raw_query += "\n    ( " + str(tc["start"]) + " < ldt_utils_segment.start_ts AND ldt_utils_segment.start_ts < " + str(tc["end"]) + " )"
+            raw_query += "\n  )) "
+        raw_query += "\n)"
+        
+        # Dict because of itemgetter for groupby
+        tagged_segs = [ dict(s.__dict__) for s in Segment.objects.raw(raw_query) ]
+        for i in tagged_segs:
+            i["tags"] = i["_tags_cache"] # WHY ????? Because i don't know but we need it
+        # Prefetch all contents
+        all_contents = list(Content.objects.filter(iri_id__in=[s['iri_id'] for s in tagged_segs]))
+        results = []
+        for iri_id, items in groupby(tagged_segs, itemgetter('iri_id')):
+            # Get good content
+            content = None
+            content_filter = filter(lambda e: e.iri_id == iri_id, all_contents)
+            if len(content_filter)>0:
+                content = content_filter[0]
+            if content is None:
+                continue
+            # Get segments
+            s = list(items)
+            results.append({ 'content': content, 'list': s })
+        nb_contents = len(results)
+        nb_segments = len(tagged_segs)
+        
+        context = {"chapter_annots":True, "q":"", "searched_tags": [], "results": results, "nb_contents": nb_contents, "nb_annotations": nb_segments}
+        
+        return self.render_to_response(context)