web/ldt/ldt_utils/projectserializer.py
author ymh <ymh.work@gmail.com>
Thu, 14 Oct 2010 11:36:12 +0200
changeset 88 7f2c2d9adf58
parent 85 3b70d84e661a
child 89 30c6e597a7de
child 94 9927a619d2b5
permissions -rw-r--r--
correct project serializer

import lxml.etree
import uuid
from datetime import datetime
from ldt.ldt_utils.models import Content, Project

DATE_FORMATS = ["%d/%m/%Y","%Y-%m-%d"]

"""
Serialize a project object to a cinelab compatible array
"""
class ProjectSerializer:
    
    def __init__(self, project, from_contents=True, from_display=True):
        self.project = project
        self.parsed = False
        self.ldt_doc = None
        self.medias = []
        self.annotations = []
        self.tags = {}
        self.tags_by_id = {}
        self.annotation_types = []
        self.views = []
        self.lists = []
        self.serialize_contents = from_contents
        self.from_display = from_display
        
    
    def __parse_ensemble(self, ensemble_node, content):
        
        ensemble_id = ensemble_node.attrib[u"id"]
        ensemble_author = ensemble_node.attrib[u"author"]
        ensemble_title = ensemble_node.attrib[u"title"]
        ensemble_description = ensemble_node.attrib[u"abstract"]
        ensemble_created = datetime.utcnow().isoformat()
        ensemble_modified = ensemble_created 
        
        list_items = []
        new_list = {
            "id" : ensemble_id,
            "items" : list_items,
            "meta" : {
                "dc:creator":ensemble_author,
                "dc:created": ensemble_created,
                "dc:contributor":"undefined",
                "dc:modified": ensemble_modified,
                "dc:title":ensemble_title,
                "dc:description": ensemble_description,
                "id-ref":content.iri_id,
                "editable":"false"
            }
        }
        
        
        for decoupage_node in ensemble_node:
            if decoupage_node.tag != "decoupage" :
                continue
            
            decoupage_id = decoupage_node.attrib[ u"id"]
            decoupage_creator = decoupage_node.attrib[u"author"]
            if not decoupage_creator:
                decoupage_creator = "IRI"
            decoupage_contributor = decoupage_creator
            date_str = decoupage_node.get(u"date")
            decoupage_created = None
            if date_str :
                for date_format in DATE_FORMATS:
                    try:
                        decoupage_created = datetime.strptime(date_str,date_format).isoformat()
                        break
                    except Exception:
                        decoupage_created = None
            if decoupage_created is None:
                decoupage_created = datetime.utcnow().isoformat()
            decoupage_modified = decoupage_created
            
            decoupage_title = ""
            for txtRes in decoupage_node.xpath("title/text()", smart_strings=False): 
                    decoupage_title += txtRes

            decoupage_description = ""
            for txtRes in decoupage_node.xpath("abstract/text()", smart_strings=False): 
                    decoupage_description += txtRes
            

            
            list_items.append({"id-ref":decoupage_id})
            
            new_annotation_types = {
                "id":decoupage_id,
                "dc:creator":decoupage_creator,
                "dc:created":decoupage_created,
                "dc:contributor":decoupage_contributor,
                "dc:modified":decoupage_modified,
                "dc:title":decoupage_title,
                "dc:description":decoupage_description
            }
            
            self.annotation_types.append(new_annotation_types)            
                        
            res = decoupage_node.xpath("elements/element")
            for element_node in res:
                
                element_id = element_node.attrib[u"id"]
                element_begin = element_node.attrib[u"begin"]
                element_duration = element_node.attrib[u"dur"]
                element_media = content.iri_id
                element_color = element_node.attrib[u"color"]
                
                element_title = ""
                for txtRes in element_node.xpath("title/text()", smart_strings=False): 
                    element_title += txtRes
        
                element_description = ""
                for txtRes in element_node.xpath("abstract/text()", smart_strings=False): 
                    element_description += txtRes
                
                element_audio_src = ""
                element_audio_href = ""
                res = element_node.xpath("audio")
                if len(res) > 0:
                    element_audio_src = res[0].get(u"source",u"")
                    element_audio_href =  res[0].text                
                
                element_tags = []
                
                tags = element_node.get(u"tags",u"")
                
                tags_list = map(lambda s:s.strip(),tags.split(","))

                #tags                                
                if tags is None or len(tags) == 0:
                    tags_list = []
                    restagnode = element_node.xpath("tag/text()", smart_strings=False)
                    for tagnode in restagnode:
                        tags_list.append(tagnode)
                        
                if tags_list is None or len(tags_list) == 0:
                    tags_list = []
                    restagnode = element_node.xpath("tags/tag/text()", smart_strings=False)
                    for tagnode in restagnode:
                        tags_list.append(tagnode)
                
                tag_date = datetime.utcnow().isoformat()
                for tag_title in tags_list:
                    if tag_title not in self.tags:
                        tag_id = unicode(uuid.uuid1())
                        new_tag = {
                            "id":tag_id,
                            "meta" : {
                                "dc:creator":"IRI",
                                "dc:created": tag_date,
                                "dc:contributor":"IRI",
                                "dc:modified": tag_date,
                                "dc:title":tag_title
                            }
                        }
                        self.tags[tag_title] = new_tag
                        self.tags_by_id[tag_id] = new_tag
                    element_tags.append({"id-ref":tag_id})

                if not element_tags:
                    element_tags = None
                    
                new_annotation = {
                    "begin": element_begin,
                    "end": int(element_begin) + int(element_duration),
                    "id": element_id,
                    "media": element_media,
                    "content": {
                        "mimetype": "application/x-ldt-structured",
                        "title": element_title,
                        "description": element_description,
                        "color": element_color,
                        "audio": {
                            "src" : element_audio_src,
                            "mimetype": "audio/mp3",
                            "href": element_audio_href
                        },
                    },
                    "tags": element_tags,
                    "meta": {
                        "id-ref": decoupage_id,
                        "dc:creator": decoupage_creator,
                        "dc:contributor": decoupage_contributor,
                        "dc:created": decoupage_created,
                        "dc:modified": decoupage_modified
                    }
                }
                
                self.annotations.append(new_annotation)
        
        if not list_items:
            new_list["items"] = None
        self.lists.append(new_list)


    def __parse_ldt(self):
        
        self.ldt_doc = lxml.etree.fromstring(self.project.ldt.encode("utf-8"))
        
        res = self.ldt_doc.xpath("/iri/medias/media")
        for mediaNode in res:
            iri_id = mediaNode.attrib[u"id"]
            content = Content.objects.get(iri_id=iri_id)
            self.__parse_content(content)
            
        res = self.ldt_doc.xpath("/iri/annotations/content")
        for content_node in res:
            content_id = content_node.attrib[u"id"]
            content = Content.objects.get(iri_id=content_id)
            for ensemble_node in content_node:
                if ensemble_node.tag != "ensemble" :
                    continue
                self.__parse_ensemble(ensemble_node, content)            
    
#        res = self.ldt_doc.xpath("/iri/displays/display")
#        for display_node in res:
#            pass
        
        self.parsed = True
    
    def __parse_content(self, content):
        
        doc = lxml.etree.parse(content.iri_file_path())
        
        authors = content.authors.all()
        
        if len(authors) > 0 :
            author = authors[0].handle
        else :
            author = "IRI"
        
        if len(authors) > 1 :
            contributor = authors[1].handle
        else :
            contributor = author
        
        content_author = ""
        
        res = doc.xpath("/iri/head/meta[@name='author']/@content")
        if len(res) > 0:
            content_author = res[0]
        
        
        content_date = ""
        
        res = doc.xpath("/iri/head/meta[@name='date']/@content")
        if len(res) > 0:
            content_date = res[0]

        
        new_media = {
             "http://advene.liris.cnrs.fr/ns/frame_of_reference/ms" : "o=0",
             "id" : content.iri_id,
             "href" : content.videopath.rstrip('/') + "/" + content.src,
             "unit" : "ms",
             "origin" : "0",
             "meta": {
                 "dc:creator" : author,
                 "dc:created" : content.creation_date.isoformat(),
                 "dc:contributor" : contributor,
                 "dc:modified" : content.update_date.isoformat(),
                 "dc:creator.contents" : content_author,
                 "dc:created.contents" : content_date,
                 "dc:title" : content.title,
                 "dc:description" : content.description,
                 "dc:duration" : content.get_duration(),
                 "item": {
                     "name" : "streamer",
                     "value": content.videopath.rstrip('/') + "/"
                 },
             }
        }
        
        self.medias.append(new_media)
        
        if self.serialize_contents:        
            res = doc.xpath("/iri/body/ensembles/ensemble")
            for ensemble_node in res:
                self.__parse_ensemble(ensemble_node, content)

    
    def serialize_to_cinelab(self):
    
        res = {}
        
        if not self.parsed:
            self.__parse_ldt()    
        
        project_main_media = ""
        if len(self.medias) > 0:
            project_main_media = self.medias[0]["id"]
        
        res['meta'] = {
             'id': self.project.ldt_id,
             'dc:created':self.project.creation_date.isoformat(),
             'dc:modified':self.project.modification_date.isoformat(),
             'dc:contributor':self.project.changed_by,
             'dc:creator':self.project.created_by,
             'dc:title':self.project.title,
             'dc:description':self.project.get_description(self.ldt_doc), # get from doc, parse ldt
             'main_media': {"id-ref":project_main_media}
            }
        
        if not self.medias:
            self.medias = None
                        
        if not self.annotation_types:
            self.annotation_types = None
        
        if len(self.tags) == 0:
            tags = None
        else:
            tags = self.tags.values()
            
        if not self.lists:
            self.lists = None
            
        if not self.views:
            self.views = None
            
        if not self.annotations:
            self.annotations = None
        
        res['medias'] =  self.medias
        res['annotation-types'] = self.annotation_types
        res['annotations'] = self.annotations
        res['lists'] = self.lists
        res['tags'] = tags
        res['views'] = self.views # ignored for the moment
        
        return res
    
    def getAnnotations(self, first_cutting=True):
        
        if not self.parsed:
            self.__parse_ldt()
        
        annotations = []
        
        current_cutting = None
        uri = None
        for annot in self.annotations:
            if first_cutting and current_cutting and current_cuttings != annot['meta']['id-ref'] :
                break
            current_cuttings = annot['meta']['id-ref']
            content_id = annot['media']
            content = Content.objects.get(iri_id=content_id)
            if annot['tags']:
                tags_list = map(lambda tag_entry: self.tags_by_id[tag_entry['id-ref']]['meta']['dc:title'],annot['tags'])
            else:
                tags_list = []
            begin = int(annot['begin'])
            duration = int(annot['end'])-begin
            if content.media_obj and content.media_obj.external_publication_url:
                uri = "%s#t=%d" % (content.media_obj.external_publication_url, begin)

        
            annotations.append({
                'begin': begin,
                'duration':duration,
                'title':annot['content']['title'],
                'desc':annot['content']['description'],
                'tags': tags_list,
                'id':annot['id'],
                'uri':uri
            })
            
        return annotations