:- module(yaz_game_recap, [ ]). :- use_module(library(http/http_dispatch)). :- use_module(library(http/http_parameters)). :- use_module(library(http/http_path)). :- use_module(library(http/html_write)). :- use_module(library(http/html_head)). :- use_module(library(http/http_json)). :- use_module(library(http/js_write)). :- use_module(library(http/json)). :- use_module(library(http/json_convert)). :- use_module(library(http/http_session)). :- use_module(user(user_db)). :- use_module(library(semweb/rdf_db)). :- use_module(library(semweb/rdfs)). :- use_module(library(semweb/rdf_label)). :- use_module(library(yaz_util)). :- use_module(library(yui3)). :- use_module(library(user_process)). :- use_module(library(video_annotation)). :- use_module(components(label)). :- use_module(components(yaz_page)). :- http_handler(yaz(gamerecap), http_yaz_game_recap, []). :- http_handler(yaz('data/update'), http_yaz_api_update_tags, []). :- http_handler(yaz('data/provenance'), http_yaz_api_provenance, []). %% http_yaz_game_recap(+Request) % % Emit the a video player with a tag carousel running along side % of it. http_yaz_game_recap(Request) :- ensure_logged_on(User0), user_property(User0, url(User)), http_parameters(Request, [ video(Video, [description('Current video')]), process(Process, [optional(true), desription('When set only annotations within this process are shown')]), user(Player, [optional(true), description('When set only annotations created by this user are shown')]), interval(Interval, [default(0), number, description('When set one entry per tag is returned in interval (in milliseconds)')]), confirmed(Confirmed, [boolean, default(false), description('When true only tags that are entered by >1 user are shown')]), limit(Limit, [default(1000), number, description('limit number of tags shown')]), start(StartTime, [default(0),description('Start time of the video')]) ]), Options = [process(Process), user(Player), interval(Interval), confirmed(Confirmed) ], create_user_process(User, [rdf:type=pprime:'GameRecap', opmv:used=Video ], _Process), video_annotations(Video, Annotations0, Options), sort_by_arg(Annotations0, 2, Annotations1), list_limit(Annotations1, Limit, Annotations, _), html_video_page(Video, Annotations, StartTime, Options). %% html_video_page(+Video, +Annotations, +StartTime, +Options) % % Emit an HTML page with a video player and a tag carousel. html_video_page(Video, Annotations, StartTime, Options) :- reply_html_page(yaz, [ title(['YAZ - ', Video]) ], [ \html_requires(css('player.css')), div(class('video-results'), \html_video_page_containers(Video, Options)), script(type('text/javascript'), \html_video_page_yui(Video, Annotations, StartTime, Options)) ]). html_video_page_containers(Video, _Options) --> { display_label(Video, Title) }, html([ h2(Title), div(id(video), [ div(id(tagplayer), []), div(id(videoplayer), []) ]), div(style('float:left;width:50%'), [ h4(['Pending actions ', input([id(submitChanges), type(submit), value(submit)]) ]), div(id(changehistory), []) ]), div(style('float:left;width:50%'), [ h4(['Provenance']), div(id(provenance), []) ]) ]). html_video_page_yui(Video, Annotations, StartTime, _Options) --> { video_source(Video, Src), http_absolute_location(js('videoplayer/'), FilePath, []), http_absolute_location(js('videoplayer/videoplayer.js'), VideoPlayer, []), http_absolute_location(js('tagcarousel/tagcarousel.js'), TagCarousel, []), http_absolute_location(js('changehistory/changehistory.js'), ChangeHistory, []), annotation_to_json(Annotations, JSONTags) }, html_requires(js('videoplayer/swfobject.js')), js_yui3([{modules:{'video-player':{fullpath:VideoPlayer}, 'tag-carousel':{fullpath:TagCarousel}, 'change-history':{fullpath:ChangeHistory} }} ], [node,event,widget,anim, 'querystring-stringify-simple','io','json', 'video-player','tag-carousel','change-history' ], [ \js_new(videoPlayer, 'Y.mazzle.VideoPlayer'({filepath:FilePath, src:Src, width:640, height:480, autoplay:symbol(false), controls:symbol(true), start:StartTime })), \js_new(tagCarousel, 'Y.mazzle.TagCarousel'({tags:JSONTags, height:480, width:200, edit:true, remove:true })), \js_new(changeHistory, 'Y.mazzle.ChangeHistory'({height:200, width:300 })), 'var oldTime;\n', \js_call('videoPlayer.render'('#videoplayer')), \js_call('tagCarousel.render'('#tagplayer')), \js_call('changeHistory.render'('#changehistory')), \js_yui3_on(videoPlayer, timeChange, \js_video_time_change), \js_yui3_on(tagCarousel, itemSelect, \js_tag_select), \js_yui3_on(tagCarousel, itemSelect, \js_fetch_provenance), \js_yui3_event(tagCarousel, 'on', itemUpdate, 'changeHistory.addActionHandler', changeHistory), \js_yui3_event(changeHistory, 'on', undo, 'tagCarousel.undo', tagCarousel), \js_yui3_on('Y.one("#submitChanges")', click, \js_submit_changes(Video)) ]). js_tag_select --> js_function([e], \[ ' if(e.tag.startTime) { var time = (e.tag.startTime/1000)-2; videoPlayer.setTime(time, true); }\n' ]). js_video_time_change --> js_function([e], \[ ' var time = Math.round(e.time); if(time!==oldTime) { oldTime = time; tagCarousel.focusTime(Math.round(e.time)+1); }\n' ]). js_submit_changes(Video) --> { http_location_by_id(http_yaz_api_update_tags, TagUpdateServer) }, js_function([e], [ ' var actions = Y.JSON.stringify(changeHistory.getActiveActions());\n', \js_call('Y.io'(TagUpdateServer, {method:'POST', data:{video:Video, action:symbol(actions)}, on:{success:symbol('changeHistory.disableAll')}, context:symbol(changeHistory) })) ]). js_fetch_provenance --> { http_location_by_id(http_yaz_api_provenance, ProvenanceServer) }, js_function([e], \[ ' var uris = [], as = e.tag.annotations; for(var i=0;i maplist(remove_video_annotation(Video), Annotations) ; Type = edit -> change_annotations(Annotations, NewValue) ), process_actions(As, Video). annotation_uri(json([uri=URI|_]), URI). annotation_uri(i(URI, _Time), URI). action_term(remove(Annotation), remove, Tag, Annotations, _) :- Annotation = annotation(Tag, _, _, Annotations). action_term(edit(Annotation, New), edit, Tag, Annotations, New) :- Annotation = annotation(Tag, _, _, Annotations). change_annotations([], _). change_annotations([Annotation|As], NewValue) :- update_annotation_value(Annotation, NewValue), change_annotations(As, NewValue). %% http_yaz_api_provenance(+Request) % % Handler for POST submission of tag modifications. http_yaz_api_provenance(Request) :- http_parameters(Request, [ annotation(Annotations, [zero_or_more, description('URI of an annotation object')]) ]), Annotations = [Annotation], annotation_provenance(Annotation, Provenance), html_current_option(content_type(Type)), phrase(html(table(tbody([\table_head, \html_provenance(Provenance) ]) )), HTML), format('Content-type: ~w~n~n', [Type]), print_html(HTML). table_head --> html(tr([th(time), th(user), th(action), th(value), th(playhead) ])). html_provenance([]) --> !. html_provenance([action(_,Time,User,_,Action)|T]) --> html_provenance_action(Action,Time,User), html_provenance(T). html_provenance_action(added(_, _, Value, PlayHead), Time, User) --> html(tr([ td(\html_time(Time)), td(\html_user(User)), td(added), td(Value), td(PlayHead) ])). html_provenance_action(removed(_, _), Time, User) --> html(tr([ td(\html_time(Time)), td(\html_user(User)), td(removed), td([]) ])). html_provenance_action(valueChange(_, Value), Time, User) --> html(tr([ td(\html_time(Time)), td(\html_user(User)), td(changed), td(Value), td([]) ])). html_provenance_action(timeChange(_, PlayHead), Time, User) --> html(tr([ td(\html_time(Time)), td(\html_user(User)), td(changed), td([]), td(PlayHead) ])). html_time(TimeStamp) --> { format_time(atom(Formatted), '%Y-%m-%d %T', TimeStamp) }, html(Formatted). html_user(UserURL) --> { display_label(UserURL, Name) }, html(Name).