:- module(vumix_p1, []). % semweb :- use_module(library('semweb/rdf_db')). :- use_module(library('semweb/rdfs')). :- use_module(library('semweb/rdf_label')). :- use_module(library(yui3_beta)). % http libraries :- use_module(library('http/http_dispatch')). :- use_module(library('http/http_parameters')). :- use_module(library('http/html_write')). :- use_module(library('http/html_head')). :- use_module(library('http/http_path')). :- use_module(library('http/http_json')). :- use_module(components(label)). :- use_module(library(settings)). :- use_module(user(user_db)). :- use_module(library(instance_search)). :- use_module(library(graph_version)). :- use_module(api(annotation)). :- use_module(library(user_process)). :- use_module(api(reconcile)). :- use_module(library(video_annotation)). :- use_module(library(yaz_util)). /*************************************************** * http handlers ***************************************************/ :- http_handler(cliopatria(vumix/p1), http_vumix_p1, []). /*************************************************** * settings ***************************************************/ /*************************************************** * http replies ***************************************************/ %% http_vumix_p1(+Request) % % Generate page to annotate a vumix. http_vumix_p1(Request) :- http_parameters(Request, [ target(Target, [uri, description('URI of the object to be annotated') ]), field(Fields0, [zero_or_more, description('URI of annotation field') ]) ]), ( Fields0 = [] -> Fields = ['http://semanticweb.cs.vu.nl/prestoprime/personAnnotation', 'http://semanticweb.cs.vu.nl/prestoprime/placeAnnotation', 'http://semanticweb.cs.vu.nl/prestoprime/nameAnnotation', 'http://semanticweb.cs.vu.nl/prestoprime/subjectAnnotation'] ; Fields = Fields0 ), ( setting(vumix:login, true) -> authorized(write(_,_)), logged_on(User) ; logged_on(User, anonymous) ), user_process(User, Target, _), video_annotations(Target, As, [interval(10)]), sort_by_arg(As, 2, Annotations), video_scenes(Target, Scenes), scene_annotations(Scenes, Annotations, SceneAnnotations), html_page(Target, SceneAnnotations). user_process(User, Target, Process) :- ( current_user_process(Process), rdf(Process, rdf:type, pprime:'Annotation'), rdf(Process, opmv:used, Target) -> true ; create_user_process(User, [rdf:type=pprime:'Annotation', opmv:used=Target ], Process) ), start_user_process(Process). %% video_scenes(+Target, -Scenes) % % Scenes is a list of video scenes in Target. % Currently this simply sets a scenes every 10 seconds. video_scenes(Target, Scenes) :- mbh_video_source(Target, Source), rdf(Target, pprime:duration, literal(DA)), atom_number(DA, Duration), !, scene_list(1000, Duration, 10000, Source, Scenes). video_scenes(_, []). scene_list(Time, Duration, _, _, []) :- Time > Duration, !. scene_list(Start, Duration, Interval, Source, [Scene|Rest]) :- Scene = scene(Start, End, KeyFrame), End is Start+Interval, KeyFrame is Start+(Interval/2), scene_list(End, Duration, Interval, Source, Rest). %% scene_annotations(+SceneList, +Annotations, -SceneAnnotations) % % SceneAnnotations contains all scenes from SceneList % with the annotations. scene_annotations([], _, []). scene_annotations([scene(Start,End,Key)|T], Annotations, [scene(Start,End,Key,As)|Rest]) :- annotations_in_scene(Annotations, Start, End, As, AnnotationsRest), scene_annotations(T, AnnotationsRest, Rest). annotations_in_scene([], _, _, [], []). annotations_in_scene([A|As], Start, End, AsInScene, Rest) :- A = annotation(_Value,Time,_End,_Entries,_Score), ( Time < Start -> annotations_in_scene(As, Start, End, AsInScene, Rest) ; Time < End -> AsInScene = [A|AsInScene0], annotations_in_scene(As, Start, End, AsInScene0, Rest) ; Rest = [A|As] ). % hack for mbh demo mbh_video_source(R, Video) :- rdf_has(R, dc:id, literal(FragmentId)), !, concat_atom(['http://eculture2.cs.vu.nl/pprime/videos/',FragmentId,'.mp4'], Video). mbh_video_source(_R, @null). /*************************************************** * annotation page ***************************************************/ %% html_page(+Target, +Scenes) % % HTML page html_page(Target, Scenes) :- mbh_video_source(Target, Source), rdf_global_id(_:Id, Target), reply_html_page( [ title(['Annotate -- ', Id]) ], [ \html_requires(yui3('cssgrids/grids-min.css')), \html_requires(css('annotation.css')), \html_requires(css('vumix.css')), div(class('yui3-skin-sam yui-skin-sam'), [ div(id(hd), []), div(id(bd), div([id(layout)], [ div(id(title), []), div(id(scenes), \html_scenes(Scenes, Source)) ]) ), div(id(ft), []) ]), script(type('text/javascript'), [])% \yui_script(Target, Fields)) ]). html_scenes([], _) --> !. html_scenes([scene(Start, End, KeyFrame0, As)|T], Source) --> { KeyFrame is KeyFrame0/1000, http_link_to_id(serve_video_frame, [url(Source),time(KeyFrame)], Thumb) }, html(div([class('yui3-g frame'), style('margin-bottom:15px')], [ div(class('yui3-u-1-2'), [ div(class(thumb), img([src(Thumb)])), div(class(time), [Start, ' -- ', End]) ]), div(class('yui3-u-1-2 tags'), ul(\html_scene_annotations(As))) ])), html_scenes(T, Source). html_scene_annotations([]) --> !. html_scene_annotations([A|As]) --> { A = annotation(Value,_S,_E,Entries,_Score), ( Value = literal(_) -> literal_text(Value, Label) ; rdf_label(Value, Label) ), length(Entries, Count) }, html(li([Label, ' (', Count,')'])), html_scene_annotations(As). /******************************* * JavaScript * *******************************/ %% yui_script(+Graph) % % Emit YUI object. yui_script(Target, Fields) --> { findall(M-C, js_module(M,C), Modules), pairs_keys(Modules, Includes) }, yui3([json([modules(json(Modules))])], ['recordset-base'|Includes], [\js_video(Target), \js_video_frames(Target), \js_title_edit(Target), \js_annotation_fields(Fields, Target), 'videoFrames.on("frameSelect", function(e) {videoPlayer.setTime(e.time, true)});']). js_module('videoplayer', json([fullpath(Path), requires([node,event,widget]) ])) :- http_absolute_location(js('vuplayer/videoplayer.js'), Path, []). js_module('videoframes', json([fullpath(Path), requires([node,event,widget]) ])) :- http_absolute_location(js('videoframes.js'), Path, []). js_module('textedit', json([fullpath(Path), requires([node,event,io,plugin,'querystring-stringify-simple']) ])) :- http_absolute_location(js('textedit.js'), Path, []). js_module('annotation', json([fullpath(Path), requires(['recordset-base', autocomplete, 'autocomplete-highlighters', overlay, 'io','json', 'querystring-stringify-simple' ]) ])) :- http_absolute_location(js('annotation.js'), Path, []). js_video_frames(Target) --> { http_location_by_id(serve_video_frame, FrameServer), video_source(Target, Src) }, yui3_new(videoFrames, 'Y.VideoFrames', {frameServer:FrameServer, video:Src, duration:343000, interval:5000, width:730 }), yui3_render(videoFrames, one(id(videoFrames))). js_title_edit(Target) --> { http_location_by_id(http_update_annotation, Update), rdf_equal(dcterms:title, Field), ( annotation_api:annotation_in_field(Target, Field, Annotation, _Body, Text, _Comment, _User) -> true ; Annotation = @null, Text = @null ) }, yui3_plug(one(id(title)), 'Y.Plugin.TextEdit', {target:Target, field:Field, annotation:Annotation, text:Text, store:{update:Update} }). js_video(Target) --> { http_absolute_location(js('vuplayer/'), FilePath, []), video_source(Target, Src) }, yui3_new(videoPlayer, 'Y.VideoPlayer', {filepath:FilePath, src:Src, width:730, height:460, autoplay:symbol(false), controls:symbol(true) }), yui3_render(videoPlayer, one(id(video))). %% js_annotation_fields(+FieldURIs, +AnnotationTarget) % % Write JavaScript to init annotation fields js_annotation_fields([], _) --> !. js_annotation_fields([URI|T], Target) --> js_annotation_field(URI, Target), js_annotation_fields(T, Target). js_annotation_field(FieldURI, Target) --> { http_location_by_id(http_add_annotation, Add), http_location_by_id(http_remove_annotation, Remove), rdf_global_id(_:Id, FieldURI), setting(min_query_length, MinQueryLength), rdf(FieldURI, an:source, literal(Source)), annotation_api:json_annotation_list(Target, FieldURI, Tags) }, yui3_plug(one(id(Id)), 'Y.Plugin.Annotation', {target:Target, field:FieldURI, source:Source, store:{add:Add, remove:Remove }, tags:Tags, minQueryLength:MinQueryLength, resultListLocator: results, resultTextLocator: label, resultHighlighter: phraseMatch}).