Merge pull request #284 from ArthurHoaro/plugin-playvideos
PLUGIN playvideos
This commit is contained in:
commit
245432e796
7 changed files with 10715 additions and 0 deletions
71
plugins/playvideos/README.md
Normal file
71
plugins/playvideos/README.md
Normal file
|
@ -0,0 +1,71 @@
|
|||
### ► Play Videos plugin for Shaarli
|
||||
This plugin adds a `► Play Videos` button to [Shaarli](https://github.com/shaarli/Shaarli)'s toolbar. Click this button to play all videos on the page in an overlay HTML5 player. Nice for continuous stream of music, documentaries, talks...
|
||||
|
||||
This uses code from https://zaius.github.io/youtube_playlist/ and is currently only compatible with Youtube videos.
|
||||
|
||||
![](https://cdn.mediacru.sh/D_izf0zjAtxy.png)
|
||||
|
||||
#### Installation and setup
|
||||
Place the files in the `tpl/plugins/playvideos/` directory of your Shaarli.
|
||||
This is a default Shaarli plugin, you just have to enable it.
|
||||
|
||||
To enable the plugin, add `playvideos` to the `TOOLBAR_PLUGINS` config option in your `index.php` or `data/options.php`. Example:
|
||||
|
||||
$GLOBALS['config']['TOOLBAR_PLUGINS'] = array('aplugins', 'anotherone', 'playvideos');
|
||||
|
||||
#### Troubleshooting
|
||||
If your server has [Content Security Policy](http://content-security-policy.com/) headers enabled, this may prevent the script from loading fully. You should relax the CSP in your server settings. Example CSP rule for apache2:
|
||||
`Header set Content-Security-Policy "script-src 'self' 'unsafe-inline' https://www.youtube.com https://s.ytimg.com 'unsafe-eval'"`
|
||||
|
||||
### License
|
||||
```
|
||||
File: youtube_playlist.js
|
||||
Copyright: (c) 2010-2014, David Kelso <david@kelso.id.au>
|
||||
License: The ISC License (http://opensource.org/licenses/ISC)
|
||||
|
||||
Files: jquery*.js
|
||||
License: MIT License (http://opensource.org/licenses/MIT)
|
||||
Copyright: (C) jQuery Foundation and other contributors, https://jquery.com/download/
|
||||
|
||||
-----------------------------------------------------
|
||||
|
||||
The ISC License (http://opensource.org/licenses/ISC)
|
||||
|
||||
Copyright (c) 2010-2014, David Kelso (david at kelso dot id dot au)
|
||||
Copyright (c) 2010-2014, nodiscc (nodiscc at gmail dot com)
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE
|
||||
|
||||
----------------------------------------------------
|
||||
MIT LICENSE
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
----------------------------------------------------
|
||||
```
|
10346
plugins/playvideos/jquery-1.11.2.js
vendored
Normal file
10346
plugins/playvideos/jquery-1.11.2.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
BIN
plugins/playvideos/jquery-1.11.2.min.js
vendored
Normal file
BIN
plugins/playvideos/jquery-1.11.2.min.js
vendored
Normal file
Binary file not shown.
1
plugins/playvideos/playvideos.html
Normal file
1
plugins/playvideos/playvideos.html
Normal file
|
@ -0,0 +1 @@
|
|||
<a href="#" id="playvideos">► Play Videos</a>
|
40
plugins/playvideos/playvideos.php
Normal file
40
plugins/playvideos/playvideos.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
/**
|
||||
* Plugin PlayVideos
|
||||
*
|
||||
* Add a button in the toolbar allowing to watch all videos.
|
||||
* Note: this plugin adds jQuery.
|
||||
*/
|
||||
|
||||
/**
|
||||
* When linklist is displayed, add play videos to header's toolbar.
|
||||
*
|
||||
* @param array $data - header data.
|
||||
*
|
||||
* @return mixed - header data with playvideos toolbar item.
|
||||
*/
|
||||
function hook_playvideos_render_header($data)
|
||||
{
|
||||
if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) {
|
||||
$data['buttons_toolbar'][] = file_get_contents(PluginManager::$PLUGINS_PATH . '/playvideos/playvideos.html');
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* When linklist is displayed, include playvideos JS files.
|
||||
*
|
||||
* @param array $data - footer data.
|
||||
*
|
||||
* @return mixed - footer data with playvideos JS files added.
|
||||
*/
|
||||
function hook_playvideos_render_footer($data)
|
||||
{
|
||||
if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) {
|
||||
$data['js_files'][] = PluginManager::$PLUGINS_PATH . '/playvideos/jquery-1.11.2.min.js';
|
||||
$data['js_files'][] = PluginManager::$PLUGINS_PATH . '/playvideos/youtube_playlist.js';
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
196
plugins/playvideos/youtube_playlist.js
Normal file
196
plugins/playvideos/youtube_playlist.js
Normal file
|
@ -0,0 +1,196 @@
|
|||
var run_playideos = (function () {
|
||||
var e, n, t, o, r, i = [].indexOf || function (e) {
|
||||
for (var n = 0, t = this.length; n < t; n++) {
|
||||
if (n in this && this[n] === e) return n
|
||||
}
|
||||
return -1
|
||||
};
|
||||
if (!window.console) {
|
||||
window.console = {
|
||||
log: function () {}
|
||||
}
|
||||
}
|
||||
n = {
|
||||
shadow: {
|
||||
"background-color": "black",
|
||||
position: "fixed",
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
"z-index": 1e3,
|
||||
opacity: .8
|
||||
},
|
||||
player_box: {
|
||||
position: "fixed",
|
||||
left: "50%",
|
||||
top: "50%",
|
||||
width: 640,
|
||||
height: 480,
|
||||
"margin-left": -320,
|
||||
"margin-top": -240,
|
||||
"z-index": 1001
|
||||
},
|
||||
prev_button: {
|
||||
"float": "left"
|
||||
},
|
||||
next_button: {
|
||||
"float": "right"
|
||||
}
|
||||
};
|
||||
t = function (e, n) {
|
||||
var t, o, r;
|
||||
r = document.createElement("script");
|
||||
r.src = e;
|
||||
o = document.getElementsByTagName("head")[0];
|
||||
t = false;
|
||||
r.onload = r.onreadystatechange = function () {
|
||||
var e, i;
|
||||
e = !this.readyState || (i = this.readyState) === "loaded" || i === "complete";
|
||||
if (!t && e) {
|
||||
t = true;
|
||||
n();
|
||||
r.onload = r.onreadystatechange = null;
|
||||
return o.removeChild(r)
|
||||
}
|
||||
};
|
||||
return o.appendChild(r)
|
||||
};
|
||||
e = function (e) {
|
||||
var t, o, r, a, u, l, d, c, f, p, s, y, h, g, v, m, w;
|
||||
e.getScript("//www.youtube.com/iframe_api");
|
||||
d = [];
|
||||
w = new RegExp("https?://(www.)?youtube.com/");
|
||||
e('a[href^="http"]').each(function () {
|
||||
var n;
|
||||
if (!e(this).attr("href").match(w)) {
|
||||
return
|
||||
}
|
||||
n = this.href.replace(/^.*v=/, "").replace(/\&.*$/, "");
|
||||
if (i.call(d, n) < 0) {
|
||||
return d.push(n)
|
||||
}
|
||||
});
|
||||
console.log("video ids", d);
|
||||
c = 0;
|
||||
y = null;
|
||||
g = "playlist_player";
|
||||
f = function () {
|
||||
console.log("Playing", c, d[c]);
|
||||
return y.loadVideoById(d[c])
|
||||
};
|
||||
p = function () {
|
||||
c++;
|
||||
if (c >= d.length) {
|
||||
c -= d.length
|
||||
}
|
||||
return f()
|
||||
};
|
||||
s = function () {
|
||||
c--;
|
||||
if (c < 0) {
|
||||
c += d.length
|
||||
}
|
||||
return f()
|
||||
};
|
||||
l = function () {
|
||||
e("#shadow, #player_box").remove();
|
||||
return e(document).unbind("keyup.player")
|
||||
};
|
||||
e(document).bind("keyup.player", function (e) {
|
||||
if (e.keyCode === 27) {
|
||||
l()
|
||||
}
|
||||
if (e.keyCode === 39) {
|
||||
p()
|
||||
}
|
||||
if (e.keyCode === 37) {
|
||||
return s()
|
||||
}
|
||||
});
|
||||
u = e("<div />", {
|
||||
id: "shadow",
|
||||
css: n.shadow,
|
||||
click: l
|
||||
});
|
||||
r = e("<div />", {
|
||||
id: "player_box",
|
||||
css: n.player_box
|
||||
});
|
||||
o = e("<div />", {
|
||||
id: g
|
||||
});
|
||||
a = e("<a />", {
|
||||
href: "javascript:;",
|
||||
text: "previous",
|
||||
css: n.prev_button,
|
||||
click: s
|
||||
});
|
||||
t = e("<a />", {
|
||||
href: "javascript:;",
|
||||
text: "next",
|
||||
css: n.next_button,
|
||||
click: p
|
||||
});
|
||||
r.append(o).append(a).append(t);
|
||||
e("body").append(u).append(r);
|
||||
v = function (e) {
|
||||
console.log("player ready");
|
||||
return e.target.playVideo()
|
||||
};
|
||||
h = function (e) {
|
||||
var n, t;
|
||||
n = {
|
||||
2: "invalid video id",
|
||||
5: "video not supported in html5",
|
||||
100: "video removed or private",
|
||||
101: "video not embedable",
|
||||
150: "video not embedable"
|
||||
};
|
||||
t = n[e.data] || "unknown error";
|
||||
console.log("Error", t);
|
||||
d.splice(c, 1);
|
||||
if (c >= d.length) {
|
||||
c = 0
|
||||
}
|
||||
return f()
|
||||
};
|
||||
m = function (e) {
|
||||
if (e.data === YT.PlayerState.ENDED) {
|
||||
return p()
|
||||
}
|
||||
};
|
||||
return window.onYouTubeIframeAPIReady = function () {
|
||||
return y = new YT.Player(g, {
|
||||
height: "390",
|
||||
width: "640",
|
||||
videoId: d[0],
|
||||
events: {
|
||||
onReady: v,
|
||||
onError: h,
|
||||
onStateChange: m
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
o = false;
|
||||
if (typeof jQuery !== "undefined" && jQuery !== null && jQuery.fn && jQuery.fn.jquery) {
|
||||
r = jQuery.fn.jquery.split(".");
|
||||
if (r.length === 3 && parseInt(r[1]) > 3) {
|
||||
console.log("using in page jquery version", jQuery.fn.jquery);
|
||||
e(jQuery);
|
||||
o = true
|
||||
}
|
||||
}
|
||||
if (!o) {
|
||||
t("plugins/playvideos/jquery-1.11.2.min.js", function () {
|
||||
return e(jQuery.noConflict(true))
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
var input = document.querySelector('#playvideos');
|
||||
input.addEventListener('click', function()
|
||||
{
|
||||
run_playideos();
|
||||
});
|
61
tests/plugins/PluginPlayvideosTest.php
Normal file
61
tests/plugins/PluginPlayvideosTest.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* PluginPlayvideosTest.php
|
||||
*/
|
||||
|
||||
require_once 'plugins/playvideos/playvideos.php';
|
||||
require_once 'application/Router.php';
|
||||
|
||||
/**
|
||||
* Class PluginPlayvideosTest
|
||||
* Unit test for the PlayVideos plugin
|
||||
*/
|
||||
class PluginPlayvideosTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Reset plugin path
|
||||
*/
|
||||
function setUp()
|
||||
{
|
||||
PluginManager::$PLUGINS_PATH = 'plugins';
|
||||
}
|
||||
|
||||
/**
|
||||
* Test render_linklist hook.
|
||||
*/
|
||||
function testPlayvideosHeader()
|
||||
{
|
||||
$str = 'stuff';
|
||||
$data = array($str => $str);
|
||||
$data['_PAGE_'] = Router::$PAGE_LINKLIST;
|
||||
|
||||
$data = hook_playvideos_render_header($data);
|
||||
$this->assertEquals($str, $data[$str]);
|
||||
$this->assertEquals(1, count($data['buttons_toolbar']));
|
||||
|
||||
$data = array($str => $str);
|
||||
$data['_PAGE_'] = $str;
|
||||
$this->assertEquals($str, $data[$str]);
|
||||
$this->assertArrayNotHasKey('buttons_toolbar', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test render_footer hook.
|
||||
*/
|
||||
function testPlayvideosFooter()
|
||||
{
|
||||
$str = 'stuff';
|
||||
$data = array($str => $str);
|
||||
$data['_PAGE_'] = Router::$PAGE_LINKLIST;
|
||||
|
||||
$data = hook_playvideos_render_footer($data);
|
||||
$this->assertEquals($str, $data[$str]);
|
||||
$this->assertEquals(2, count($data['js_files']));
|
||||
|
||||
$data = array($str => $str);
|
||||
$data['_PAGE_'] = $str;
|
||||
$this->assertEquals($str, $data[$str]);
|
||||
$this->assertArrayNotHasKey('js_files', $data);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue