Apr 152013
 
videointerface002

Das HTML5 Videointerface, kann als Jquery/HTML5/Canvas Tool viel mehr, als es Flash je leisten könnte, ohne Player und mit einem Bruchteil des Codes, der vom Server zum Client übertragen werden muß. Dadurch ist das Interface auch zur Ausgabe von Videocontent auf Smartphone tauglich. Dank direkter Ausgabe in HTML, sind alle Daten zu Filmen, Ausschnitten und Cuepoints, von Bots zu lesen, was SEO einfache und umfangreiche unterstützt. Ajax, verlagert längere Ladeprozesse in den Hintergrund. Links von beliebigen HTML Seiten, können nicht nur auf Videos verweisen, sondern direkt zu einer bestimmten Zeitpunkt, innerhalb eines Videos führen. Das Interface kann als Frontend von Gallery2, WordPress, Typo3, Magento sowie text oder XML Dateien administriert werden. Dazu ist weder ein CMS-Interface notwendig, noch muss die administrierende Anwendung auf dem selben Server oder der selben Domain installiert sein.

Cuepointsteuerung & Timelinks

Über Cuepoints lassen sich bestimmte Zeitmarken in einem Videoclip, mit einem interaktiven Ereignis verbinden. In der Videoansicht lassen sich zudem Bestimmte Zeitintervalle aus dem Video direkt als Link aufrufen. Das Video wird dabei mit der Id als URL Parameter aufgerufen:
http://www.addit-media.net/new/uploads/jq-develop/index.php?id=0
Gut das geht mit Anderen auch, aber ein bestimmter Zeitpunkt innerhalb des Videos (z.B. 2 min.), wird schon schwieriger:
http://www.addit-media.net/new/uploads/jq-develop/index.php?id=0&t=120
Oder, nur einen bestimmten Zeitabschnitt, innerhalb des Videos (z.B. von 2 min. – 2.30 min.). Ruft man das Video mit diesem Link auf, spielt er das Video ab 120 sec. und stoppt bei 150 sec.:
http://www.addit-media.net/new/uploads/jq-develop/index.php?id=0&t=120,150

Natürlich, muss das Video nur in einer Version hochgeladen werden. Beim ersten Aufruf der Videoansicht, werden die Cuepoint-Thumbnails und die für die unterschiedlichen Browser notwenndigen Videoformate selbständig berechnet und stehen dann für die Listenansicht zur Verfügung, sobald diese gerechnet sind. In der Listenansicht, wurde die übliche UI-Navigation, durch einen Streifen mit den Cuepoint-Thumbs ersetzt, über die man die Videos vor und zurückspulen kann.

Videoansicht

Bild 1 von 3

DieVideoansicht, zeigt ein ausgewähltes Video incl. Details

 

Apr 072013
 
VideoInter004

NeverLookBehindV2 from Stefan Weiss on Vimeo. Never look behind mit Cuepoints auf addit-media.net/video

Die Cuepoints Liste in Sekunden.

0  = Start
1  = Durch die Kollision zweier Zwillingsplaneten, auf der gleichen Umlaufbahn um die Sonne, vor 4,5 Milliarden Jahren, entsteht ein Planet und ein Trümmerfeld.
10 = Der Planet, kühlt an der Oberfläche ab, sodass eine dünne feste Kruste, auf dem ansonsten flüssigen Planet entsteht.
25 = Die Kruste zereisst in fragile Platten, die auf dem flüssigem Gestein im Inneren schwimmen.
48 = Die jetzt um den Planet kreisenden Trümmer des zweiten Planeten, verdichten sich zu einem neuen Himmelskörper, dem Erdmond.
60 = Durch die Kollission, wurde die Erde nicht nur größer, sondern bekam auch einen größeren Eisenkern, der ein starkes Magnetfeld erzeugt, welches gefährliche Strahlung aus dem All ablenkt, was von der Erde aus als Polarlichter sichtbar wird.
81 = Der Planet hat zufälligerweise genau den Abstand zur Sonne, der eine Temperatur auf der Oberfläche entstehen lässt, dass Wasser in flüssigem Zustand vorhanden ist.
120 = Wärme aus dem Inneren und Energie der Sonne, lassen Wasser zum Teil verdampfen und aus dem heissen Inneren treten Gase aus. Dank der Kollision reicht die Gravidation aus, dass diese sich wie eine Hülle um den Planeten legen. Es entsteht eine Atmosphäre.
138 = Der Umlauf des Mondes erzeugt durch seine Anziehungskraft, Ebbe und Flut, der Meere, in denen sich das Leben entwickelt.
150 = 3 milliarden Jahre leben nur Einzeller, erst dann entstehen komplexere Lebewesen.
166 = Mindestens 2 Mal schlagen Asteroiden auf der Erde ein und töten beinahe alles Leben, dass sich bis dahin entwickelt hatte.
185 = Der Mensch ist allerdings das einzige Lebewesen, dass in der Lage ist, das Erscheinungsbild des Planeten nachhaltig zu verändern.
193 = Stehen Mond und Sonne, von der Erde aus in der selben Richtung, addieren sich deren Gravitationkräfte und ziehen eine gewaltige Springflut den Amazonas hundert kilometer Flussaufwärts.
221 = Wellen speichern die Energie, der Mondgravidation und des Windes, die von Surfern genutzt wird. Eine einzige dieser Wellen, kracht mit einem Druck von 4 Tonnen auf den Strand.
246 = Mehrfach in der Geschichte des Planeten, war das komplette Wasser gefrohren. Die Wärme aus dem Erdinneren, verhinderte aber immer wieder, dass dieser Zustand entgültig blieb.
301 = Im flüssigen Zustand verändert Wasser ständig das Angesicht der Erde und macht die Veränderung zum Einzigen was konstant bleibt.
322 = Die Atmosphäre, ist rein technisch ein Gasgemisch.
351 = Immer wieder konnte sich Leben aufs Neue anpassen und bildete sich in Millionen unterschiedlicher Arten aus.
368 = Fällt man aus dem Weltraum, auf die Erde zu, fühlt sich die Atmosphäre wie eine Flüssigkeit an, sodass man Wassersportarten darin ausüben kann und die kleinere Brocken aus dem Weltall, beim Aufschlag darauf verglühen und nicht in die Oberfläche einschlagen lässt.
436 = Tatsächlich ist der Einfluss des Menschen, auf den Planeten, so gravierend, dass das Zeitalter des Menschen, wissenschaftlich gesehen, eine eigene Erdgeschichtliche Epoche darstellt. Das Anthropozän. Nimmt man für die Lebenszeit der Erde 1 Tag an, entfallen auf das Anthropozän 0,2 s davon.

Hier steht wie’s geht ( http://news.addit-media.net/2012/04/html5player-mit-cuepoints/ )

Jan 162013
 
Love Bizarre 6 paula-mix

“Love Bizarre” ist Thema der Partyreihe Love Bizarre Party

Die Party, soll über Videoclips, die von der  Facebookseite der Veranstaltung an Freunde verteilt werden, bekannt gemacht werden. Da für die Videoclips aktuell nur Foto- aber kein Filmmaterial vorhanden ist, können nur Slideshows geschnitten werden, was sich zukünftig jedoch ändern soll. Wir werden daher, zur Erstellung eigener Videosequenzen Models braucht, in diesem Fall sogar ganz Spezielle, die wir uns selbst suchen werden. Bei der weitgehend aus extrovertierten Individualisten bestehenden Szene, die eigentlich immer Bedarf an professioneller Selbstdarstellung haben, ist es naheliegend, diese auch direkt dort zu casten. Der Aufruf zum Casting per Videoclip, soll Bedarf wecken, selbst Teil einer solchen Produktion zu sein und muss regelmässig über die Facebookseite der Veranstaltung verteilt werden. Die Models aus dem Casting, können zudem noch andere, repräsentative Aufgaben, auf den Partys, z.B. als Hostessen o.Ä., übernehmen und zu VIPs oder Ikonen der Partys stilisiert werden. Das Video dokumentiert die Entwicklung, vom ersten Layout zum fertigen Clip, anhand dieses Castingaufrufs.

Socialnetwork Marketing mit Videoclips

Eine statistische Auswertung der Lovebizarreparty Facebookseite zeigt, daß die Viralität, das ist der Prozentsatz der User, die einen Post teilen, für die Videos bei 30 – 50% lag. Bei einem Post mit Bild, im Stil eines Flyers, bei nichtmal 5%. Da der Vertriebsweg der Videos Web2.0 ist werden alle Versionen in einen youTube Channel hochgeladen, aber nicht gelistet.Dort können sie von den Kunden abgenommen werden. Nach erfolgter Abnahme durch den Kunden, werden sie als öffentlich deklariert und an die Facebookseite der Party ausgeliefert, sprich: Mit dieser geteilt. Zum bekanntmachen einer Party, ist Web2.0 durchaus ein brauchbarer Verteiler, allerdings bleiben die User dabei immer User des Networks, Traffic für die eigene Website, also “echte” Kunden, lassen sich damit nicht gewinnen.

Das Video zeigt, wie sich der Clip entwickelt hat.

Apr 092012
 

Zur Browserverbreitung, gibt es ja Einiges im Web, aber diese Darstellung ist eine der Besten, die zu finden war, sie berücksichtigt nicht nur die absolute Menge von Browsern, sondern enthält auch die einzelnen Browserversionen in einer Übersicht.

(Das Bild anklicken um sie als Interaktive Statistik zu öffnen.)

Basis für die Statistik sind die monatlichen zahlen, der W3 School. Leider gilt sie nur für Europa, weltweit sieht das vermutlich anders aus, so ist z.B. in Südamerika Google Chrom mittlerweilen bereits auf Platz1 in der Statistik für Marktanteile. Die Fachwelt prognostiziert Dieses auch für alle anderen Kontinente bis auf Asien, bis Ende 2012.

Apr 022012
 
tt013

In dem Post vom 27.2.2012, habe ich einen Flashplayer vorgestellt, mit dem man auch Cuepoints ansteuern kann die Bestandteil einer Flash .flv-Dateien sind. Man kann die Punkte nicht nur direkt ansteuern, sondern es können auch Daten, die mit den Punkten verbunden sind angezeigt werden, sobald der Film einen Cuepoint überläuft. Diese Cuepoints sind eine Flash-spezifische Eigenheit, die in anderen Videoformaten nicht vorhanden sind. Da unser Kunde seine Videos aber auch auf iPads anschaun möchte, brauchten wir

Cuepoints für einen HTML5-Player.

Hier gehts zu unserer Beispielanwendung

Unser Beispiel verwendet zwar keine echten Flash Cuepoints sondern eine Javascript Ersatz für Cuepoints, funktioniert aber tatsächlich genauso gut. Sie hat gegenüber der Flash Version, sogar den Vorteil, das die Punkte nicht Bestandteil des Videos sein müssen sondern auch noch nachträglich beim Aufruf der Seite gesetzt werden können, was diese HTML5 Variante sogar flexibler macht als die Flash Version und sie läuft natürlich, wie alle HTML5 Player, auch auf dem iPad.

Und so sieht der Scriptcode aus:

(function() {
var Cuepoint, Utils, utils;
Utils = (function() {
function Utils() {}
Utils.prototype.log = function(args) {
this.args = args;
if (window.console) {
return console.log(Array.prototype.slice.call(this, arguments));
}
};
return Utils;
})();
Cuepoint = (function() {
function Cuepoint() {
this.nativeKeys = Object.keys;
}
Cuepoint.prototype.init = function(slides) {
var key, value, _results;
this.slides = slides;
this.subtitles = document.getElementById(“subtitles”);
this.video = document.getElementById(“video”);
_results = [];
for (key in slides) {
value = slides[key];
this.addSlide(key, value);
_results.push(this.events.call);
}
return _results;
};
Cuepoint.prototype.events = function() {};
Cuepoint.prototype.currentTime = function() {
return this.video.currentTime;
};
Cuepoint.prototype.update = function(html) {
this.html = html;
return this.subtitles.innerHTML = this.html;
};
Cuepoint.prototype.setTime = function(time) {
this.time = time;
this.video.currentTime = time;
return this.video.play();
};
Cuepoint.prototype.addSlide = function(time, html) {
var self;
this.time = time;
this.html = html;
self = this;
return this.video.addEventListener(“timeupdate”, function() {
if (this.currentTime >= time && this.currentTime <= time + 0.3) {
return self.update(html);
}
},
false);
};
Cuepoint.prototype.play = function() {
return this.video.play();
};
Cuepoint.prototype.pause = function() {
if (!this.video.paused) {
return this.video.pause();
}
};
return Cuepoint;
})();
utils = new Utils;
window.cuepoint = new Cuepoint;
}).call(this);

Dann brauchen wir noch die Ready Funktion, die das Javascript aus der HTML Seite aufruft:

Dieses Script wird im Header der .html-Datei eingefügt, die den HTML5 Player enthält.

<script>
$(document).ready(function(){
//Slides object mit time (integer) und html string
var slides = {
15: “Etno”,
25: “Kurierstyle”,
36: “Madona”,
47: “Moskau”,
60: “Nostalgie”,
71: “Bikerstyle”,
79: “kitzbühl”,
85: “Vienna”,
89: “Firenze”,
94: “Davos”,
102: “Firenze”,
110: “Sorbet”,
122: “Las Vegas”,
128: “Schuhe”,
137: “Beautycase”
}
//cuepoints starten und die Subtitles übergeben.
cuepoint.init(slides);

//Hier sind die Aufruffunktionen die natürlich auf der Seite platziert sein müssen, cuepoint.setTime(seconds) funktionen
$(‘#1′).click(function(){ cuepoint.setTime(15)});
$(‘#2′).click(function(){ cuepoint.setTime(25)});
$(‘#3′).click(function(){ cuepoint.setTime(36)});
$(‘#4′).click(function(){ cuepoint.setTime(47)});
$(‘#5′).click(function(){ cuepoint.setTime(60)});
$(‘#6′).click(function(){ cuepoint.setTime(71)});
$(‘#7′).click(function(){ cuepoint.setTime(79)});
$(‘#8′).click(function(){ cuepoint.setTime(85)});
$(‘#9′).click(function(){ cuepoint.setTime(89)});
$(‘#10′).click(function(){ cuepoint.setTime(94)});
$(‘#11′).click(function(){ cuepoint.setTime(102)});
$(‘#12′).click(function(){ cuepoint.setTime(110)});
$(‘#13′).click(function(){ cuepoint.setTime(122)});
$(‘#14′).click(function(){ cuepoint.setTime(128)});
$(‘#15′).click(function(){ cuepoint.setTime(137)});
});
</script>

Und natürlich der HTML5 Player, der innerhalb des <body> Tags, wo auch immer platziert wird:

<section id=’cuePlayer’>
<video id=’video’ width=”100%” preload=”auto” controls=”controls” poster=”http://addit-media.net/new/uploads/francoroma/VideoJukebox/p0000005673_2.jpg” autoplay=”autoplay”>
<source src=’http://addit-media.net/new/uploads/francoroma/VideoJukebox/Sources/liquides-desktop.mp4′ type=”video/mp4″ />
<source src=’http://addit-media.net/new/uploads/francoroma/VideoJukebox/Sources/liquides-desktop.ogg’ type=”video/ogg” />
</video>
<div id=’subtitles’></div>
</section>

Ebenso, wie die Links, zum Aufruf der Cuepoints, die natürlich irgendwo innerhalb des HTML Codes stattfinden müssen, etwa so:

<ul>
<li><h3><a id=”1″ href=”#”>play Etno</a></h3></li>
<li><h3><a id=”2″ href=”#”>play Kurierstyle</a></h3></li>
<li><h3><a id=”3″ href=”#”>play Madona</a></h3></li>
<li><h3><a id=”4″ href=”#”>play Moskau</a></h3></li>
<li><h3><a id=”5″ href=”#”>play Nostalgie</a></h3></li>
<li><h3><a id=”6″ href=”#”>play Bikerstyle</a></h3></li>
<li><h3><a id=”7″ href=”#”>play Kitzbühl</a></h3></li>
<li><h3><a id=”8″ href=”#”>play Vienna</a></h3></li>
<li><h3><a id=”9″ href=”#”>play Firenze</a></h3></li>
<li><h3><a id=”10″ href=”#”>play Davos</a></h3></li>
<li><h3><a id=”11″ href=”#”>play Firenze</a></h3></li>
<li><h3><a id=”12″ href=”#”>play Sorbet</a></h3></li>
<li><h3><a id=”13″ href=”#”>play Las Vegas</a></h3></li>
<li><h3><a id=”14″ href=”#”>play Schuhe</a></h3></li>
<li><h3><a id=”15″ href=”#”>play Beautycase</a></h3></li>
</ul>

Was gibt’s noch? ach ja, das DIV, mit der Id = ‘subtitles’, wird in unserem Beispiel natürlich mit display=’absolute’ angezeigt, damit es über dem Video liegt.

 

Mrz 262012
 
tt012

Die Jquery Komponente für Steve Rowland ist für Fotos schon sehr gut, aber da ich mehr und mehr Videos zu produzieren habe, mußte das Steve Rowland Photography Frontend noch um die Möglichkeit erweitert werden, Videos abzuspielen. Da ich ein Frontend haben möchte das auf jedem Endgerät läuft, habe ich den

Player als HTML5-Mediaelement Jquery-Erweiterung,

in das bestehende Jquery-Frontend integriert. Wie das geht und wie man das Ganze mit Gallery2, als Assetmanagement adminstriertbar macht, ist Thema dieses Posts. Das Video veranschaulicht, wie das Handling des Frontends arbeiten muß: 1. Video wird ausgewählt. 2. Das <img> wird durch einen <video> Element ersetzt. 3. Das Video wird abgespielt, sobald der Ladezustand soweit fortgeschritten ist, das der Film ohne Pause durchlaufen kann 4. Ein anderes Video wird ausgewählt. 5. Die <source> Elemente des <Video> Elements, werden durch die neuen <source> Elemente ersetzt und neu geladen. 6. wie 3. 7. Wird ein Thumbnail ausgewählt, das ein Foto referenziert, wird das <video> Element wieder durch das <img> Element ersetzt.

Wer das ganze mit seiner eigenen Gallery durchexerzieren möchten, muss natürlich die URL: http://www.steverowland.net/gallery2, durch seine eigene Gallery2 Installations-URL ersetzen. Wer keine Gallery2 als Assetmanagement verwenden möchte, kann das Frontend auch in einer Standalone-Version, ganz am Ende des Posts herunterladen, und ohne Gallery2 verwenden. Der Post beschreibt aber die Variante, wie ich sie auf der Steverowland.net installiert habe, also mit Gallery2 Assetmanagement.

1. Gallery2

Die letzte stabile Version 2.3.1, am Besten gleich die Developer Version(mit Alles), von Gallery2, hier herunterladen. und auf dem Server instalieren. Es gibt auch Gallery3, was aber keine neue Version von Gallery2, sondern eine andere Bildergallerie, die mit einer anderen Programmarchitektur programmiert wurde darstellt, die eher geeignet ist, wenn man schnell eine Bildergallery ins Netz stellen will. Wir benötigen die wesentlich umfangreichere API von Gallery2, um das als Admininterface für das Jquery umstricken zu können. Die installation ist eigentlich selbsterklärend, wer Schwierigkeiten hat, hier gibts die ausgezeichnete Dokumentation für Gallery2. Welches Thema man wählt ist eigentlich egal, denn der User wird die Gallery ohnehin nicht betreten, man sollte also ein Thema wählen, mit dem man selbst eine gute Übersicht behält. Im Gegensatz dazu, werden ALLE verfügbaren Plugins(Module), incl. URL-Rewrite installiert (sind unter der gleichen URL gelistet, wie die Core, aber alle Bestandteil der Developer Version) und richtig konfiguriert.  Um Gallery2 wirklich perfekt zum laufen zu kriegen, wären folgende Server Applications zu empfehlen: GD-Library(stellt Bildbearbeitung funktionen zur Verfügung), ImageMagick(Ist sozusagen die "Platin-Edition" zu GD), Jpegtran (Kann Jpegs verlustfrei umrechnen). Da auch die Adminstration von Filmen vorgesehen ist, wäre auch die ffmpeg-Extension zu empfehlen, dafür sollte zusätzlich 'ffmpeg' auf dem Server installiert sein. Alle Pfade zu den Binaries der gelisteten Server-Apps, müssen als Ressource-Pfade, PHP zur Verfügung stehen.(Wird in der php_ini gesetzt), Wer keine Root Zugang zum Server hat, muss seinen Serveradmin entsprechend instruieren. Gallery2 würde auch ohne das Alles grunsätzlich funktionieren und Standarts bieten, aber mit diesen Tools, ist es ein echtes 'Bildbearbeitungs-Brett', von herrausragender Qualität und Performance, das auch für hochprofessionelles Assetmanagement, keine Wünsche offen lässt.

2. Simpleviewer Source Extension

Es gibt eine Gallery2 Extension, die eigntlich zu einem Flash Imageslider gehört, die SimpleviewerSource. Diese ist nicht Bestandteil der Offiziellen Repository und müsste man sich aus den Community-Extensions besorgen. Allerdings ist eine größeres PHP-Workaround notwendig, wenn man die Original-Erweiterung verwendet, deshalb kann man sich meine, bereits umgenbaute Version herunterladen und diese installieren. Diese kann allerdings nicht im "normalen" Plugin installationsprozess von Gallery2 installiert werden, sondern wird Gallery2, wie folgt zugeführt.

Instalation: 1. zip Datei hier herunterladen 2.zip auspacken und Ordner in das Verzeichnis [Gallery installationspfad]/modules auspacken, oder zip hochladen und im Verzeichnis auspacken. 3. In der Site-administration, Module auswählen. Jetzt ist die Erweiterung SimpleviewerSource unter 'Exportieren', verfügbar und kann aktiviert werden.

VORSICHT!!! Die Nummer funktioniert nur, weil Simpleviewer Source eine "offizielle Extension" ist, der wir ein Kuckuks-Ei unterschieben, in der GalleryFactory wird Simpleviewer Source als ordentlich Extension in Gallery2 registriert, man kann also nicht einfach irgendeinen Ordner anlegen, der dann von Gallery2 als Extension wahrgenommen wird. Wahlweise, kann man natürlich auch die Extension übers Backend installieren und anschliessend die Moduldateien, per ftp-Upload mit den modifizierten überschreiben.

Man kann auch ein eigenes Modul für Gallery2 schreiben, aber SimpleviewerSource, hat bereits fast alles was wir brauchen, Was, Wie, Warum genau diese Extension bietet, würde hier den Rahmen sprengen und eher Thema für einen eigenen Post, aber SimpleviewerSource erstellt eine XML-struckturierte Ausgabe, der kompletten Gallery, die eigentlich als URL für  den HTTP-Request dier Flash Datei gedacht ist und genau DIESE, bietet auch das perfekte Datenmodel für den View, den wir dem Modul hinzufügen. Man muss keinen der SimpleviewerSource Konfigurationsparameter ausfüllen oder setzen, da diese von der überarbeiteten Version schlicht übergangen werden!

3. Die Views

Gallery2 ist in MVC Architektur programmiert. Das Model sowie Controller, sind schon im Modul vorhanden, wir müssen dem Modul nur einen View hinzufügen, analog zum XMLOut View hab ich ihn HTMLOut genannt und er erweitert die GalleryView Class, die Datei die ihn beinhaltet, heisst dann nach Gallery2-API HTMLOut.inc. Der einzige Parameter der an den Controller übergeben wird, ist die Id, des Album Elements für den wir den View haben mölchten. Im Gegensatz zur XMLOut, die ein Album und deren Fotoelemente darstellt, habe ich den HTMLView um eine Hirarchie erweitert, es wird also eine Album mit dessen Unteralben und die Bilder in den Unteralben ausgelesen werden, um das Datenmodel, wie es für die JQuery-Ausgabe benötigt wird, zu erhalten. Eine Möglichkeit das neu Frontend anzuzeigen besteht nun darin, den View direkt mit der ItenId des Portfolios (in diesem Fall ist das die 1051) aufzurufen. Die Gallery2-API setzt noch Prefix davor, also g2_view und g2_itemId, wodurch der komplette Aufruf so aussieht:

http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.HTMLOut&g2_itemId=1051

Ausserdem brauchen wir, für die Thumbnailnavigation einen View, der die Thumbnails der Bilder in den Subalben zeigt, z.B. so:

http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.DownloadThumb&g2_itemId=3561

dieser wird in das jeweilige img.src attribut eingetragen.

Beim Click auf das Thumbnail, soll das Hintergrund Bild geladen werden, das Jquery verwendet dazu den Wert im img.alt Attribut des jeweiligen Thumbnails. Wir brauchen also noch einen weiteren View, nämlich den, der das große Bild zeigt. Bestandteil der SimpleviewerSource, wäre der View, downloadMax View, wobei dieser dem DownloadItem View der Core, um die beiden Parameter g2_maxImageHeight und g2_maxImageWidth erweitert entspricht. Da diesen hier keine Bedeutung zukommt, da die Bildgröße nicht von Gallery2, sondern durch das Jquery an die jeweilige Screengröße angepasst wird, kann man genausogut den View der Core verwenden.

http://www.steverowland.net/gallery2/main.php?g2_view=core.DownloadItem&g2_itemId=3561

Da der Aufruf innerhalb des Gallery Root Pfades erfolgt, würden auch die relative Pfade genügen, hier aus dem Blog müssen wir natürlich absolut verlinken. Auch ganz ohne Views, wäre es theoretisch möglich, auf die Items zuzugreifen, ein paar Beispiele:

Dieser Code etwa: <a href="http://www.steverowland.net/gallery2/v/show/crist/1967_ORDER03.jpg.html" ><img src="http://www.steverowland.net/gallery2/d/4314-2/1967_ORDER03.jpg" alt="1967_ORDER03" /></a>, das kleine v steht für view, show/ ist das oberste Album, crist/ ist das subalbum, 1967_ORDER03.jpg ist der Bildname und .html, zeigt, das nicht das Bild sondern die Fotoseite des Bildes angezeigt wird. Im src attribut des angezeigten Bildes steht das d/ für "download", was immer ein Bild zeigt, wärend v/ den g2_view des Bildes zeigt. In HTML ausgeführt, wird hier ein clickbares Thumbnail gezeigt, das auf die Photoseite des Items verlinkt und sieht so aus:

1967_ORDER03

Oder dieser Code: <a href="http://www.steverowland.net/gallery2/d/4313-1/1967_ORDER03.jpg"><img src="http://www.steverowland.net/gallery2/d/4316-2/1967_ORDER03.jpg" alt="1967_ORDER03" /></a>. Sowohl das href als auch das src zeigen ein Bild(d/). In diesem Fall, die erste Zwischengrösse, clickbar, mit Verweis zur Originaldatei. was in HTML so aussieht:

1967_ORDER03

Dieser Code würde hier in HTML, den Blog sprengen: <img src="http://www.steverowland.net/gallery2/d/4313-1/1967_ORDER03.jpg" alt="1967_ORDER03" /> er würde direkt die Originaldatei hier anzeigen, wie am href Attribut des vorherigen Beispiels deutlich zu sehen ist. Wer's nicht glaubt, kann ja den Wert der src, direkt ins Browser Adressfenster kopieren. Die URL-Rewrite Regeln für Gallery2, lassen sich in der Siteadministration derselben auch umdefinieren.

Damit haben wir die URLs, die wir im HTML Code der jquery extension in das src und das alt atribut des jeweilegen Thumbs eintragen müssen. Ein Listenelement könnte also, in etwa so aussehen, wobei ich aus Übersichtsgründen, die cufon-wraps weggelassen habe und hier der simpleviewerSource View eingetragen ist, was wie gesagt, in diesem Fall das gleiche Resultat liefert:

<li class="album">
<span class="st_link">Cover-shooting, D&W Katalog 2002, Milano <span class="st_arrow_down"></span></span>
<div style="overflow: hidden;" class="st_wrapper st_thumbs_wrapper">
<div style="width: 1098px;" class="st_thumbs">
<img src="http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.DownloadThumb&amp;g2_itemId=4791" alt="main.php?g2_view=simpleviewersource.DownloadMax&amp;g2_maxImageHeight=&amp;g2_maxImageWidth=&amp;g2_itemId=4791" title="http://www.steverowland.net/gallery2/v/show/D_W01_Titel/D+W01_Titel.jpg.html">
<img src="http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.DownloadThumb&amp;g2_itemId=4796" alt="main.php?g2_view=simpleviewersource.DownloadMax&amp;g2_maxImageHeight=&amp;g2_maxImageWidth=&amp;g2_itemId=4796" title="http://www.steverowland.net/gallery2/v/show/D_W01_Titel/D+W01_Titel.jpg.html">
<img src="http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.DownloadThumb&amp;g2_itemId=4800" alt="main.php?g2_view=simpleviewersource.DownloadMax&amp;g2_maxImageHeight=&amp;g2_maxImageWidth=&amp;g2_itemId=4800" title="http://www.steverowland.net/gallery2/v/show/D_W01_Titel/D+W01_Titel.jpg.html">
<img src="http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.DownloadThumb&amp;g2_itemId=4804" alt="main.php?g2_view=simpleviewersource.DownloadMax&amp;g2_maxImageHeight=&amp;g2_maxImageWidth=&amp;g2_itemId=4804" title="http://www.steverowland.net/gallery2/v/show/D_W01_Titel/D+W01_Titel.jpg.html">
<img src="http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.DownloadThumb&amp;g2_itemId=4812" alt="main.php?g2_view=simpleviewersource.DownloadMax&amp;g2_maxImageHeight=&amp;g2_maxImageWidth=&amp;g2_itemId=4812" title="http://www.steverowland.net/gallery2/v/show/D_W01_Titel/D+W01_Titel.jpg.html">
<img src="http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.DownloadThumb&amp;g2_itemId=4816" alt="main.php?g2_view=simpleviewersource.DownloadMax&amp;g2_maxImageHeight=&amp;g2_maxImageWidth=&amp;g2_itemId=4816" title="http://www.steverowland.net/gallery2/v/show/D_W01_Titel/D+W01_Titel.jpg.html">
</div>
</div>
</li>

Jetzt sollte auch deutlich werden, warum diese Gallery äusserst Suchmaschinen optimal ist, den auf diese Weise, sind tatsächlich alle relevanten Bild und Albumparameter, bereits in dieser einen Datei vorhanden und direkt vom Googlebot Indizierbar, ohne weitere Aktion oder einer Substitution der Calls durch Snapshots für den Googlebot, wie das für Flash notwendig wäre.

Damit sieht, der View ja schonmal aus, wie die gewünschte Ausgabe und ist es ja auch, aber…

http://www.steverowland.net/gallery2/main.php?g2_view=simpleviewersource.HTMLOut&g2_itemId=1051

… sie soll ja eigentlich mit der folgenden URL aufgerufen werden:

http://www.steverowland.net/gallery2/portfolio.php

Die URL sieht nicht nur besser aus, sondern hat auch den Vorteil, das es auch ausserhalb des Gallery2-Instalationspfades funktionieren würde, was mit dem View nicht geht. Aber dazu fehlt noch die Datei "portfolio.php", eine sog. Wrapper-Datei.

4. Die Wrapper Datei

Ruft man Gallery2 auf, erfolgt normalerweise ein Aufruf der Datei 'main.php'. View und Item werden als URL Parameter, an diese übergeben. Aber Gallery2 kann auch eingebettet, in einer anderen Anwendung, oder mit einer anderen Anwendung über ein event-based loose coupling verbunden, aufgerufen werden. In diesem Fall, wird Gallery2 nicht über die 'main.php', sondern über die 'embed.php' aufgerufen. Damit wird die 'bootstrap.inc' nicht zuerst eingebunden und die Gallery2 Ausgabe kann in ein andere Datei, oder eine andere Anwendung, umgeleitet werden. Diese kann in einem anderen Verzeichnis, muß aber auf der selben Domain liegen (auch keine Subdomain). Wird Gallery2 in eine andere Anwendung geleitet, läuft Gallery2 'eingebettet". Wird Gallery2 über ein coupling verbunden findet die Ausgabe von Gallery2 und die der verbundenen Anwenndung, in einer weiteren Datei statt. Diese Datei nennt man Wrapper Datei.

Die Datei muss folgendes enthalten:

<?php

// der relative Pfad zum Gallery-Root Verzeichnis (in diesem Fall befinden sich die wrapper-Datei im Gallery-Root Verzeichnis)

$g2_Config['path'] = dirname(__FILE__) . '/';  

// Den Rootpath der Gallery2 installation, allso von der Domain-Root zum Gallery-Root Verzeichnis.

$g2_Config['g2Uri'] = '/gallery2/';

// und den embed Pfad, also von der Domain-root zur wrapper Datei, damit lassen sich alle anderen Relation herstellen.

$g2_Config['embedUri'] = '/gallery2/portfolio.php'; 

// Dann wird die embed.php eingebunden.

require_once( $g2_Config['path'] . 'embed.php');

// Wir schicken einen HTML Header

if (!headers_sent()) {
    header('Content-Type: text/html; charset=UTF-8');
}

// Durch die init, wird ein Status in der Gallery erzeugt, der aufrufe verarbeiten kann und

$ret = GalleryEmbed::init(array('fullInit' => true));
check($ret);
GalleryCapabilities::set('login',true);

// Eine Instanz der Gallerie laden und autifizieren.

/* Grab the authToken */
global $gallery;
$session =& $gallery->getSession();
$authToken = $session->getAuthToken();

// die Request Varialblen direkt an den entsprechenden view übergeben.

GalleryUtilities::putRequestVariable('view', 'simpleviewersource.HTMLOut');
GalleryUtilities::putRequestVariable('itemId', '1051');

// Und die Anfragen von den definierten Controllern bearbeiten lassen

$data = GalleryEmbed::handleRequest();

// Die $data, enthält jetzt die Daten unserer Ausgabegallerie, bis auf das Thema. Da hier MVC, konsequent durchgezogen wurde, besteht eine 100% Trennung, zwischen Form und Inhalt. Wobei $data['headHtml'] die Headerdaten und $data['bodyHtml'] die Bodydaten enthält.

// Da wir wegen einer möglichen Video Ausgabe eine HTML5 Ausgabe möchten, Gallerie aber ein HTML4 Ausgabe schicken würde, haben wir das komplette HTML im View integriert und geben diesen auch wieder komplett als HTML aus.

function check($ret) {
    if ($ret) die($ret->getAsHtml());
}

?>

5. Das Javascript

Auch diese Datei ist Bestandteil, der umgebauten SimpleviewerSource-Erweiterung und zwar hier:  js/HTML5JqueryMediaelement.1.1.js. Die Datei enthält bereits Teile, für die Version 2, die hier noch garnicht zum Einsatz kommen, wie z.B. die Verwendung von Canvas zum zeichnen von Standbildern aus dem Video. Diese hab ich hier weggelassen.

$(function() {

 // einzige konfigurierbare Variable. Wo liegen die Filmdateien?

var $videoPath = 'http://addit-media.net/new/uploads/stevemovies/';

 // Variablen, die sich auf die verwendete Index Datei beziehen
// the loading image

var $loader    = $('#st_loading');

// the ul element

var $list        = $('#st_nav');

// the current image being shown

var $currImage = $('#st_main').children('img:first');
var windowWidth = $(window).width(),
windowHeight = $(window).height();

// Aktuellen Bild….
// und die Navigation mit den Thumbs laden

$('<img>').load(function(){
$loader.hide();
$currImage.fadeIn(3000);

setTimeout(function(){
$list.animate({'left':'0px'},500);
},
1000);
}).attr('src',$currImage.attr('src'));

// Breite des div elements, für die Thumbnailnavi berechnen
// um festzustellen, wo die einzelnen thumbs agezeigt werden müssen

buildThumbs();
function buildThumbs() {
$list.children('li.album').each(function(){
var $elem = $(this);
var $thumbs_wrapper = $elem.find('.st_thumbs_wrapper');
var $thumbs = $thumbs_wrapper.children(':first');

//180px pro thumb + 3 für margin

var finalW = $thumbs.find('img').length * 183;
$thumbs.css('width',finalW + 'px');

//element scrollbar machen, funktion siehe ganz am ende des skripts

makeScrollable($thumbs_wrapper,$thumbs)

;});

}

// ein Video laden

function loadVideo(title, from, to){

// Hier sieht man, wie 'from' und 'to' als "#" Anker übergeben werden!!
// Ich habe die Viedeos in den einzelnen Ordner _1, _2, _3 genannt, theoretisch, kann mann auch alle 3 einfach "video" nennen,
// da sie sich aufgrund der unterschiedlichen Endung ohnehin unterscheiden.

$('#video').append(createSource($videoPath + title + '/_1.mp4#t='+from+','+to, 'video/mp4'));    
$('#video').append(createSource($videoPath + title + '/_2.ogg#t='+from+','+to, 'video/ogg'));
$('#video').append(createSource($videoPath + title + '/_3.webm#t='+from+','+to, 'video/webm'));  
};

// source elemente in das Video laden

function createSource(src, type){
var source = document.createElement('source');
source.src = src;
source.type = type;
return source;
};

// einen Button herstellen

function createButton(parent, value) {
var myButton = document.createElement('input');
myButton.type  = 'button';
myButton.value = value;
parent.prepend(myButton);
return myButton;
};

// eine Debugg funktion mit der man ein Objekt, komplett durchlaufen und auslesen kann

function showObjProps(obj) {
var output = '';
for (property in obj) {
output += property + ': ' + obj[property]+'; ';
 }
alert(output);
};

// die Rollover Eigenschaften der Links definieren

$list.find('.st_link').bind('mouseenter',function(){
 $(this).stop().animate({'opacity':'1'});
 }).bind('mouseleave',function(){
 $(this).stop().animate({'opacity':'0.5'});
});

// ein menüitem anklicken (up and down arrow)
// zeigt die thumbs an ….

$list.find('.st_arrow_down').live('click',function(){
var $this = $(this);
hideThumbs();
$this.addClass('st_arrow_up').removeClass('st_arrow_down');
var $elem = $this.closest('li');
$elem.addClass('current').animate({'height':'200px'},200);
var $thumbs_wrapper = $this.parent().next();
var pos = $this.position();
$thumbs_wrapper.show(200);
if($thumbs_wrapper.is('.desc_wrapper') ) {
$thumbs_wrapper.next().show(200);
$thumbs_wrapper.animate({'left': (pos.left + 120) + 'px'},200);
 }
 });

// …oder versteckt sie wieder

$list.find('.st_arrow_up').live('click',function(){
var $this = $(this);
$this.addClass('st_arrow_down').removeClass('st_arrow_up');
hideThumbs();
 });

// live() oder bind()?
// in diesem Fall wird der click event mit live an die thumbnails gebunden
// beide Funktionen sind ähnlich, aber bind(), bindet den Event, an dieses
// eine Objekt, während live(), den Event an dieses eine und alle noch
// folgenden gleichen Objekte, also auch wenn man ein thumbnail löschen würde
// und dafür eine anderes ersetzt, bleibt die Bindung erhalten, was hier ja auf jedenfall
// gewünscht ist.

$list.find('.st_thumbs img').live('click',function(){
var $this = $(this);

// loading anzeigen….

$loader.show();

// enthält das title attribut, die zeichenfolge irgendwas .jpg, und zwar am ende?

var search = $this.attr('title').search(/.+\.jpg/);

// wird kein treffer gefunden, gibt die funktion search() -1 zurück.

if( search != -1 ) {

// ist search() nicht -1, brauchen wir ein <img>, es könnte aber noch ein video geladen sein.

var $currImage = $('#st_main').children(':first');

//ist firstchild der Player?

if( $currImage.is('#cuePlayer') ) {

// video auswerfen!

$currImage.find('#video').stop();

// durch das img ersetzen!

$currImage.fadeOut(2000,function(){
$(this).replaceWith('<img class="st_preview"/>');
 });
 }

// image in das img laden

$('<img class="st_preview"/>').load(function(){
var $this = $(this);
$currImage = $('#st_main').children('img:first');
$this.insertBefore($currImage);
$loader.hide();
$currImage.fadeOut(2000,function(){
$(this).remove();
});
}).attr('src',$this.attr('alt'));
} else {

// gibt search() -1 zurück, ist kein Bild, demnach ein Video gefragt
// ist firstchild der Player?

if($('#st_main').children(':first').is('#cuePlayer') ) {
$video = $('#video');

// die alten sources rauswerfen….

$video.stop();
$video.empty();

// und die neuen Videos reinladen, im Gegesatz zum Photo, wird für das Video das 'title'-Attribut des Thumbnails zum bilden der Aufrauf-URL verwendet, denn das 'alt'-Attribut, wird ja für die thumbnail.src gebraucht.

loadVideo($this.attr('title'));

// das video laden

$video.load();

// ist firstchild nicht der Player?

} else { $currImage = $('#st_main').children('img:first');

// neues videoelement erstellen

var $video = document.createElement('video');

// img durch html5 video element ersetzen

$currImage.fadeOut(2000,function() {
$(this).replaceWith($video);

// die angefragten sources reinladen

loadVideo($this.attr('title'));

// den loader verstecker

$loader.hide();

//und die cuePlayer section darumwickeln

}).wrap("<section id='cuePlayer'></section>");

// Video Eigenschaften definieren.

var vState = 'Pause'
$video.id = 'video';
$video.controls=true;
$video.autoplay = true;
$video.preload='none';

// Und die Handler zu den Events, die abgehört werden sollen, laden….
//  Ich hab hier nur 3 die wichtigsten, also die minimal-config ausgeführt
//  Alle Events und API der HTML5 Viedeo Componente, sind hier zu finden,
//  http://www.w3.org/2010/05/video/mediaevents.html
//  Anhand des dort gezeigten Beispiels, lässt sich genau nachverfolgen, welcher Event, wann gefeuert wird.
// Eventlistener und Handler 'loadedmetadata'-Event ( für IE6, IE7 und IE8 müsste der Aufruf so aussehen: $video.attachEvent(…..),
// ebenso der nächste, wir haben damit also schonmal 3 Verschiedene Eventhandlings für 5 Browser, ohne Mobilgeräte).
// Erschliesst sich mir nicht so ganz, denn das Video feuert ja den Event selbst, warum muss dann ein Eventlistener,
// den eigenen Event abhören??? funktioniert aber in Chrome & Safari nicht anders. Nicht notwendig in Firefox & Opera,
// da wäre $video.onloadedmetadata direkt als Eigenschaft vorhanden, was mir auch logischer erscheint und da funktioniert auch
// der Listener nur, wenn die Callback Funktion des Handlers, anonym und direkt im Eventlistener gestartet wird, für Chrome & Safari
// könnte man auch eine seperate Funktion mit Namen aufrufen. Dieser Event ist minimales MUST HAVE, denn es ist der Event,
// zu dem die Videodaten, wie Länge, Breite, Duration ect. im Skript bekannt werden und damit, DER PLATZ schlechthin, um CSS u. Parameter
// für Elemente zu setzen, die von der Beschaffenheit des Videos abhängen, wie Fortschritsbalken oder Laufzeitanzeige ect.

$video.addEventListener('loadedmetadata',  
function(e) {
if(!$video.autoplay) vState = 'Play';
var playpause = createButton($('#video').parent(), vState);
playpause.id = 'playpause';
 $('#playpause').bind('click',function(){    
playpause.value = $video.paused ? 'Pause' : 'Play';
if ($video.paused) {
$video.play();
} else {
$video.pause();
}
}).css({'height': '20px',
 'width' : '100px',
 'top'   :  this.offsetTop,
'left'  :  '15px',
 'border-radius':'5px'
 });
$('#cuePlayer').css({
'height': (this.videoHeight + 40)+'px',
'width': this.videoWidth + 'px'});
}, false);

// Eventlistener und Handler   'canplaythrough'-Event
// Nicht ganz so essentiell, wie der Vorher aber auch wichtig. Der Event, wird gefeuert, wenn das Video soweit vorgeladen wurde,
// Das es komplett gespielkt werden kann, ohne unterbrechen zu müssen um nachzuladen, und ist somit eigentlich der richtige Moment,
// um das Video zu starten,
// Oder einen Play-Button für den Benutzer freizugeben.

$video.addEventListener('canplaythrough',  
function(e) {
$video.play();
$loader.hide();
}, false);

// Die Mousehandler an den Player Binden

$('#cuePlayer').bind('mouseenter',
function(){
$('#playpause').show(200);
 }).bind('mouseleave',function(){
$('#playpause').hide(200);
 });

// Und Die Mousehandler für komplette Action

}).bind('mouseenter',function(){
$(this).stop().animate({'opacity':'1'});
}).bind('mouseleave',function(){
$(this).stop().animate({'opacity':'0.5'});
 });

// Funktion um das Momentan geöffnete Menü zu schliessen

function hideThumbs(){
$list.find('li.current')
.animate({'height':'50px'},400,function(){
$(this).removeClass('current');
})
.find('.st_thumbs_wrapper')
 .hide(200)
.andSelf()
.find('.st_link span')
.addClass('st_arrow_down')
.removeClass('st_arrow_up')
.andSelf()
.find('.desc_wrapper')
.hide(200);
 }

// die Thumbnailnavigations divs skrollbar machen
// mit on-mouse-move-Handler, um die Thumbs bei Rollover automatisch zu scrollen.

function makeScrollable($outer, $inner){
var extra             = 800;
var divWidth = $outer.width();
$outer.css({
overflow: 'hidden'
});
var lastElem = $inner.find('img:last');
$outer.scrollLeft(0);
$outer.unbind('mousemove').bind('mousemove',function(e){
extra             = 800;
divWidth = $outer.width();
var containerWidth = lastElem[0].offsetLeft + lastElem.outerWidth() + 2*extra;
var left = (e.pageX – $outer.offset().left) * (containerWidth-divWidth) / divWidth – extra;
$outer.scrollLeft(left);
});
}
});

OK, das war jetzt eine Menge Code, ist aber leider nicht Anders zu machen. Wer kein Assetmanagement verwenden möchte oder wem das zuviel Coding ist, der kann sich auch

eine Standalone Version des Jquery hier herunterladen.

Mrz 192012
 

Die neue Website für Steve Rowland Photography wurde als Javascript, Jquery realisiert. Als Assetmanagement, zur Administration der Website, dient Gallery2. Das Admin Interface ist von der Frontseite aus nicht erreichbar und kann nur durch direkte Eingabe der URL aufgerufen werden.

Suchmaschinen optimierte Ausgabe.

Bei diesem Jquery, sind alle, für Suchmaschinen relevanten Daten der Bilder, bereits Bestandteil des HTML Codes, der aufgerufenen Seite und können von Robots problemlos ausgelesen werden.

Durch Auswahl eines Photos aus der Navigationsleiste, werden die großen Bilder vom Server nachgeladen und direkt in das Seitenlayout eingebaut, ohne daß ein komplettes Update der Seite stattfinden muss. Ein "loading" Button rechts oben zeigt dabei die Ladetätigkeit an.

Die Seite verhält sich "fluid", das heißt, die Größe des Hauptphotos und die der Thumbnailnavigation passen sich der Grösse des öffnenden Fensters an, auch wenn diese erst nach dem Laden verändert wird, wodurch sich die Seite auch zur Darstellung und Navigation auf Tablet PCs gut eignet.