src/ldt/ldt/ldt_utils/views/ldt_json.py
author durandn
Tue, 21 Apr 2015 15:05:22 +0200
changeset 1364 fb0046d64c82
parent 1363 a8f354a9b8e4
child 1387 82d256129376
permissions -rw-r--r--
replaced mimetype arg in HTTPResponse objects with content_type + fixed a url error from commit changing json to ldt_json + replaced md5 lib (deprecated) with hashlib.md5 for project id generation

# -*- coding: utf-8 -*-
from datetime import datetime
import json
import logging
import lxml.etree
from operator import itemgetter

from django.conf import settings
from django.http import HttpResponse, HttpResponseForbidden
from django.shortcuts import get_object_or_404, get_list_or_404
from django.utils.html import escape
from django.utils.translation import ugettext as _

import ldt.auth as ldt_auth
from ldt.ldt_utils.models import Project
from ldt.ldt_utils.projectserializer import ProjectJsonSerializer
from ldt.ldt_utils.searchutils import search_generate_ldt


logger = logging.getLogger(__name__)


def project_json_id(request, id):  # @ReservedAssignment
    
    project = get_object_or_404(Project.safe_objects, ldt_id=id)

    return project_json(request, project, False)

def project_json_cutting_id(request, id, cutting_id):  # @ReservedAssignment

    project = get_object_or_404(Project.safe_objects, ldt_id=id)

    return project_json(request, project, first_cutting=cutting_id)

def project_json_externalid(request, id):  # @ReservedAssignment
        
    res_proj = get_list_or_404(Project.safe_objects.order_by('-modification_date'), contents__external_id=id)
    
    return project_json(request, res_proj[0], False)



def project_json(request, project, serialize_contents=True, first_cutting=None):
    
    if not ldt_auth.check_access(request.user, project):
        return HttpResponseForbidden(_("You can not access this project"))
        
    content_type = request.REQUEST.get("content_type")
    if content_type is None:
        content_type = "application/json; charset=utf-8"
    else:
        content_type = content_type.encode("utf-8")
    if "charset" not in content_type:
        content_type += "; charset=utf-8" 
    resp = HttpResponse(content_type=content_type)
    resp['Cache-Control'] = 'no-cache, must-revalidate'
    resp['Pragma'] = 'no-cache'
    
    indent = request.REQUEST.get("indent")
    if indent is None:
        indent = settings.LDT_JSON_DEFAULT_INDENT
    else:
        indent = int(indent)
    
    callback = request.REQUEST.get("callback")
    escape_str = request.REQUEST.get("escape")
    escape_bool = False
    if escape_str:
        escape_bool = {'true': True, 'false': False, "0": False, "1": True}.get(escape_str.lower())
    
    one_content_str = request.REQUEST.get("onecontent")
    one_content_bool = False
    if one_content_str:
        one_content_bool = {'true': True, 'false': False, "0": False, "1": True}.get(one_content_str.lower())
        
        
    ps = ProjectJsonSerializer(project, serialize_contents, first_cutting=first_cutting)
    project_dict = ps.serialize_to_cinelab(one_content_bool)
    
    json_str = json.dumps(project_dict, ensure_ascii=False, indent=indent)
    
    if callback is not None:
        json_str = "%s(%s)" % (callback, json_str)
    
    if escape_bool:
        json_str = escape(json_str)
    
    resp.write(json_str)

    return resp



def mashup_by_tag(request):
    # do we indent ?
    indent = request.REQUEST.get("indent")
    if indent is None:
        indent = settings.LDT_JSON_DEFAULT_INDENT
    else:
        indent = int(indent)
    # do we escape ?
    escape_str = request.REQUEST.get("escape")
    escape_bool = False
    if escape_str:
        escape_bool = {'true': True, 'false': False, "0": False, "1": True}.get(escape_str.lower())
    # do we remove annotations from mashup if the have duration=0 ? (yes by default)
    remove_zero_dur_str = request.REQUEST.get("removezeroduration")
    remove_zero_dur = True
    if remove_zero_dur_str:
        remove_zero_dur = {'true': True, 'false': False, "0": False, "1": True}.get(remove_zero_dur_str.lower())
    
    # We search
    s = request.REQUEST.get("tag")
    sort_type = request.REQUEST.get("sort", "")
    if s:
        # We get the projects with all the segments
        project_xml, results = search_generate_ldt(request, "tags", s, False)
        
        logger.debug("mashup_by_tag : search_generate_ldt done")
        
        project = Project()
        project.ldt = lxml.etree.tostring(project_xml, pretty_print=True)
        # Needed datas for jsonification
        now = datetime.now()
        project.modification_date = project.creation_date = now
        #return HttpResponse(lxml.etree.tostring(project_xml, pretty_print=True), content_type="text/xml;charset=utf-8")
        logger.debug("mashup_by_tag : serialize_to_cinelab prepare")
        
        ps = ProjectJsonSerializer(project, from_contents=False)
        logger.debug("mashup_by_tag : serialize_to_cinelab serializer ready")        
        mashup_dict = ps.serialize_to_cinelab()

        logger.debug("mashup_by_tag : serialize_to_cinelab done")
        
        # Now we build the mashup with the good segments (the ones between in and out)
        if results:
            tc_in = 0
            if request.REQUEST.get("in") :
                tc_in = float(request.REQUEST.get("in"))
            tc_out = float('inf')
            if request.REQUEST.get("out") :
                tc_out = float(request.REQUEST.get("out"))
            # Since the timecodes are saved as strings, we filter after calculating float in and out. Timecodes are in milliseconds
            mashup_list = {
                "items": [],
                "meta": {
                    "dc:contributor": "IRI",
                    "dc:creator": "IRI",
                    "dc:title": "Generated mashup with tag '"+s+"'",
                    "dc:modified": now.isoformat(),
                    "dc:created": now.isoformat(),
                    "listtype": "mashup",
                    "dc:description": ""
                },
                "id": "generated_mashup_list"
            }
            # If sort_type = weight, we sort the result by the tag's weight
            if sort_type.lower() == "weight":
                # First we turn each string timecode to a float
                for res in results:
                    res["start_ts"] = float(res["start_ts"])
                    res["duration"] = float(res["duration"])
                # We sort to group by start_ts for each media/iri_id
                sorted_results = sorted(results, key=itemgetter("iri_id", "start_ts", "duration"))
                highest_weighted = []
                current_weight = 1
                nb_res = len(sorted_results)
                for i, res in enumerate(sorted_results):
                    # Explanation : we calculate the weight, which is the number of segments 
                    # tagged with the searched tag for the same iri_id at the same start_ts.
                    # Thanks to the previous sort, the last segment is the one with the longest duration and the one we finally keep
                    next_res = None
                    if i<(nb_res-1):
                        next_res = sorted_results[i+1]
                    if next_res and next_res["iri_id"]==res["iri_id"] and next_res["start_ts"]==res["start_ts"]:
                        current_weight += 1
                        continue
                    res["weight"] = current_weight
                    highest_weighted.append(res)
                    current_weight = 1
                
                # Now that we have the weight for all temporal segments, we just have to sort the array.
                highest_weighted = sorted(highest_weighted, key=itemgetter("weight"), reverse=True)
                for res in highest_weighted:
                    cur_in = res["start_ts"]
                    cur_out = cur_in + res["duration"]
                    if tc_in<=cur_in and cur_out<=tc_out and ((not remove_zero_dur) or (remove_zero_dur and res["duration"]>0.0)) and (res["element_id"] not in mashup_list["items"]):
                        #mashup_list["items"].append(res["iri_id"] + ", " + res["element_id"] + ", " + str(res["start_ts"]) + ", " + str(res["duration"]) + ", " + str(res["weight"]))
                        #mashup_list["items"].append(res["element_id"] + ", " + str(res["weight"]) + ", " + res["title"])
                        mashup_list["items"].append(res["element_id"])
            else:
                # no particular sorting
                for res in results:
                    cur_in = float(res["start_ts"])
                    dur = float(res["duration"])
                    cur_out = cur_in + dur
                    if tc_in<=cur_in and cur_out<=tc_out and ((not remove_zero_dur) or (remove_zero_dur and dur>0.0)):
                        mashup_list["items"].append(res["element_id"])
            if mashup_dict["lists"] is None:
                mashup_dict["lists"] = []
            mashup_dict["lists"].append(mashup_list)
    
            # If asked, we remove the annotations not used in the mashup.
            # It enabled a lighter response 
            remove_not_used_str = request.REQUEST.get("removenotused")
            remove_not_used = False
            if remove_not_used_str:
                remove_not_used = {'true': True, 'false': False, "0": False, "1": True}.get(remove_not_used_str.lower())
            if remove_not_used:
                for a in mashup_dict["annotations"]:
                    if a["id"] not in mashup_list["items"]:
                        mashup_dict["annotations"].remove(a)
    
    
    json_str = json.dumps(mashup_dict, ensure_ascii=False, indent=indent)
    if escape_bool:
        json_str = escape(json_str)
    
    # Callback to allo jsonp
    callback = request.REQUEST.get("callback")
    if callback is not None:
        json_str = "%s(%s)" % (callback, json_str)
    
    resp = HttpResponse(content_type="application/json; charset=utf-8")
    resp.write(json_str)
    
    return resp