:- module(yaz_garden, []). :- 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/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(video_annotation)). :- use_module(applications(yaz_tag)). :- use_module(components(label)). :- use_module(components(yaz_page)). :- use_module(components(yaz_video_item)). :- use_module(library(rdf_history)). :- use_module(library(user_process)). :- http_handler(yaz(garden), http_yaz_garden, []). :- http_handler(yaz(gardenaccept), http_yaz_garden_accept, []). :- http_handler(yaz(gardenreset), http_yaz_garden_reset, []). :- http_handler(yaz(data/reconcileentries), http_data_reconcile_entries, []). reconcile_source(gtaa, 'GTAA', Server, Params) :- http_location_by_id(http_reconcile, Server), www_form_encode('[{"http://www.w3.org/2004/02/skos/core#inScheme":"http://data.beeldengeluid.nl/gtaa/GTAA"}]',Ps), atom_concat('&properties=',Ps,Params). reconcile_source(wordnet, 'WordNet', Server, '&type=http://www.w3.org/2006/03/wn/wn20/schema/Synset') :- http_location_by_id(http_reconcile, Server). %reconcile_source(cornetto, % 'Cornetto', % Server, %'&type=http://purl.org/vocabularies/cornetto/Synset') :- % http_location_by_id(http_reconcile, Server). %reconcile_source(geonames, % 'Geonames', %'http://api.kasabi.com/api/reconciliation-api-geonames', % '&apikey=908177a484aa25f9b602d3eb76cf057d73e7aa39'). %reconcile_source(dbpedia, % 'DBPedia', %'http://api.kasabi.com/api/reconciliation-api-dbpedia-36', % '&apikey=908177a484aa25f9b602d3eb76cf057d73e7aa39'). reconcile_source(freebase, 'Freebase', 'http://standard-reconcile.freebaseapps.com/reconcile', ''). %% http_yaz_garden_accept(+Request) % % Emit an HTML page to link tags to concepts. http_yaz_garden_accept(Request) :- ensure_logged_on(_), http_parameters(Request, [ video(Video, [description('Current video')]) ]), http_link_to_id(http_yaz_shot, [video(Video)], ShotAnnotation), http_link_to_id(http_yaz_garden, [video(Video)], TagGarden), % throw(http_reply(moved_temporary(Garden))). reply_html_page(yaz, [ title(['YAZ accept - ', Video]) ], [ div(['You accepted to moderate ', Video]), ul([li(['Start tag gardening I:', a(href(TagGarden), ' cleanup tags')]), li(['Start tag gardening II:', a(href(ShotAnnotation), ' annotate video shots')]) ]) ]). %% http_yaz_garden_remove(+Request) % % Emit an HTML page to link tags to concepts. http_yaz_garden_reset(_Request) :- rdf_transaction(forall(visible_garden_process(Process), rdf_assert(Process, rdf:type, pprime:'Hidden', Process))), reply_html_page(yaz, [ title(['YAZ accept - ', Video]) ], [ div(['You hide the previous gardening sessions for ', Video]), div(['go back to ', a(href(location_by_id(http_yaz_home)), 'your videos') ]) ]). visible_garden_process(Process) :- rdf(Process, rdf:type, pprime:'TagGarden'), \+ rdf(Process, rdf:type, pprime:'Hidden'). %% http_yaz_garden(+Request) % % Emit an HTML page to link tags to concepts. http_yaz_garden(Request) :- ensure_logged_on(User0), user_property(User0, url(User)), http_parameters(Request, [ video(Video, [description('Current video')]), interval(Interval, [default(10), 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')]) ]), Options0 = [video(Video), confirmed(Confirmed), interval(Interval) ], ( current_user_process(Process), rdf(Process, rdf:type, pprime:'TagGarden'), rdf(Process, opmv:used, Video) -> true ; create_user_process(User, [rdf:type=pprime:'TagGarden', opmv:used=Video ], Process) ), start_user_process(Process), delete_nonground(Options0, Options), video_annotations(Video, As0, Options), sort_by_arg(As0, 2, Annotations), sort_by_arg(As0, 1, As1), merge_entries(As1, TagEntries0), sort_by_arg_count(TagEntries0, 2, TagEntries, desc), findall(Id=json([label=Label,url=URL,parameters=Parameters]), reconcile_source(Id,Label,URL,Parameters), Sources), html_page(Video, Annotations, TagEntries, json(Sources), Options). merge_entries([], []). merge_entries([A0|T], [A|As]) :- A0 = annotation(Value,_,_,_,_), A = annotation(Value,Entries), same_entries([A0|T], Value, Entries0, Rest), sort_by_arg(Entries0, 3, Entries), merge_entries(Rest, As). same_entries([annotation(V,_,_,[i(URI,Time)|_],_)|As], V, [entry(URI,V,Time)|Es], Rest) :- same_entries(As, V, Es, Rest). same_entries(As, _, [], As). %% html_page(+Video, +Annotations, +Options) % % Emit an HTML page for concept gardening html_page(Video, Annotations, Groups, Sources, Options) :- reply_html_page(yaz, [ title(['YAZ - ', Video]) ], [ \html_requires(css('garden.css')), \yaz_video_header(Video), div(id(tags), [ div(id(taglist), []), div(class(box), [ div(class(hd), 'Reconcile'), div([class(bd), id(tagreconcile)], []) ]) ]), div(id(frames), [ div(id(videoframes), []) ]), div(id(video), [ div(id(timeline), []), div(id(videoplayer), []) ]), script(type('text/javascript'), \html_video_page_yui(Video, Annotations, Groups, Sources, Options)) ]). source_options([]) --> !. source_options([Label-Value|Ls]) --> html(option(value(Value), Label)), source_options(Ls). html_video_page_yui(Video, Annotations, Groups, ReconcileSources, Options) --> { video_source(Video, Src, Duration), http_location_by_id(serve_video_frame, FrameServer), http_absolute_location(js('videoplayer/'), FilePath, []), http_absolute_location(js('videoplayer/videoplayer.js'), Videoplayer, []), http_absolute_location(js('videoframes/videoframes.js'), Videoframes, []), http_absolute_location(js('tagplayer/taglist.js'), Taglist, []), http_absolute_location(js('tagplayer/tagReconcile.js'), Tagreconcile, []), http_absolute_location(js('timeline/timeline.js'), Timeline, []), annotation_to_json(Annotations, JSONTags), annotation_to_json(Groups, JSONTagGroups) }, html_requires(js('videoplayer/swfobject.js')), js_yui3([{modules:{'video-player':{fullpath:Videoplayer}, 'video-frames':{fullpath:Videoframes}, 'tag-list':{fullpath:Taglist}, 'tag-reconcile':{fullpath:Tagreconcile}, 'timeline':{fullpath:Timeline} }} ], [node,event,widget,anim, 'json','jsonp','querystring-stringify-simple',io, 'video-player','video-frames',timeline, 'tag-list','tag-reconcile' ], [ \js_new(tagList, 'Y.mazzle.TagList'({tags:JSONTagGroups, height:425, width:200 })), \js_new(tagReconcile, 'Y.mazzle.TagReconcile'({height:200, width:190, sources:ReconcileSources, limit:10 })), \js_new(videoPlayer, 'Y.mazzle.VideoPlayer'({filepath:FilePath, src:Src, width:560, height:400, autoplay:symbol(false), controls:symbol(true), duration:Duration })), \js_new(videoFrames, 'Y.mazzle.VideoFrames'({frameServer:FrameServer, video:Src, width:200, height:425, duration:Duration, playerPath:FilePath, confirm:symbol(false), showRelated:symbol(false), showTime:symbol(true), disabled:symbol(true) })), \js_new(timeline, 'Y.mazzle.Timeline'({height:20, width:560, duration:Duration, items:JSONTags })), 'tagReconcile.set("tags", tagList.get("tags"));', \js_yui3_decl(params, json(Options)), \js_yui3_decl(delayID, -1), \js_yui3_render(videoFrames, #(videoframes)), \js_yui3_render(videoPlayer, #(videoplayer)), \js_yui3_render(timeline, #(timeline)), \js_yui3_render(tagList, #(taglist)), \js_yui3_render(tagReconcile, #(tagreconcile)), %\js_yui3_render(tagLinker, #(taglinker)), \js_yui3_on(tagList, itemSelect, \js_tag_select), \js_yui3_on(tagList, reconcileSelect, \js_reconcile_select(Video)), \js_yui3_on(videoFrames, frameHover, \js_frame_hover), \js_yui3_on(videoFrames, frameSelect, \js_frame_select), \js_yui3_on(tagReconcile, reconcileStart, \js_reconcile_start), \js_yui3_on(tagReconcile, reconcileReturn, \js_reconcile_return) ]). js_tag_select --> js_function([e], \[ ' var tag = e.tag, entry = tag.annotations[0], time = (entry.startTime/1000)-10;\n', ' videoPlayer.pause(); videoFrames.set("frames", tag.annotations); videoFrames.set("disabled", false);\n' ]). js_frame_select --> js_function([e], \[ ' var frame = e.frame; var time = (frame.startTime/1000)-8; videoPlayer.setTime(time, true);\n' ]). js_frame_hover --> js_function([e], \[ ' timeline.highlightIndex(e.index);\n' ]). js_reconcile_select(Video) --> { http_location_by_id(http_data_reconcile_entries, Server) }, js_function([o], \[ ' Y.io("',Server,'", { data: {video:"',Video,'", uri:o.uri, tag:o.tag, index:o.index },\n', ' on: { success: function(e,o) { Y.log("reconcilation saved as: "+Y.JSON.parse(o.responseText).reconciliation); } }, });\n' ]). js_reconcile_start --> js_function([], \[ ' tagList.resetReconciled();' ]). js_reconcile_return --> js_function([o], \[ ' tagList.setReconciled(o.reconciled, o.startIndex, o.endIndex);' ]). %% http_data_reconcile_entries(+Request) % % http_data_reconcile_entries(Request) :- http_parameters(Request, [ video(Video, [description('video we are updating entries of')]), tag(Tag, [escription('tag being reconciled')]), uri(URI, [description('Link to a concept')]), index(Index, []) ]), logged_on(User0, anonymous), user_property(User0, url(User)), ( current_user_process(Process), rdf(Process, rdf:type, pprime:'TagGarden'), rdf(Process, opmv:used, Video) -> true ; create_user_process(User, [rdf:type=pprime:'TagGarden', opmv:used=Video ], _GardenProcess) ), rdfh_transaction(reconcile_tag(Video, Tag, URI, Index, Event)), reply_json(json([reconciliation=Event])). reconcile_tag(Video, Tag, URI, Index, R) :- rdf_bnode(R), rdfh_assert(R, rdf:type, pprime:'Reconciliation'), rdfh_assert(R, pprime:video, Video), rdfh_assert(R, pprime:tag, Tag), rdfh_assert(R, pprime:concept, URI), rdfh_assert(R, pprime:index, literal(Index)).