--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/data-api.md Wed Jun 20 14:45:30 2012 +0200
@@ -0,0 +1,304 @@
+# API d’accès aux métadonnées #
+
+ATTENTION !
+Cette documentation se réfère à la v.3 du Metadataplayer, actuellement disponible dans la branche **new-model** du repository
+http://www.iri.centrepompidou.fr/dev/hg/metadataplayer
+
+## Élément de base ##
+
+ IriSP.Model.Element
+
+### Rôle ###
+
+Classe de base dont héritent les différents types d’objets utilisés dans le Metadataplayer: annotations, types d’annotations, médias, etc.
+
+### Instanciation ###
+
+**Element** fonctionne comme une classe abstraite est n’est jamais instancié directement.
+
+Néanmoins, tous les objets en héritant seront instanciés de la manière suivante :
+
+ var myElement = new IriSP.Model.Element(id, source);
+
+- **id** est l’identifiant unique de l’élément. S’il est à *false*, un identifiant unique sera généré.
+- **source** identifie la source de données dont provient l’élément (cf. Source de Données, *IriSP.Model.Source*, plus bas).
+
+### Propriétés ###
+
+#### type ####
+
+Type d’élément, surchargé par les classes qui héritent de l’élément de base:
+
+- **element** pour IriSP.Model.Element
+- **media** pour IriSP.Model.Media
+- **annotationType** pour IriSP.Model.AnnotationType
+- **tag** pour IriSP.Model.Tag
+- **annotation** pour IriSP.Model.Annotation
+- **mashup** pour IriSP.Model.Mashup
+- **mashedAnnotation** pour IriSP.Model.MashedAnnotation
+
+#### id ####
+
+Identifiant unique de l’élément
+
+#### title ####
+
+Titre de l’élément, par défaut une chaîne vide ("")
+
+#### description ####
+
+Description de l’élément, par défaut une chaîne vide ("")
+
+## Media ##
+
+ IriSP.Model.Media
+
+### Rôle ###
+
+Représente un média (vidéo ou audio).
+
+Hérite de l’Élément de base
+
+### Propriétés ###
+
+#### video ####
+
+Il s’agit de l’URL de la vidéo à charger
+
+#### duration ####
+
+Il s’agit de la durée du média (telle que renseignée dans les métadonnées -- peut ne pas être égale à la durée telle que lue dans la fenêtre vidéo).
+
+Il s’agit d’un objet durée (cf. *IriSP.Model.Time* plus bas)
+
+### Méthodes ###
+
+#### getDuration ####
+
+Permet de spécifier la durée du média, en millisecondes
+
+#### getAnnotations ####
+
+Retourne la liste des annotations associées au média
+
+#### getAnnotationsByTypeTitle ####
+
+Retourne la liste des annotations associées au média et dont le type d’annotation (ou découpage, ou ligne, c.f. Type d’Annotation plus bas) correspond à l’argument de la fonction
+
+## Type d’Annotation ##
+
+ IriSP.Model.AnnotationType
+
+### Rôle ###
+
+Représente un type d’annotation, correspondant également à ce qui peut être nommé découpage ou ligne dans *Lignes de Temps*
+
+Hérite de l’Élément de base.
+
+### Méthodes ###
+
+#### getAnnotations ####
+
+Retourne la liste des annotations associées au type d’annotation
+
+## Annotation ##
+
+ IriSP.Model.Annotation
+
+### Rôle ###
+
+Représente une annotation, correspondant à un segment temporel (dont la durée peut être nulle) d’un média
+
+Hérite de l’Élément de base.
+
+### Propriétés ###
+
+#### begin ####
+
+Timecode de fin de l’annotation. Est un objet de type durée (cf. plus bas)
+
+#### begin ####
+
+Timecode de début de l’annotation. Est un objet de type durée (cf. plus bas)
+
+### Méthodes ###
+
+#### getMedia ####
+
+Retourne l’objet **Média** (*IriSP.Model.Media*) auquel se réfère l’annotation
+
+#### getAnnotationType ####
+
+Retourne l’objet **Type d’Annotation** (*IriSP.Model.AnnotationType*) auquel se réfère l’annotation
+
+#### getTags ####
+
+Retourne la liste (cf. Liste d’éléments *IriSP.Model.List*) des tags associés à l’annotation.
+
+#### getTagTexts ####
+
+## Mashup ##
+
+ IriSP.Model.Mashup
+
+### Rôle ###
+
+Il s’agit d’un bout à bout, composé d’une liste de segments (définis par des annotations de durée non nulle) accolés les uns après les autres.
+
+### Méthodes ###
+
+**À compléter**
+
+## Liste d’éléments ##
+
+ IriSP.Model.List
+
+### Rôle ###
+
+Etend les fonctionnalités des tableaux javascript (*Array*) pour lister des éléments (cf. types d’éléments ci-dessus).
+
+### Instanciation ###
+
+ var myList = new IriSP.Model.List(directory);
+
+- **directory** est le répertoire de données auxquelles la liste permet d’accéder (cf. plus bas)
+
+### Méthodes ###
+
+#### Méthodes de parcours de liste ####
+
+Ces méthodes sont fournies grâce à la bibliothèque extérieure *underscore.js* et sont documentées sur http://documentcloud.github.com/underscore/
+
+Il s’agit de:
+
+- **map**: Renvoie un tableau (*Array*) dont les éléments correspondent aux éléments de la liste, via une fonction passée en argument de map
+- **forEach**: Itère une fonction sur la liste.
+- **filter**: Ne renvoie que les éléments de la liste dont la valeur correspond au résultat d’une fonction.
+- **sortBy**: Fonction de tri, par ordre croissant de la valeur retournée par la fonction passée en argument.
+
+#### searchByTitle, searchByDescription, searchByTextFields ####
+
+Méthodes retournant une nouvelle liste d’éléments, contenant les éléments de la liste dont respectivement le titre, la description ou les deux correspondent à l’argument de la méthode.
+
+ myList.searchByTitle("texte"); // => un *IriSP.Model.List* contenant les éléments de myList dont le titre contient "texte"
+
+## Durée ##
+
+ IriSP.Model.Time
+
+### Rôle ###
+
+Facilite la gestion des durées en millisecondes utilisées dans le Metadataplayer
+
+### Instanciation ###
+
+ var myTime = new IriSP.Model.Time(ms);
+
+- **ms** est une durée en millisecondes
+
+### Méthodes ###
+
+#### getSeconds ####
+
+Renvoie la durée convertie en secondes
+
+#### toString ####
+
+Renvoie la durée au format (hh:)mm:ss
+
+#### setSeconds ####
+
+Permet d’affecter une durée en secondes
+
+ myTime.setSeconds(12); // 12000 millisecondes
+
+## Source de données ##
+
+ IriSP.Model.Source
+
+et
+ IriSP.Model.RemoteSource
+
+### Rôle ###
+
+Gère une source de données : fichier externe JSON, XML, etc. pour *IriSP.Model.RemoteSource*, projet créé à la volée pour *IriSP.Model.Source*.
+
+*IriSP.Model.RemoteSource* hérite de *IriSP.Model.Source* et ne diffère que par son implémentation de la méthode *get*.
+
+Sur la plateforme *Lignes de Temps*, il existe plusieurs API qui sont utilisées comme sources :
+
+- L’API projet, qui renvoie un fichier JSON contenant un projet LDT complet.
+- L’API segment, qui renvoie toutes les annotations d’un média situées entre deux timecodes fournis en argument.
+- L’API de publication d’annotation, qui demande l’envoi (par la méthode HTTP PUT) d’une liste d’annotation et renvoie celle-ci en retour, avec les identifiants des annotations en base de données.
+
+### Instanciation ###
+
+ var config = { directory: myDirectory };
+ var mySource = new IriSP.Model.Source(config);
+
+- **config** est un objet contenant les options de configuration:
+ - Il doit nécessairement contenir une propriété **directory**, désignant le répertoire de données (cf. plus bas).
+ - La propriété **serializer** doit désigner le *Sérialiseur* utilisé pour désérialiser les données importées ou sérialiser l’export.
+ - un *IriSP.Model.RemoteSource* doit également être appelé avec une propriété **url**, désignant l’URL de la source.
+
+Une Source ne doit pas être instanciée directement, ce rôle est donné aux répertoires de données, ce qui permet notamment d’éviter des accès multiples à une même URL.
+
+### Propriétés ###
+
+#### currentMedia ####
+
+*TODO: transférer dans un objet "Project"*
+
+Donne accès au média en cours du projet. Peut désigner un vrai média ou un mashup.
+
+### Méthodes ###
+
+#### get ####
+
+Permet de récupérer ou de rafraîchir, via Ajax, les données de la source. Pour un *IriSP.Model.Source* de base, n’a aucun effet.
+
+#### onLoad ####
+
+Permet d’exécuter une fonction, passée en argument, au chargement de la source.
+
+#### serialize, deSerialize ####
+
+Transforme les données de la source en données sérialisées, au format du sérialiseur associées à la source, et inversement.
+
+#### getAnnotations, getAnnotationTypes, getMedias, getTags, getMashups ####
+
+Retourne les listes respectives d’annotations, types d’annotations, médias, tags et mashups de la source.
+
+#### getAnnotationsByTypeTitle ####
+
+Retourne la liste des annotations dont le type d’annotation correspond à l’argument de la fonction.
+
+## Répertoire de données ##
+
+ IriSP.Model.Directory
+
+### Rôle ###
+
+Gère l’instanciation des sources de données et la mise en cache de ces sources lorsque plusieurs appels à la même URLs sont faits.
+
+Permet également aux objets de plusieurs sources d’interagir entre eux.
+
+### Instanciation ###
+
+ var myDirectory = new IriSP.Model.Directory
+
+### Méthodes ###
+
+#### newLocalSource ####
+
+Crée une nouvelle source non attachée à une URL. S’il faut exporter des données, un sérialiseur doit être passé en paramètres.
+
+ var myConfig = { serializer: IriSP.serializers.ldt };
+ var myLocalSource = myDirectory.newLocalSource(myConfig);
+
+#### remoteSource ####
+
+Crée ou récupère (si celle-ci existe déjà) une source attachée à une URL. Le sérialiseur est obligatoire.
+
+ var myConfig = { url: "source-data.json", serializer: IriSP.serializers.ldt };
+ var myLocalSource = myDirectory.remoteSource(myConfig);
--- a/src/js/defaults.js Tue Jun 12 19:44:20 2012 +0200
+++ b/src/js/defaults.js Wed Jun 20 14:45:30 2012 +0200
@@ -13,7 +13,8 @@
jwplayer : "jwplayer.js",
raphael : "raphael-min.js",
tracemanager : "tracemanager.js",
- jwPlayerSWF : "player.swf"
+ jwPlayerSWF : "player.swf",
+ json : "json2.js"
},
locations : {
// use to define locations outside defautl_dir
--- a/src/js/init.js Tue Jun 12 19:44:20 2012 +0200
+++ b/src/js/init.js Wed Jun 20 14:45:30 2012 +0200
@@ -55,8 +55,13 @@
.script(IriSP.getLib("underscore"))
.script(IriSP.getLib("Mustache"))
.script(IriSP.getLib("jQuery"))
- .script(IriSP.getLib("swfObject"))
- .wait()
+ .script(IriSP.getLib("swfObject"));
+
+ if (typeof JSON == "undefined") {
+ $L.script(IriSP.getLib("json"));
+ }
+
+ $L.wait()
.script(IriSP.getLib("jQueryUI"));
if (this.config.player.type === "jwplayer" || this.config.player.type === "auto") {
@@ -175,7 +180,7 @@
IriSP.Metadataplayer.prototype.configurePopcorn = function() {
IriSP.log("IriSP.Metadataplayer.prototype.configurePopcorn");
var pop,
- ret = this.layoutDivs("video"),
+ ret = this.layoutDivs("video",this.config.player.height || undefined),
containerDiv = ret[0],
spacerDiv = ret[1],
_this = this,
@@ -285,6 +290,10 @@
pop = new IriSP.PopcornReplacement.allocine("#" + containerDiv, this.config.player);
break;
+ case "mashup-html":
+ pop = new IriSP.PopcornReplacement.htmlMashup("#" + containerDiv, this.config.player, this.videoData);
+ break;
+
default:
pop = undefined;
};
@@ -296,7 +305,7 @@
@param widgetName the name of the widget.
@return an array of the form [createdivId, spacerdivId].
*/
-IriSP.Metadataplayer.prototype.layoutDivs = function(_name) {
+IriSP.Metadataplayer.prototype.layoutDivs = function(_name, _height) {
if (typeof(_name) === "undefined") {
_name = "";
}
@@ -317,6 +326,9 @@
position: "relative",
clear: "both"
});
+ if (typeof _height !== "undefined") {
+ divHtml.css("height", _height);
+ }
this.$.append(divHtml);
this.$.append(spacerHtml);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/js/libs/json2.js Wed Jun 20 14:45:30 2012 +0200
@@ -0,0 +1,487 @@
+/*
+ json2.js
+ 2011-10-19
+
+ Public Domain.
+
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+ See http://www.JSON.org/js.html
+
+
+ This code should be minified before deployment.
+ See http://javascript.crockford.com/jsmin.html
+
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+ NOT CONTROL.
+
+
+ This file creates a global JSON object containing two methods: stringify
+ and parse.
+
+ JSON.stringify(value, replacer, space)
+ value any JavaScript value, usually an object or array.
+
+ replacer an optional parameter that determines how object
+ values are stringified for objects. It can be a
+ function or an array of strings.
+
+ space an optional parameter that specifies the indentation
+ of nested structures. If it is omitted, the text will
+ be packed without extra whitespace. If it is a number,
+ it will specify the number of spaces to indent at each
+ level. If it is a string (such as '\t' or ' '),
+ it contains the characters used to indent at each level.
+
+ This method produces a JSON text from a JavaScript value.
+
+ When an object value is found, if the object contains a toJSON
+ method, its toJSON method will be called and the result will be
+ stringified. A toJSON method does not serialize: it returns the
+ value represented by the name/value pair that should be serialized,
+ or undefined if nothing should be serialized. The toJSON method
+ will be passed the key associated with the value, and this will be
+ bound to the value
+
+ For example, this would serialize Dates as ISO strings.
+
+ Date.prototype.toJSON = function (key) {
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ return this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z';
+ };
+
+ You can provide an optional replacer method. It will be passed the
+ key and value of each member, with this bound to the containing
+ object. The value that is returned from your method will be
+ serialized. If your method returns undefined, then the member will
+ be excluded from the serialization.
+
+ If the replacer parameter is an array of strings, then it will be
+ used to select the members to be serialized. It filters the results
+ such that only members with keys listed in the replacer array are
+ stringified.
+
+ Values that do not have JSON representations, such as undefined or
+ functions, will not be serialized. Such values in objects will be
+ dropped; in arrays they will be replaced with null. You can use
+ a replacer function to replace those with JSON values.
+ JSON.stringify(undefined) returns undefined.
+
+ The optional space parameter produces a stringification of the
+ value that is filled with line breaks and indentation to make it
+ easier to read.
+
+ If the space parameter is a non-empty string, then that string will
+ be used for indentation. If the space parameter is a number, then
+ the indentation will be that many spaces.
+
+ Example:
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}]);
+ // text is '["e",{"pluribus":"unum"}]'
+
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+ text = JSON.stringify([new Date()], function (key, value) {
+ return this[key] instanceof Date ?
+ 'Date(' + this[key] + ')' : value;
+ });
+ // text is '["Date(---current time---)"]'
+
+
+ JSON.parse(text, reviver)
+ This method parses a JSON text to produce an object or array.
+ It can throw a SyntaxError exception.
+
+ The optional reviver parameter is a function that can filter and
+ transform the results. It receives each of the keys and values,
+ and its return value is used instead of the original value.
+ If it returns what it received, then the structure is not modified.
+ If it returns undefined then the member is deleted.
+
+ Example:
+
+ // Parse the text. Values that look like ISO date strings will
+ // be converted to Date objects.
+
+ myData = JSON.parse(text, function (key, value) {
+ var a;
+ if (typeof value === 'string') {
+ a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+ if (a) {
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+ +a[5], +a[6]));
+ }
+ }
+ return value;
+ });
+
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+ var d;
+ if (typeof value === 'string' &&
+ value.slice(0, 5) === 'Date(' &&
+ value.slice(-1) === ')') {
+ d = new Date(value.slice(5, -1));
+ if (d) {
+ return d;
+ }
+ }
+ return value;
+ });
+
+
+ This is a reference implementation. You are free to copy, modify, or
+ redistribute.
+*/
+
+/*jslint evil: true, regexp: true */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
+ test, toJSON, toString, valueOf
+*/
+
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+var JSON;
+if (!JSON) {
+ JSON = {};
+}
+
+(function () {
+ 'use strict';
+
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ if (typeof Date.prototype.toJSON !== 'function') {
+
+ Date.prototype.toJSON = function (key) {
+
+ return isFinite(this.valueOf())
+ ? this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z'
+ : null;
+ };
+
+ String.prototype.toJSON =
+ Number.prototype.toJSON =
+ Boolean.prototype.toJSON = function (key) {
+ return this.valueOf();
+ };
+ }
+
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ gap,
+ indent,
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ rep;
+
+
+ function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+ escapable.lastIndex = 0;
+ return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string'
+ ? c
+ : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"' : '"' + string + '"';
+ }
+
+
+ function str(key, holder) {
+
+// Produce a string from holder[key].
+
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+ if (value && typeof value === 'object' &&
+ typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
+
+// What happens next depends on the value's type.
+
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
+
+ case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+ return isFinite(value) ? String(value) : 'null';
+
+ case 'boolean':
+ case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+ return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+ case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+ if (!value) {
+ return 'null';
+ }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+ gap += indent;
+ partial = [];
+
+// Is the value an array?
+
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+ v = partial.length === 0
+ ? '[]'
+ : gap
+ ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
+ : '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ if (typeof rep[i] === 'string') {
+ k = rep[i];
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+ for (k in value) {
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+ v = partial.length === 0
+ ? '{}'
+ : gap
+ ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
+ : '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
+ }
+ }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+ if (typeof JSON.stringify !== 'function') {
+ JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+ var i;
+ gap = '';
+ indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
+ }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('JSON.stringify');
+ }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+ return str('', {'': value});
+ };
+ }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+ if (typeof JSON.parse !== 'function') {
+ JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+ var j;
+
+ function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
+ }
+ }
+ }
+ }
+ return reviver.call(holder, key, value);
+ }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+ text = String(text);
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' +
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+ if (/^[\],:{}\s]*$/
+ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
+ .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
+ .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+ j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+ return typeof reviver === 'function'
+ ? walk({'': j}, '')
+ : j;
+ }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+ throw new SyntaxError('JSON.parse');
+ };
+ }
+}());
--- a/src/js/model.js Tue Jun 12 19:44:20 2012 +0200
+++ b/src/js/model.js Wed Jun 20 14:45:30 2012 +0200
@@ -1,3 +1,5 @@
+/* TODO: Separate Project-specific data from Source */
+
/* model.js is where data is stored in a standard form, whatever the serializer */
IriSP.Model = {
@@ -294,11 +296,11 @@
}
IriSP.Model.Time.prototype.getSeconds = function() {
- return Math.floor(this.milliseconds / 1000);
+ return this.milliseconds / 1000;
}
IriSP.Model.Time.prototype.getHMS = function() {
- var _totalSeconds = Math.abs(this.getSeconds());
+ var _totalSeconds = Math.abs(Math.floor(this.getSeconds()));
return {
hours : Math.floor(_totalSeconds / 3600),
minutes : (Math.floor(_totalSeconds / 60) % 60),
@@ -779,6 +781,9 @@
}
IriSP.Model.Directory.prototype.remoteSource = function(_properties) {
+ if (typeof _properties !== "object" || typeof _properties.url === "undefined") {
+ throw "Error : IriSP.Model.Directory.remoteSource(configuration): configuration.url is undefined";
+ }
var _config = IriSP._({ directory: this }).extend(_properties);
if (typeof this.remoteSources[_properties.url] === "undefined") {
this.remoteSources[_properties.url] = new IriSP.Model.RemoteSource(_config);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/js/players/player.mashup-html.js Wed Jun 20 14:45:30 2012 +0200
@@ -0,0 +1,143 @@
+/* To wrap a player the develop should create a new class derived from
+ the IriSP.PopcornReplacement.player and defining the correct functions */
+
+/** jwplayer player wrapper */
+IriSP.PopcornReplacement.htmlMashup = function(container, options, metadata) {
+ /* appel du parent pour initialiser les structures communes à tous les players */
+ IriSP.PopcornReplacement.player.call(this, container, options);
+
+ this.mashup = metadata.currentMedia;
+ this.$ = IriSP.jQuery(container);
+
+ var _w = this.$.width(),
+ _h = this.$.height(),
+ _this = this;
+
+ IriSP._(metadata.currentMedia.medias).each(function(_media) {
+ var _tmpId = Popcorn.guid("video"),
+ _videoEl = IriSP.jQuery('<video>');
+
+ _videoEl
+ .attr({
+ src : _media.video,
+ id : _tmpId,
+ width : _w,
+ height : _h
+ })
+ .css({
+ position: "absolute",
+ top: 0,
+ left: 0
+ });
+
+ _this.$.append(_videoEl);
+ _media.videoEl = _videoEl;
+ _media.popcorn = Popcorn("#" + _tmpId);
+ _media.popcorn.on("timeupdate", function() {
+ if (!_this.media.paused && _media === _this.currentMedia) {
+ var _time = _media.popcorn.currentTime();
+ // var _status = "Timeupdate from " + _media.id + " at time " + _time;
+ if ( _time < _this.segmentEnd ) {
+ if ( _time >= _this.segmentBegin ) {
+ _this.timecode = _time - _this.timedelta;
+ // _status += " within segment";
+ } else {
+ _this.timecode = _this.segmentBegin - _this.timedelta;
+ _media.popcorn.currentTime(_this.segmentBegin);
+ // _status += " before segment begin";
+ }
+ } else {
+ _this.timecode = _this.segmentEnd - _this.timedelta;
+ _media.popcorn.pause();
+ _this.changeCurrentAnnotation();
+ // _status += " after segment end";
+ }
+ /* _status += ", translated to " + _this.timecode;
+ console.log(_status); */
+ _this.trigger("timeupdate");
+ }
+ });
+ });
+
+ this.timecode = 0;
+
+ /* Définition des fonctions de l'API */
+ this.playerFns = {
+ play: function() {
+ _this.changeCurrentAnnotation();
+ },
+ pause: function() {
+ _this.currentMedia.popcorn.pause();
+ },
+ getPosition: function() {
+ return _this.timecode;
+ },
+ seek: function(pos) {
+ _this.timecode = pos;
+ _this.changeCurrentAnnotation();
+ },
+ getMute: function() {
+ return
+ typeof _this.currentMedia !== "undefined"
+ ? _this.currentMedia.popcorn.muted()
+ : false;
+ },
+ setMute: function(p) {
+ var _mute = !!p;
+ for (var _i = 0; _i < _this.mashup.medias.length; _i++) {
+ _this.mashup.medias[_i].popcorn.muted(_mute);
+ }
+ },
+ getVolume: function() {
+ return
+ typeof _this.currentMedia !== "undefined"
+ ? _this.currentMedia.popcorn.volume()
+ : .5;
+ },
+ setVolume: function(_vol) {
+ for (var _i = 0; _i < _this.mashup.medias.length; _i++) {
+ _this.mashup.medias[_i].popcorn.volume(_vol);
+ }
+ }
+ }
+/*
+ options.events = this.callbacks;
+
+ _player.setup(options);
+ */
+};
+
+IriSP.PopcornReplacement.htmlMashup.prototype = new IriSP.PopcornReplacement.player("", {});
+
+IriSP.PopcornReplacement.htmlMashup.prototype.changeCurrentAnnotation = function() {
+ var _annotation = this.mashup.getAnnotationAtTime( 1000 * this.timecode );
+ if (typeof _annotation == "undefined") {
+ if (typeof this.currentMedia !== "undefined") {
+ this.currentMedia.popcorn.pause();
+ this.media.paused = true;
+ }
+ return;
+ }
+ if (_annotation !== this.currentAnnotation) {
+ this.currentAnnotation = _annotation;
+ this.segmentBegin = this.currentAnnotation.annotation.begin.getSeconds();
+ this.segmentEnd = this.currentAnnotation.annotation.end.getSeconds();
+ this.timedelta = this.segmentBegin - this.currentAnnotation.begin.getSeconds();
+ this.currentMedia = this.currentAnnotation.getMedia();
+
+ for (var _i = 0; _i < this.mashup.medias.length; _i++) {
+ if (this.mashup.medias[_i].id !== this.currentMedia.id) {
+ this.mashup.medias[_i].videoEl.hide();
+ this.mashup.medias[_i].popcorn.pause();
+ } else {
+ this.mashup.medias[_i].videoEl.show();
+ }
+ }
+ }
+ if (this.currentMedia.popcorn.readyState()) {
+ this.currentMedia.popcorn.currentTime(this.timecode + this.timedelta);
+ }
+ if (!this.media.paused) {
+ this.currentMedia.popcorn.play();
+ }
+}
--- a/src/js/pop.js Tue Jun 12 19:44:20 2012 +0200
+++ b/src/js/pop.js Wed Jun 20 14:45:30 2012 +0200
@@ -33,7 +33,7 @@
a segment (similar to the popcorn.code plugin). */
this._options = options;
-
+
};
IriSP.PopcornReplacement.player.prototype.listen = function(msg, callback) {
@@ -43,6 +43,8 @@
this.msgPump[msg].push(callback);
};
+IriSP.PopcornReplacement.player.prototype.on = IriSP.PopcornReplacement.player.prototype.listen;
+
IriSP.PopcornReplacement.player.prototype.trigger = function(msg, params) {
if (!this.msgPump.hasOwnProperty(msg))
return;
@@ -55,6 +57,8 @@
};
+IriSP.PopcornReplacement.player.prototype.emit = IriSP.PopcornReplacement.player.prototype.trigger;
+
IriSP.PopcornReplacement.player.prototype.guid = function(prefix) {
var str = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
@@ -98,16 +102,13 @@
IriSP.PopcornReplacement.player.prototype.play = function() {
this.media.paused = false;
this.trigger("play");
- //IriSP.PopcornReplacement.trigger("playing");
this.playerFns.play();
};
IriSP.PopcornReplacement.player.prototype.pause = function() {
-// if ( !this.media.paused ) {
this.media.paused = true;
this.trigger( "pause" );
this.playerFns.pause();
-// }
};
IriSP.PopcornReplacement.player.prototype.muted = function(val) {
@@ -147,7 +148,13 @@
return _vol;
};
-IriSP.PopcornReplacement.player.prototype.mute = IriSP.PopcornReplacement.player.prototype.muted;
+IriSP.PopcornReplacement.player.prototype.mute = function() {
+ this.muted(true);
+}
+
+IriSP.PopcornReplacement.player.prototype.unmute = function() {
+ this.muted(false);
+}
IriSP.PopcornReplacement.player.prototype.code = function(options) {
this.__codes.push(options);
--- a/src/js/serializers/ldt.js Tue Jun 12 19:44:20 2012 +0200
+++ b/src/js/serializers/ldt.js Wed Jun 20 14:45:30 2012 +0200
@@ -25,6 +25,10 @@
_res.title = _data.meta["dc:title"];
_res.description = _data.meta["dc:description"];
_res.setDuration(_data.meta["dc:duration"]);
+ _res.url = _data.meta.url;
+ if (typeof _data.meta.img !== "undefined" && _data.meta.img.src !== "undefined") {
+ _res.thumbnail = _data.meta.img.src;
+ }
return _res;
},
serializer : function(_data, _source) {
--- a/src/widgets/Controller.js Tue Jun 12 19:44:20 2012 +0200
+++ b/src/widgets/Controller.js Wed Jun 20 14:45:30 2012 +0200
@@ -196,7 +196,7 @@
};
IriSP.Widgets.Controller.prototype.muteHandler = function() {
- this.player.popcorn.mute(!this.player.popcorn.muted());
+ this.player.popcorn.muted(!this.player.popcorn.muted());
};
IriSP.Widgets.Controller.prototype.volumeUpdater = function() {
--- a/src/widgets/MediaList.css Tue Jun 12 19:44:20 2012 +0200
+++ b/src/widgets/MediaList.css Wed Jun 20 14:45:30 2012 +0200
@@ -83,4 +83,20 @@
margin: 2px 0 2px 62px;
font-size: 10px;
color: #666666;
-}
\ No newline at end of file
+}
+
+.Ldt-MediaList-Now-MediaView {
+ clear: both; width: 100%; height: 12px; margin: 5px 0 0; overflow: hidden; position: relative;
+}
+
+.Ldt-MediaList-Other-MediaView {
+ clear: both; width: 100%; height: 6px; margin: 5px 0 0; overflow: hidden; position: relative;
+}
+
+.Ldt-MediaList-MediaView-Background {
+ position: absolute; top: 0; left: 0; width: 100%; height: 100%; filter: alpha(opacity=50); opacity: 0.5; background: #999999;
+}
+
+.Ldt-MediaList-Segment {
+ position: absolute; top: 0; height: 100%; border-style: none solid; margin-left: -1px; border-color: #ffffff; border-width: 1px;
+}
--- a/src/widgets/MediaList.js Tue Jun 12 19:44:20 2012 +0200
+++ b/src/widgets/MediaList.js Wed Jun 20 14:45:30 2012 +0200
@@ -20,7 +20,8 @@
IriSP.Widgets.MediaList.prototype.defaults = {
default_thumbnail : "http://ldt.iri.centrepompidou.fr/static/site/ldt/css/imgs/video_sequence.png",
- media_url_template : "http://ldt.iri.centrepompidou.fr/ldtplatform/ldt/front/player/{{media}}/"
+ media_url_template : "http://ldt.iri.centrepompidou.fr/ldtplatform/ldt/front/player/{{media}}/",
+ default_color : "#000080"
};
IriSP.Widgets.MediaList.prototype.template =
@@ -29,14 +30,19 @@
+ '<div class="Ldt-MediaList-Now-ThumbContainer"><a href="" target="_blank">'
+ '<img class="Ldt-MediaList-Now-Thumbnail" src="" /></a></div>'
+ '<h3 class="Ldt-MediaList-Now-Title"><a href="" target="_blank"></a></h3>'
- + '<p class="Ldt-MediaList-Now-Description"></p></div></div>'
+ + '<p class="Ldt-MediaList-Now-Description"></p><div class="Ldt-MediaList-Now-MediaView"></div></div></div>'
+ '<div class="Ldt-MediaList-Other"><h2></h2><hr /><ul class="Ldt-MediaList-OtherList"></ul></div>';
+IriSP.Widgets.MediaList.prototype.mediaViewTemplate =
+ '<div class="Ldt-MediaList-MediaView-Background"></div>{{#segments}}<div class="Ldt-MediaList-Segment" style="background: {{color}}; left: {{left}}px; width: {{width}}px;"></div>{{/segments}}';
+
IriSP.Widgets.MediaList.prototype.mediaTemplate =
'<li class="Ldt-MediaList-OtherList-li"><div class="Ldt-MediaList-Other-ThumbContainer"><a href="{{url}}" target="_blank">'
+ '<img class="Ldt-MediaList-Other-Thumbnail" src="{{thumbnail}}" /></a></div>'
+ '<h3 class="Ldt-MediaList-Other-Title"><a href="{{url}}" target="_blank">{{title}}</a></h3>'
- + '<p class="Ldt-MediaList-Other-Description">{{description}}</p></li>'
+ + '<p class="Ldt-MediaList-Other-Description">{{description}}</p><div class="Ldt-MediaList-Other-MediaView">'
+ + IriSP.Widgets.MediaList.prototype.mediaViewTemplate + '</div></li>';
+
IriSP.Widgets.MediaList.prototype.onSearch = function(searchString) {
this.searchString = typeof searchString !== "undefined" ? searchString : '';
@@ -57,6 +63,23 @@
this.redraw();
};
+IriSP.Widgets.MediaList.prototype.getSegments = function(_media) {
+ var _this = this,
+ _scale = this.$.width()/_media.duration.milliseconds;
+ return this.getWidgetAnnotations()
+ .filter(function(_annotation) {
+ return _annotation.getMedia().id == _media.id;
+ })
+ .map(function(_a) {
+ var _annotation = ( _a.type = "mashedAnnotation" ? _a.annotation : _a );
+ return {
+ left: _scale * _annotation.begin,
+ width: _scale * (_annotation.end - _annotation.begin),
+ color: ( typeof _annotation.color !== "undefined" && _annotation.color ? _annotation.color : _this.default_color )
+ }
+ })
+}
+
IriSP.Widgets.MediaList.prototype.redraw = function(_media) {
if (typeof _media !== "undefined") {
this.$.find('.Ldt-MediaList-Other h2').html(this.l10n.other_media);
@@ -69,6 +92,10 @@
media: _media.id
});
this.$.find('.Ldt-MediaList-NowContainer a').attr("href", _url);
+ var _mediaView = Mustache.to_html( this.mediaViewTemplate, {
+ segments: this.getSegments(_media)
+ });
+ this.$.find('.Ldt-MediaList-Now-MediaView').html(_mediaView);
} else {
this.$.find('.Ldt-MediaList-Other h2').html(this.l10n.all_media);
this.$.find('.Ldt-MediaList-NowPlaying').hide();
@@ -87,7 +114,8 @@
media: _media.id
}),
title: _media.title,
- description: _media.description
+ description: _media.description,
+ segments: _this.getSegments(_media)
})
}).join("");
this.$.find('.Ldt-MediaList-OtherList').html(_html);
Binary file test/mashup/bab_files/player_bab_ldt.swf has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/mashup/moon.htm Wed Jun 20 14:45:30 2012 +0200
@@ -0,0 +1,99 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Preuve de concept Mashup</title>
+ <link rel="stylesheet" type="text/css" href="style.css" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" src="../metadataplayer/LdtPlayer-core.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <div class="main-container">
+ <div class="header">
+ <h1>Hash Cut #</h1>
+ </div>
+ <div class="steps">
+ <h2>Créer un Hash-cut en 3 étapes :</h2>
+ <div class="steps-frame">
+ <div class="step">
+ <div class="step-icon step-1"></div>
+ <div class="step-title">S'inscrire et<br />créer un projet</div>
+ </div>
+ <div class="step-separator"></div>
+ <div class="step">
+ <div class="step-icon step-2"></div>
+ <div class="step-title">Découper et<br />Assembler</div>
+ </div>
+ <div class="step-separator"></div>
+ <div class="step active">
+ <div class="step-icon step-3"></div>
+ <div class="step-title">Partager et<br />regarder !</div>
+ </div>
+ </div>
+ </div>
+ <div class="colgauche">
+ <h2>Mon HashCut</h2>
+ <hr />
+ <div id="LdtPlayer"></div>
+ </div>
+ <div class="coldroite">
+ <div id="mediaList"></div>
+ </div>
+ <div class="footer">
+ <hr />
+ <p style="text-align: right;">© IRI 2012</p>
+ </div>
+ </div>
+ <script type="text/javascript">
+
+IriSP.libFiles.defaultDir = "../libs/";
+IriSP.widgetsDir = "../metadataplayer";
+IriSP.language = 'fr';
+var _metadata = {
+ url: 'moon/moon.json',
+ format: 'ldt'
+};
+var _config = {
+ gui: {
+ width : 630,
+ container : 'LdtPlayer',
+ default_options: {
+ metadata: _metadata
+ },
+ css : '../metadataplayer/LdtPlayer-core.css',
+ widgets: [
+ { type: "Slider" },
+ { type: "Controller" },
+ {
+ type: "Segments",
+ annotation_type: false
+ },
+ { type: "Arrow" },
+ {
+ type: "Annotation",
+ annotation_type: false
+ },
+ {
+ type: "MediaList",
+ container: "mediaList"
+ },
+ { type: "Mediafragment" }
+ ]
+ },
+ player:{
+ type:'mashup-html',
+ live: true,
+ height: 350,
+ width: 630,
+ provider: "rtmp",
+ mashup_swf : "bab_files/player_bab_ldt.swf",
+ mashup_xml : "moon/moon.xml",
+ autostart: true,
+ metadata: _metadata
+ }
+};
+
+_myPlayer = new IriSP.Metadataplayer(_config);
+
+ </script>
+ </body>
+</html>
\ No newline at end of file
Binary file test/mashup/moon/apollo.jpg has changed
Binary file test/mashup/moon/atlas.jpg has changed
Binary file test/mashup/moon/melies.jpg has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/mashup/moon/moon.json Wed Jun 20 14:45:30 2012 +0200
@@ -0,0 +1,406 @@
+{
+ "views": null,
+ "tags": null,
+ "lists": null,
+ "medias": [
+ {
+ "origin": "0",
+ "url": "moon/melies.webm",
+ "http://advene.liris.cnrs.fr/ns/frame_of_reference/ms": "o=0",
+ "meta": {
+ "dc:contributor": "IRI",
+ "dc:created": "2011-09-19T13:17:56.656743",
+ "dc:duration": 674000,
+ "dc:creator": "IRI",
+ "dc:created.contents": "2012-02-13",
+ "dc:title": "Le Voyage dans la Lune de Méliès",
+ "dc:creator.contents": "IRI",
+ "dc:modified": "2012-02-13T11:55:33.052583",
+ "dc:description": "Georges Méliès, 1902. Domaine public.",
+ "url": "http://en.wikipedia.org/wiki/File:Le_Voyage_dans_la_Lune_%28Georges_M%C3%A9li%C3%A8s,_1902%29.ogv",
+ "img": {
+ "src": "moon/melies.jpg"
+ }
+ },
+ "id": "media-melies",
+ "unit": "ms"
+ },
+ {
+ "origin": "0",
+ "url": "moon/juno.webm",
+ "http://advene.liris.cnrs.fr/ns/frame_of_reference/ms": "o=0",
+ "meta": {
+ "dc:contributor": "IRI",
+ "dc:created": "2011-09-19T13:17:56.656743",
+ "dc:duration": 130000,
+ "dc:creator": "IRI",
+ "dc:created.contents": "2012-02-13",
+ "dc:title": "Launch of Juno!, NASA",
+ "dc:creator.contents": "IRI",
+ "dc:modified": "2012-02-13T11:55:33.052583",
+ "dc:description": "An Atlas V rocket lofted the Juno spacecraft toward Jupiter from Space Launch Complex-41. The 4-ton Juno spacecraft will take five years to reach Jupiter on a mission to study its structure and decipher its history. NASA, 2011. Domaine public.",
+ "url": "http://www.nasa.gov/multimedia/videogallery/index.html?media_id=105049051",
+ "img": {
+ "src": "moon/atlas.jpg"
+ }
+ },
+ "id": "media-atlas",
+ "unit": "ms"
+ },
+ {
+ "origin": "0",
+ "url": "moon/apollo.webm",
+ "http://advene.liris.cnrs.fr/ns/frame_of_reference/ms": "o=0",
+ "meta": {
+ "dc:contributor": "IRI",
+ "dc:created": "2011-09-19T13:17:56.656743",
+ "dc:duration": 137000,
+ "dc:creator": "IRI",
+ "dc:created.contents": "2012-02-13",
+ "dc:title": "Apollo 11 Overview, NASA",
+ "dc:creator.contents": "IRI",
+ "dc:modified": "2012-02-13T11:55:33.052583",
+ "dc:description": "Video highlights from the historic first manned landing on the moon, during the Apollo 11 mission in July 1969. NASA, 2011. Domaine public.",
+ "url": "http://www.nasa.gov/multimedia/videogallery/index.html?media_id=11463015",
+ "img": {
+ "src": "moon/apollo.jpg"
+ }
+ },
+ "id": "media-apollo",
+ "unit": "ms"
+ }
+ ],
+ "meta": {
+ "dc:contributor": "admin",
+ "dc:created": "2012-05-11T16:26:53.787298",
+ "dc:creator": "admin",
+ "main_media": {
+ "id-ref": "mashup-001"
+ },
+ "dc:description": "",
+ "dc:title": "To the Moon, feat. Méliès + NASA",
+ "id": "5afd8bbe-9b75-11e1-9e5d-00145ea4a2be",
+ "dc:modified": "2012-05-11T16:37:30.246796"
+ },
+ "annotations": [
+ {
+ "content": {
+ "mimetype": "application/x-ldt-structured",
+ "description": "Le Voyage dans la Lune, Segment 1",
+ "img": {
+ "src": ""
+ },
+ "title": "La capsule lunaire est chargée dans le canon permettant son lancement",
+ "color": "16763904",
+ "polemics": [],
+ "audio": {
+ "mimetype": "audio/mp3",
+ "src": "",
+ "href": null
+ }
+ },
+ "begin": 301000,
+ "end": 306000,
+ "meta": {
+ "dc:contributor": "perso",
+ "id-ref": "decoupage-melies",
+ "dc:created": "2012-05-11T15:08:00.348480",
+ "dc:modified": "2012-05-11T15:08:00.348480",
+ "dc:creator": "perso"
+ },
+ "tags": [],
+ "color": "10485760",
+ "media": "media-melies",
+ "id": "segment-melies-001"
+ },
+ {
+ "content": {
+ "mimetype": "application/x-ldt-structured",
+ "description": "Le Voyage dans la Lune, Segment 2",
+ "img": {
+ "src": ""
+ },
+ "title": "Ordre de mise à feu du canon propulseur",
+ "color": "16763904",
+ "polemics": [],
+ "audio": {
+ "mimetype": "audio/mp3",
+ "src": "",
+ "href": null
+ }
+ },
+ "begin": 314500,
+ "end": 316000,
+ "meta": {
+ "dc:contributor": "perso",
+ "id-ref": "decoupage-melies",
+ "dc:created": "2012-05-11T15:08:00.348480",
+ "dc:modified": "2012-05-11T15:08:00.348480",
+ "dc:creator": "perso"
+ },
+ "tags": [],
+ "color": "10485760",
+ "media": "media-melies",
+ "id": "segment-melies-002"
+ },
+ {
+ "content": {
+ "mimetype": "application/x-ldt-structured",
+ "description": "Le Voyage dans la Lune, Segment 3",
+ "img": {
+ "src": ""
+ },
+ "title": "La Lune se rapproche et dévoile son visage",
+ "color": "16763904",
+ "polemics": [],
+ "audio": {
+ "mimetype": "audio/mp3",
+ "src": "",
+ "href": null
+ }
+ },
+ "begin": 344000,
+ "end": 347000,
+ "meta": {
+ "dc:contributor": "perso",
+ "id-ref": "decoupage-melies",
+ "dc:created": "2012-05-11T15:08:00.348480",
+ "dc:modified": "2012-05-11T15:08:00.348480",
+ "dc:creator": "perso"
+ },
+ "tags": [],
+ "color": "10485760",
+ "media": "media-melies",
+ "id": "segment-melies-003"
+ },
+ {
+ "content": {
+ "mimetype": "application/x-ldt-structured",
+ "description": "Le Voyage dans la Lune, Segment 4",
+ "img": {
+ "src": ""
+ },
+ "title": "Alunissage et sortie de l'équipage",
+ "color": "16763904",
+ "polemics": [],
+ "audio": {
+ "mimetype": "audio/mp3",
+ "src": "",
+ "href": null
+ }
+ },
+ "begin": 348500,
+ "end": 358000,
+ "meta": {
+ "dc:contributor": "perso",
+ "id-ref": "decoupage-melies",
+ "dc:created": "2012-05-11T15:08:00.348480",
+ "dc:modified": "2012-05-11T15:08:00.348480",
+ "dc:creator": "perso"
+ },
+ "tags": [],
+ "color": "10485760",
+ "media": "media-melies",
+ "id": "segment-melies-004"
+ },
+ {
+ "content": {
+ "mimetype": "application/x-ldt-structured",
+ "description": "Lancement de la sonde Juno, Segment 1",
+ "img": {
+ "src": ""
+ },
+ "title": "Décompte du décollage de la fusée Atlas V",
+ "color": "16763904",
+ "polemics": [],
+ "audio": {
+ "mimetype": "audio/mp3",
+ "src": "",
+ "href": null
+ }
+ },
+ "begin": 7000,
+ "end": 11000,
+ "meta": {
+ "dc:contributor": "perso",
+ "id-ref": "decoupage-atlas",
+ "dc:created": "2012-05-11T15:08:00.348480",
+ "dc:modified": "2012-05-11T15:08:00.348480",
+ "dc:creator": "perso"
+ },
+ "tags": [],
+ "color": "32768",
+ "media": "media-atlas",
+ "id": "segment-atlas-001"
+ },
+ {
+ "content": {
+ "mimetype": "application/x-ldt-structured",
+ "description": "Lancement de la sonde Juno, Segment 2",
+ "img": {
+ "src": ""
+ },
+ "title": "La fusée Atlas V décolle",
+ "color": "16763904",
+ "polemics": [],
+ "audio": {
+ "mimetype": "audio/mp3",
+ "src": "",
+ "href": null
+ }
+ },
+ "begin": 16000,
+ "end": 19000,
+ "meta": {
+ "dc:contributor": "perso",
+ "id-ref": "decoupage-atlas",
+ "dc:created": "2012-05-11T15:08:00.348480",
+ "dc:modified": "2012-05-11T15:08:00.348480",
+ "dc:creator": "perso"
+ },
+ "tags": [],
+ "color": "32768",
+ "media": "media-atlas",
+ "id": "segment-atlas-002"
+ },
+ {
+ "content": {
+ "mimetype": "application/x-ldt-structured",
+ "description": "Lancement de la sonde Juno, Segment 3",
+ "img": {
+ "src": ""
+ },
+ "title": "La fusée Atlas V en vol",
+ "color": "16763904",
+ "polemics": [],
+ "audio": {
+ "mimetype": "audio/mp3",
+ "src": "",
+ "href": null
+ }
+ },
+ "begin": 35000,
+ "end": 38000,
+ "meta": {
+ "dc:contributor": "perso",
+ "id-ref": "decoupage-atlas",
+ "dc:created": "2012-05-11T15:08:00.348480",
+ "dc:modified": "2012-05-11T15:08:00.348480",
+ "dc:creator": "perso"
+ },
+ "tags": [],
+ "color": "32768",
+ "media": "media-atlas",
+ "id": "segment-atlas-003"
+ },
+ {
+ "content": {
+ "mimetype": "application/x-ldt-structured",
+ "description": "Mission Apollo 11, Segment 1",
+ "img": {
+ "src": ""
+ },
+ "title": "Décollage du lanceur Saturn V",
+ "color": "16763904",
+ "polemics": [],
+ "audio": {
+ "mimetype": "audio/mp3",
+ "src": "",
+ "href": null
+ }
+ },
+ "begin": 20000,
+ "end": 23000,
+ "meta": {
+ "dc:contributor": "perso",
+ "id-ref": "decoupage-apollo",
+ "dc:created": "2012-05-11T15:08:00.348480",
+ "dc:modified": "2012-05-11T15:08:00.348480",
+ "dc:creator": "perso"
+ },
+ "tags": [],
+ "color": "16763904",
+ "media": "media-apollo",
+ "id": "segment-apollo-001"
+ },
+ {
+ "content": {
+ "mimetype": "application/x-ldt-structured",
+ "description": "Mission Apollo 11, Segment 2",
+ "img": {
+ "src": ""
+ },
+ "title": "'One small step for man, one giant leap for mankind'",
+ "color": "16763904",
+ "polemics": [],
+ "audio": {
+ "mimetype": "audio/mp3",
+ "src": "",
+ "href": null
+ }
+ },
+ "begin": 62500,
+ "end": 75500,
+ "meta": {
+ "dc:contributor": "perso",
+ "id-ref": "decoupage-apollo",
+ "dc:created": "2012-05-11T15:08:00.348480",
+ "dc:modified": "2012-05-11T15:08:00.348480",
+ "dc:creator": "perso"
+ },
+ "tags": [],
+ "color": "16763904",
+ "media": "media-apollo",
+ "id": "segment-apollo-002"
+ }
+ ],
+ "annotation-types": [
+ {
+ "dc:contributor": "perso",
+ "dc:creator": "perso",
+ "dc:title": "Segments du Voyage sur la Lune",
+ "id": "decoupage-melies",
+ "dc:created": "2012-05-11T15:08:00.348480",
+ "dc:description": "",
+ "dc:modified": "2012-05-11T15:08:00.348480"
+ },
+ {
+ "dc:contributor": "perso",
+ "dc:creator": "perso",
+ "dc:title": "Segments du Lancement de Juno",
+ "id": "decoupage-atlas",
+ "dc:created": "2012-05-11T15:08:00.348480",
+ "dc:description": "",
+ "dc:modified": "2012-05-11T15:08:00.348480"
+ },
+ {
+ "dc:contributor": "perso",
+ "dc:creator": "perso",
+ "dc:title": "Segments d'Apollo 11",
+ "id": "decoupage-apollo",
+ "dc:created": "2012-05-11T15:08:00.348480",
+ "dc:description": "",
+ "dc:modified": "2012-05-11T15:08:00.348480"
+ }
+ ],
+ "mashups": [
+ {
+ "id": "mashup-001",
+ "meta": {
+ "dc:title": "Example mashup",
+ "dc:description": "This is an example mashup"
+ },
+ "segments": [
+ "segment-melies-001",
+ "segment-atlas-001",
+ "segment-melies-002",
+ "segment-apollo-001",
+ "segment-atlas-002",
+ "segment-melies-003",
+ "segment-atlas-003",
+ "segment-melies-004",
+ "segment-apollo-002"
+ ]
+ }
+ ]
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/mp4video.htm Wed Jun 20 14:45:30 2012 +0200
@@ -0,0 +1,21 @@
+<!doctype html>
+<html>
+
+ <head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+ <title>Metadataplayer test with HTML5 / OGG Video</title>
+ <link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
+ <link href='test.css' rel='stylesheet' type='text/css'>
+ <script type="text/javascript" src="metadataplayer/LdtPlayer-core.js" type="text/javascript"></script>
+ <script type="text/javascript" src="test-config.js" type="text/javascript"></script>
+ </head>
+
+ <body>
+ <h1>Metadataplayer test with HTML5 / H.264 Video - Does not work with Firefox and Chrome</h1>
+ <div id="LdtPlayer"></div>
+ <div id="AnnotationsListContainer"></div>
+ <script type="text/javascript">
+ testConfig('json/ldt-ogv.json', true, "trailer.mp4", "html5");
+ </script>
+ </body>
+</html>
--- a/test/oggvideo.htm Tue Jun 12 19:44:20 2012 +0200
+++ b/test/oggvideo.htm Wed Jun 20 14:45:30 2012 +0200
@@ -11,7 +11,7 @@
</head>
<body>
- <h1>Metadataplayer test with HTML5 / OGG Video</h1>
+ <h1>Metadataplayer test with HTML5 / OGG Video - Does not work with IE and Safari</h1>
<div id="LdtPlayer"></div>
<div id="AnnotationsListContainer"></div>
<script type="text/javascript">
--- a/test/test-config.js Tue Jun 12 19:44:20 2012 +0200
+++ b/test/test-config.js Wed Jun 20 14:45:30 2012 +0200
@@ -1,4 +1,4 @@
-function testConfig(_urlMetadata, _useLocalBuild) {
+function testConfig(_urlMetadata, _useLocalBuild, _video, _playerType) {
document.getElementById('LdtPlayer').innerHTML = '';
_useLocalBuild = (typeof _useLocalBuild !== "undefined" && _useLocalBuild)
IriSP.libFiles.defaultDir = _useLocalBuild ? "libs/" : "../src/js/libs/";
@@ -31,12 +31,12 @@
type: "AnnotationsList",
container: "AnnotationsListContainer"
},
- { type: "Mediafragment"},
- {
+ { type: "Mediafragment"}
+/* {
type: "Trace",
default_subject: "tests-iri",
js_console: true
- }
+ } */
]
},
player:{
@@ -49,6 +49,12 @@
metadata: _metadata
}
};
+ if (typeof _playerType != "undefined") {
+ _config.player.type = _playerType;
+ }
+ if (typeof _video != "undefined") {
+ _config.player.video = _video;
+ }
return new IriSP.Metadataplayer(_config);
}
\ No newline at end of file