first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Main class for plugin 'media_html5audio'
*
* @package media_html5audio
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Player that creates HTML5 <audio> tag.
*
* @package media_html5audio
* @copyright 2016 Marina Glancy
* @author 2011 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class media_html5audio_plugin extends core_media_player_native {
public function embed($urls, $name, $width, $height, $options) {
if (array_key_exists(core_media_manager::OPTION_ORIGINAL_TEXT, $options) &&
preg_match('/^<(video|audio)\b/i', $options[core_media_manager::OPTION_ORIGINAL_TEXT], $matches)) {
// We already had media tag, do nothing here.
return $options[core_media_manager::OPTION_ORIGINAL_TEXT];
}
// Build array of source tags.
$sources = array();
foreach ($urls as $url) {
$params = ['src' => $url];
$ext = core_media_manager::instance()->get_extension($url);
if ($ext !== 'aac') {
// Some browsers get confused by mimetype on source for AAC files.
$mimetype = core_media_manager::instance()->get_mimetype($url);
$params['type'] = $mimetype;
}
$sources[] = html_writer::empty_tag('source', $params);
}
$sources = implode("\n", $sources);
$title = $this->get_name($name, $urls);
// Escape title but prevent double escaping.
$title = s(preg_replace(['/&amp;/', '/&gt;/', '/&lt;/'], ['&', '>', '<'], $title));
// Default to not specify size (so it can be changed in css).
$size = '';
if ($width) {
$size = 'width="' . $width . '"';
}
// We don't want fallback to another player because list_supported_urls() is already smart.
// Otherwise we could end up with nested <audio> tags. Fallback to link only.
$fallback = self::LINKPLACEHOLDER;
return <<<OET
<audio controls="true" $size class="mediaplugin mediaplugin_html5audio" preload="none" title="$title">
$sources
$fallback
</audio>
OET;
}
public function get_supported_extensions() {
global $CFG;
require_once($CFG->libdir . '/filelib.php');
return file_get_typegroup('extension', 'html_audio');
}
public function list_supported_urls(array $urls, array $options = array()) {
$extensions = $this->get_supported_extensions();
$result = array();
foreach ($urls as $url) {
$ext = core_media_manager::instance()->get_extension($url);
if (in_array('.' . $ext, $extensions) && core_useragent::supports_html5($ext)) {
// Unfortunately html5 video does not handle fallback properly.
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=10975
// That means we need to do browser detect and not use html5 on
// browsers which do not support the given type, otherwise users
// will not even see the fallback link.
$result[] = $url;
}
}
return $result;
}
/**
* Default rank
* @return int
*/
public function get_rank() {
return 20;
}
}
@@ -0,0 +1,46 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy provider implementation for media_html5audio.
*
* @package media_html5audio
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace media_html5audio\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy provider implementation for media_html5audio.
*
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason(): string {
return 'privacy:metadata';
}
}
@@ -0,0 +1,27 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Strings for plugin 'media_html5audio'
*
* @package media_html5audio
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['pluginname'] = 'HTML5 audio';
$string['pluginname_help'] = 'Audio files played by the browser\'s native audio player. (Format support depends on the browser.)';
$string['privacy:metadata'] = 'The HTML5 audio media plugin does not store any personal data.';
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

@@ -0,0 +1,147 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace media_html5audio;
use core_media_manager;
use media_html5audio_plugin;
/**
* Test script for media embedding.
*
* @package media_html5audio
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class player_test extends \advanced_testcase {
/**
* Pre-test setup. Preserves $CFG.
*/
public function setUp(): void {
parent::setUp();
// Reset $CFG and $SERVER.
$this->resetAfterTest();
// Consistent initial setup: all players disabled.
\core\plugininfo\media::set_enabled_plugins('html5audio');
// Pretend to be using Firefox browser (must support ogg for tests to work).
\core_useragent::instance(true, 'Mozilla/5.0 (X11; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0 ');
}
/**
* Test that plugin is returned as enabled media plugin.
*/
public function test_is_installed(): void {
$sortorder = \core\plugininfo\media::get_enabled_plugins();
$this->assertEquals(['html5audio' => 'html5audio'], $sortorder);
}
/**
* Test method get_supported_extensions()
*/
public function test_get_supported_extensions(): void {
global $CFG;
require_once($CFG->libdir . '/filelib.php');
$nativeextensions = file_get_typegroup('extension', 'html_audio');
// Make sure that the list of extensions from the setting is exactly the same as html_audio group.
$player = new media_html5audio_plugin();
$this->assertEmpty(array_diff($player->get_supported_extensions(), $nativeextensions));
$this->assertEmpty(array_diff($nativeextensions, $player->get_supported_extensions()));
}
/**
* Test method list_supported_urls()
*/
public function test_list_supported_urls(): void {
global $CFG;
require_once($CFG->libdir . '/filelib.php');
$nativeextensions = file_get_typegroup('extension', 'html_audio');
// Create list of URLs for each extension.
$urls = array_map(function($ext){
return new \moodle_url('http://example.org/audio.' . $ext);
}, $nativeextensions);
// Make sure that the list of supported URLs is not filtering permitted extensions.
$player = new media_html5audio_plugin();
$this->assertCount(count($urls), $player->list_supported_urls($urls));
}
/**
* Test embedding without media filter (for example for displaying file resorce).
*/
public function test_embed_url(): void {
global $CFG;
$url = new \moodle_url('http://example.org/1.wav');
$manager = core_media_manager::instance();
$embedoptions = array(
core_media_manager::OPTION_TRUSTED => true,
core_media_manager::OPTION_BLOCK => true,
);
$this->assertTrue($manager->can_embed_url($url, $embedoptions));
$content = $manager->embed_url($url, 'Test & file', 0, 0, $embedoptions);
$this->assertMatchesRegularExpression('~mediaplugin_html5audio~', $content);
$this->assertMatchesRegularExpression('~</audio>~', $content);
$this->assertMatchesRegularExpression('~title="Test &amp; file"~', $content);
// Do not set default width/height (it's an audio after all).
$this->assertDoesNotMatchRegularExpression('~width=~', $content);
$this->assertDoesNotMatchRegularExpression('~height=~', $content);
// This plugin ignores size settings.
$this->assertDoesNotMatchRegularExpression('~width=~', $content);
$this->assertDoesNotMatchRegularExpression('~height=~', $content);
}
/**
* Test that mediaplugin filter replaces a link to the supported file with media tag.
*
* filter_mediaplugin is enabled by default.
*/
public function test_embed_link(): void {
$url = new \moodle_url('http://example.org/some_filename.wav');
$text = \html_writer::link($url, 'Watch this one');
$content = format_text($text, FORMAT_HTML);
$this->assertMatchesRegularExpression('~mediaplugin_html5audio~', $content);
$this->assertMatchesRegularExpression('~</audio>~', $content);
$this->assertMatchesRegularExpression('~title="Watch this one"~', $content);
$this->assertDoesNotMatchRegularExpression('~<track\b~i', $content);
}
/**
* Test that mediaplugin filter does not work on <audio> tags.
*/
public function test_embed_media(): void {
$url = new \moodle_url('http://example.org/some_filename.wav');
$trackurl = new \moodle_url('http://example.org/some_filename.vtt');
$text = '<audio controls="true"><source src="'.$url.'"/><source src="somethinginvalid"/>' .
'<track src="'.$trackurl.'">Unsupported text</audio>';
$content = format_text($text, FORMAT_HTML);
$this->assertDoesNotMatchRegularExpression('~mediaplugin_html5audio~', $content);
$this->assertEquals(clean_text($text, FORMAT_HTML), $content);
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Version details
*
* @package media_html5audio
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2024042200; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2024041600; // Requires this Moodle version.
$plugin->component = 'media_html5audio'; // Full name of the plugin (used for diagnostics).
+158
View File
@@ -0,0 +1,158 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Main class for plugin 'media_html5video'
*
* @package media_html5video
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Player that creates HTML5 <video> tag.
*
* @package media_html5video
* @copyright 2016 Marina Glancy
* @author 2011 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class media_html5video_plugin extends core_media_player_native {
public function embed($urls, $name, $width, $height, $options) {
if (array_key_exists(core_media_manager::OPTION_ORIGINAL_TEXT, $options) &&
preg_match('/^<(video|audio)\b/i', $options[core_media_manager::OPTION_ORIGINAL_TEXT], $matches)) {
// We already had media tag, do nothing here.
return $options[core_media_manager::OPTION_ORIGINAL_TEXT];
}
// Special handling to make videos play on Android devices pre 2.3.
// Note: I tested and 2.3.3 (in emulator) works without, is 533.1 webkit.
$oldandroid = core_useragent::is_webkit_android() &&
!core_useragent::check_webkit_android_version('533.1');
// Build array of source tags.
$sources = array();
foreach ($urls as $url) {
$mimetype = core_media_manager::instance()->get_mimetype($url);
if ($mimetype === 'video/quicktime' && (core_useragent::is_chrome() || core_useragent::is_edge())) {
// Set mimetype of quicktime videos to mp4 for Chrome/Edge browsers.
$mimetype = 'video/mp4';
}
$source = html_writer::empty_tag('source', array('src' => $url, 'type' => $mimetype));
if ($mimetype === 'video/mp4') {
if ($oldandroid) {
// Old Android fails if you specify the type param.
$source = html_writer::empty_tag('source', array('src' => $url));
}
// Better add m4v as first source, it might be a bit more
// compatible with problematic browsers.
array_unshift($sources, $source);
} else {
$sources[] = $source;
}
}
$sources = implode("\n", $sources);
$title = $this->get_name($name, $urls);
// Escape title but prevent double escaping.
$title = s(preg_replace(['/&amp;/', '/&gt;/', '/&lt;/'], ['&', '>', '<'], $title));
self::pick_video_size($width, $height);
if (!$height) {
// Let browser choose height automatically.
$size = "width=\"$width\"";
} else {
$size = "width=\"$width\" height=\"$height\"";
}
$sillyscript = '';
$idtag = '';
if ($oldandroid) {
// Old Android does not support 'controls' option.
$id = 'core_media_html5v_' . md5(time() . '_' . rand());
$idtag = 'id="' . $id . '"';
$sillyscript = <<<OET
<script type="text/javascript">
document.getElementById('$id').addEventListener('click', function() {
this.play();
}, false);
</script>
OET;
}
// We don't want fallback to another player because list_supported_urls() is already smart.
// Otherwise we could end up with nested <video> tags. Fallback to link only.
$fallback = self::LINKPLACEHOLDER;
return <<<OET
<span class="mediaplugin mediaplugin_html5video">
<video $idtag controls="true" $size preload="metadata" title="$title">
$sources
$fallback
</video>
$sillyscript
</span>
OET;
}
public function get_supported_extensions() {
global $CFG;
require_once($CFG->libdir . '/filelib.php');
return file_get_typegroup('extension', 'html_video');
}
public function list_supported_urls(array $urls, array $options = array()) {
$extensions = $this->get_supported_extensions();
$result = array();
foreach ($urls as $url) {
$ext = core_media_manager::instance()->get_extension($url);
if (in_array('.' . $ext, $extensions) && core_useragent::supports_html5($ext)) {
// Unfortunately html5 video does not handle fallback properly.
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=10975
// That means we need to do browser detect and not use html5 on
// browsers which do not support the given type, otherwise users
// will not even see the fallback link.
$result[] = $url;
}
}
return $result;
}
/**
* Utility function that sets width and height to defaults if not specified
* as a parameter to the function (will be specified either if, (a) the calling
* code passed it, or (b) the URL included it).
* @param int $width Width passed to function (updated with final value)
* @param int $height Height passed to function (updated with final value)
*/
protected static function pick_video_size(&$width, &$height) {
global $CFG;
if (!$width) {
$width = $CFG->media_default_width;
}
}
/**
* Default rank
* @return int
*/
public function get_rank() {
return 50;
}
}
@@ -0,0 +1,46 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy provider implementation for media_html5video.
*
* @package media_html5video
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace media_html5video\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy provider implementation for media_html5video.
*
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason(): string {
return 'privacy:metadata';
}
}
@@ -0,0 +1,27 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Strings for plugin 'media_html5video'
*
* @package media_html5video
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['pluginname'] = 'HTML5 video';
$string['pluginname_help'] = 'Video files played by the browser\'s native audio player. (Format support depends on the browser.)';
$string['privacy:metadata'] = 'The HTML5 video media plugin does not store any personal data.';
Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

@@ -0,0 +1,145 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace media_html5video;
use core_media_manager;
use media_html5video_plugin;
/**
* Test script for media embedding.
*
* @package media_html5video
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class player_test extends \advanced_testcase {
/**
* Pre-test setup. Preserves $CFG.
*/
public function setUp(): void {
parent::setUp();
// Reset $CFG and $SERVER.
$this->resetAfterTest();
// Consistent initial setup: all players disabled.
\core\plugininfo\media::set_enabled_plugins('html5video');
// Pretend to be using Firefox browser (must support ogg for tests to work).
\core_useragent::instance(true, 'Mozilla/5.0 (X11; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0 ');
}
/**
* Test that plugin is returned as enabled media plugin.
*/
public function test_is_installed(): void {
$sortorder = \core\plugininfo\media::get_enabled_plugins();
$this->assertEquals(['html5video' => 'html5video'], $sortorder);
}
/**
* Test method get_supported_extensions()
*/
public function test_get_supported_extensions(): void {
$nativeextensions = file_get_typegroup('extension', 'html_video');
// Make sure that the list of extensions from the setting is exactly the same as html_video group.
$player = new media_html5video_plugin();
$this->assertEmpty(array_diff($player->get_supported_extensions(), $nativeextensions));
$this->assertEmpty(array_diff($nativeextensions, $player->get_supported_extensions()));
}
/**
* Test method list_supported_urls()
*/
public function test_list_supported_urls(): void {
global $CFG;
require_once($CFG->libdir . '/filelib.php');
$nativeextensions = file_get_typegroup('extension', 'html_video');
// Create list of URLs for each extension.
$urls = array_map(function($ext){
return new \moodle_url('http://example.org/video.' . $ext);
}, $nativeextensions);
// Make sure that the list of supported URLs is not filtering permitted extensions.
$player = new media_html5video_plugin();
$this->assertCount(count($urls), $player->list_supported_urls($urls));
}
/**
* Test embedding without media filter (for example for displaying file resorce).
*/
public function test_embed_url(): void {
global $CFG;
$url = new \moodle_url('http://example.org/1.webm');
$manager = core_media_manager::instance();
$embedoptions = array(
core_media_manager::OPTION_TRUSTED => true,
core_media_manager::OPTION_BLOCK => true,
);
$this->assertTrue($manager->can_embed_url($url, $embedoptions));
$content = $manager->embed_url($url, 'Test & file', 0, 0, $embedoptions);
$this->assertMatchesRegularExpression('~mediaplugin_html5video~', $content);
$this->assertMatchesRegularExpression('~</video>~', $content);
$this->assertMatchesRegularExpression('~title="Test &amp; file"~', $content);
$this->assertMatchesRegularExpression('~width="' . $CFG->media_default_width . '"~', $content);
$this->assertDoesNotMatchRegularExpression('~height=~', $content); // Allow to set automatic height.
// Repeat sending the specific size to the manager.
$content = $manager->embed_url($url, 'New file', 123, 50, $embedoptions);
$this->assertMatchesRegularExpression('~width="123" height="50"~', $content);
}
/**
* Test that mediaplugin filter replaces a link to the supported file with media tag.
*
* filter_mediaplugin is enabled by default.
*/
public function test_embed_link(): void {
global $CFG;
$url = new \moodle_url('http://example.org/some_filename.mp4');
$text = \html_writer::link($url, 'Watch this one');
$content = format_text($text, FORMAT_HTML);
$this->assertMatchesRegularExpression('~mediaplugin_html5video~', $content);
$this->assertMatchesRegularExpression('~</video>~', $content);
$this->assertMatchesRegularExpression('~title="Watch this one"~', $content);
$this->assertDoesNotMatchRegularExpression('~<track\b~i', $content);
$this->assertMatchesRegularExpression('~width="' . $CFG->media_default_width . '"~', $content);
}
/**
* Test that mediaplugin filter does not work on <video> tags.
*/
public function test_embed_media(): void {
$url = new \moodle_url('http://example.org/some_filename.mp4');
$trackurl = new \moodle_url('http://example.org/some_filename.vtt');
$text = '<video controls="true"><source src="'.$url.'"/><source src="somethinginvalid"/>' .
'<track src="'.$trackurl.'">Unsupported text</video>';
$content = format_text($text, FORMAT_HTML);
$this->assertDoesNotMatchRegularExpression('~mediaplugin_html5video~', $content);
$this->assertEquals(clean_text($text, FORMAT_HTML), $content);
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Version details
*
* @package media_html5video
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2024042200; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2024041600; // Requires this Moodle version.
$plugin->component = 'media_html5video'; // Full name of the plugin (used for diagnostics).
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
define("media_videojs/loader",["exports","core/ajax","core/config","core_filters/events","core/localstorage","core/notification","jquery"],(function(_exports,_ajax,_config,_events,_localstorage,_notification,_jquery){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.setUp=void 0,_ajax=_interopRequireDefault(_ajax),_config=_interopRequireDefault(_config),_localstorage=_interopRequireDefault(_localstorage),_notification=_interopRequireDefault(_notification),_jquery=_interopRequireDefault(_jquery);var _systemImportTransformerGlobalIdentifier="undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{};function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}let firstLoad,language,langStringCache;_exports.setUp=lang=>{language=lang,firstLoad=!0,notifyVideoJS({detail:{nodes:document.body}}),document.addEventListener(_events.eventTypes.filterContentUpdated,notifyVideoJS)};const notifyVideoJS=e=>{const nodes=(0,_jquery.default)(e.detail.nodes),langStrings=getLanguageJson();nodes.find(".mediaplugin_videojs").addBack(".mediaplugin_videojs").find("audio, video").each(((index,element)=>{const id=(0,_jquery.default)(element).attr("id"),config=(0,_jquery.default)(element).data("setup-lazy"),modulePromises=["function"==typeof _systemImportTransformerGlobalIdentifier.define&&_systemImportTransformerGlobalIdentifier.define.amd?new Promise((function(resolve,reject){_systemImportTransformerGlobalIdentifier.require(["media_videojs/video-lazy"],resolve,reject)})):"undefined"!=typeof module&&module.exports&&"undefined"!=typeof require||"undefined"!=typeof module&&module.component&&_systemImportTransformerGlobalIdentifier.require&&"component"===_systemImportTransformerGlobalIdentifier.require.loader?Promise.resolve(require("media_videojs/video-lazy")):Promise.resolve(_systemImportTransformerGlobalIdentifier["media_videojs/video-lazy"])];config.techOrder&&-1!==config.techOrder.indexOf("youtube")&&modulePromises.push("function"==typeof _systemImportTransformerGlobalIdentifier.define&&_systemImportTransformerGlobalIdentifier.define.amd?new Promise((function(resolve,reject){_systemImportTransformerGlobalIdentifier.require(["media_videojs/Youtube-lazy"],resolve,reject)})):"undefined"!=typeof module&&module.exports&&"undefined"!=typeof require||"undefined"!=typeof module&&module.component&&_systemImportTransformerGlobalIdentifier.require&&"component"===_systemImportTransformerGlobalIdentifier.require.loader?Promise.resolve(require("media_videojs/Youtube-lazy")):Promise.resolve(_systemImportTransformerGlobalIdentifier["media_videojs/Youtube-lazy"])),config.techOrder&&-1!==config.techOrder.indexOf("OgvJS")&&(config.ogvjs={worker:!0,wasm:!0,base:_config.default.wwwroot+"/media/player/videojs/ogvloader.php/"+_config.default.jsrev+"/"},modulePromises.push("function"==typeof _systemImportTransformerGlobalIdentifier.define&&_systemImportTransformerGlobalIdentifier.define.amd?new Promise((function(resolve,reject){_systemImportTransformerGlobalIdentifier.require(["media_videojs/videojs-ogvjs-lazy"],resolve,reject)})):"undefined"!=typeof module&&module.exports&&"undefined"!=typeof require||"undefined"!=typeof module&&module.component&&_systemImportTransformerGlobalIdentifier.require&&"component"===_systemImportTransformerGlobalIdentifier.require.loader?Promise.resolve(require("media_videojs/videojs-ogvjs-lazy")):Promise.resolve(_systemImportTransformerGlobalIdentifier["media_videojs/videojs-ogvjs-lazy"]))),Promise.all([langStrings,...modulePromises]).then((_ref=>{let[langJson,videojs]=_ref;firstLoad&&(videojs.addLanguage(language,langJson),firstLoad=!1),videojs(id,config)})).catch(_notification.default.exception)}))},getLanguageJson=()=>{if(langStringCache)return Promise.resolve(langStringCache);const cacheKey="media_videojs/".concat(language),rawCacheContent=_localstorage.default.get(cacheKey);if(rawCacheContent){const cacheContent=JSON.parse(rawCacheContent);return langStringCache=cacheContent,Promise.resolve(langStringCache)}const request={methodname:"media_videojs_get_language",args:{lang:language}};return _ajax.default.call([request])[0].then((langStringData=>(_localstorage.default.set(cacheKey,langStringData),langStringData))).then((result=>JSON.parse(result))).then((langStrings=>(langStringCache=langStrings,langStrings)))}}));
//# sourceMappingURL=loader.min.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,9 @@
/**
* videojs-ogvjs
* @version 1.0.0
* @copyright 2023 Huong Nguyen <huongnv13@gmail.com>
* @license MIT
*/
define("media_videojs/videojs-ogvjs-lazy",["media_videojs/video-lazy","./local/ogv/ogv"],(function(videojs,ogv){const OGVCompat=ogv.OGVCompat,OGVLoader=ogv.OGVLoader,OGVPlayer=ogv.OGVPlayer,Tech=videojs.getComponent("Tech"),getDeviceOS=()=>{const ua=navigator.userAgent;return/android/i.test(ua)?"Android":/iPad|iPhone|iPod/.test(ua)?"iPhoneOS":"MacIntel"===navigator.platform&&navigator.maxTouchPoints>1?"iPadOS":"Other"};class OgvJS extends Tech{constructor(options,ready){super(options,ready),this.el_.src=options.source.src,OgvJS.setIfAvailable(this.el_,"autoplay",options.autoplay),OgvJS.setIfAvailable(this.el_,"loop",options.loop),OgvJS.setIfAvailable(this.el_,"poster",options.poster),OgvJS.setIfAvailable(this.el_,"preload",options.preload),this.on("loadedmetadata",(()=>{if("iPhoneOS"===getDeviceOS()){const canvas=this.el_.getElementsByTagName("canvas")[0];canvas.style.removeProperty("width"),canvas.style.removeProperty("margin")}})),this.triggerReady()}createEl(){const options=this.options_;if(!options.base)throw new Error("Please specify the base for the ogv.js library");OGVLoader.base=options.base;const el=new OGVPlayer(options);return el.className+=" vjs-tech",options.tag=el,el}play(){this.el_.play()}playbackRate(){return this.el_.playbackRate||1}setPlaybackRate(val){this.el_.hasOwnProperty("playbackRate")&&(this.el_.playbackRate=val)}played(){return this.el_.played}pause(){this.el_.pause()}paused(){return this.el_.paused}currentTime(){return this.el_.currentTime}setCurrentTime(seconds){try{this.el_.currentTime=seconds}catch(e){videojs.log(e,"Media is not ready. (Video.JS)")}}duration(){return this.el_.duration&&this.el_.duration!==1/0?this.el_.duration:0}buffered(){return this.el_.buffered}volume(){return this.el_.hasOwnProperty("volume")?this.el_.volume:1}setVolume(percentAsDecimal){"iPhoneOS"!==getDeviceOS()&&"iPadOS"!==getDeviceOS()&&this.el_.hasOwnProperty("volume")&&(this.el_.volume=percentAsDecimal)}muted(){return this.el_.muted}setMuted(muted){this.el_.muted=!!muted}defaultMuted(){return this.el_.defaultMuted||!1}width(){return this.el_.offsetWidth}height(){return this.el_.offsetHeight}videoWidth(){return this.el_.videoWidth}videoHeight(){return this.el_.videoHeight}src(src){if(void 0===src)return this.el_.src;this.el_.src=src}load(){this.el_.load()}currentSrc(){return this.currentSource_?this.currentSource_.src:this.el_.currentSrc}poster(){return this.el_.poster}setPoster(url){this.el_.poster=url}preload(){return this.el_.preload||"none"}setPreload(val){this.el_.hasOwnProperty("preload")&&(this.el_.preload=val)}autoplay(){return this.el_.autoplay||!1}setAutoplay(val){this.el_.hasOwnProperty("autoplay")&&(this.el_.autoplay=!!val)}controls(){return this.el_.controls||!1}setControls(val){this.el_.hasOwnProperty("controls")&&(this.el_.controls=!!val)}loop(){return this.el_.loop||!1}setLoop(val){this.el_.hasOwnProperty("loop")&&(this.el_.loop=!!val)}seekable(){return this.el_.seekable}seeking(){return this.el_.seeking}ended(){return this.el_.ended}networkState(){return this.el_.networkState}readyState(){return this.el_.readyState}supportsFullScreen(){return!1}error(){return this.el_.error}}return OgvJS.Events=["loadstart","suspend","abort","error","emptied","stalled","loadedmetadata","loadeddata","canplay","canplaythrough","playing","waiting","seeking","seeked","ended","durationchange","timeupdate","progress","play","pause","ratechange","resize","volumechange"],OgvJS.setIfAvailable=(el,name,value)=>{el.hasOwnProperty(name)&&(el[name]=value)},OgvJS.isSupported=()=>OGVCompat.supported("OGVPlayer"),OgvJS.canPlayType=type=>-1!==type.indexOf("/ogg")||type.indexOf("/webm")?"maybe":"",OgvJS.canPlaySource=srcObj=>OgvJS.canPlayType(srcObj.type),OgvJS.canControlVolume=()=>{if("iPhoneOS"===getDeviceOS()||"iPadOS"===getDeviceOS())return!1;return(new OGVPlayer).hasOwnProperty("volume")},OgvJS.canMuteVolume=()=>!0,OgvJS.canControlPlaybackRate=()=>!0,OgvJS.supportsNativeTextTracks=()=>!1,OgvJS.supportsFullscreenResize=()=>!0,OgvJS.supportsProgressEvents=()=>!0,OgvJS.supportsTimeupdateEvents=()=>!0,[["featuresVolumeControl","canControlVolume"],["featuresMuteControl","canMuteVolume"],["featuresPlaybackRate","canControlPlaybackRate"],["featuresNativeTextTracks","supportsNativeTextTracks"],["featuresFullscreenResize","supportsFullscreenResize"],["featuresProgressEvents","supportsProgressEvents"],["featuresTimeupdateEvents","supportsTimeupdateEvents"]].forEach((_ref=>{let[key,fn]=_ref;!function(obj,key,getValue){const set=value=>{Object.defineProperty(obj,key,{value:value,enumerable:!0,writable:!0})},options={configurable:!0,enumerable:!0,get(){const value=getValue();return set(value),value}};(!(arguments.length>3&&void 0!==arguments[3])||arguments[3])&&(options.set=set),Object.defineProperty(obj,key,options)}(OgvJS.prototype,key,(()=>OgvJS[fn]()),!0)})),Tech.registerTech("OgvJS",OgvJS),OgvJS}));
//# sourceMappingURL=videojs-ogvjs-lazy.min.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,798 @@
/* The MIT License (MIT)
Copyright (c) 2014-2015 Benoit Tremblay <trembl.ben@gmail.com>
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. */
/*global define, YT*/
(function (root, factory) {
if(typeof exports==='object' && typeof module!=='undefined') {
var videojs = require('video.js');
module.exports = factory(videojs.default || videojs);
} else if(typeof define === 'function' && define.amd) {
define(['media_videojs/video-lazy'], function(videojs){
return (root.Youtube = factory(videojs));
});
} else {
root.Youtube = factory(root.videojs);
}
}(this, function(videojs) {
'use strict';
var _isOnMobile = videojs.browser.IS_IOS || videojs.browser.IS_NATIVE_ANDROID;
var Tech = videojs.getTech('Tech');
class Youtube extends Tech {
constructor(options, ready) {
super(options, ready);
this.setPoster(options.poster);
this.setSrc(this.options_.source, true);
// Set the vjs-youtube class to the player
// Parent is not set yet so we have to wait a tick
this.setTimeout(function() {
if (this.el_) {
this.el_.parentNode.className += ' vjs-youtube';
if (_isOnMobile) {
this.el_.parentNode.className += ' vjs-youtube-mobile';
}
if (Youtube.isApiReady) {
this.initYTPlayer();
} else {
Youtube.apiReadyQueue.push(this);
}
}
}.bind(this));
}
dispose() {
if (this.ytPlayer) {
//Dispose of the YouTube Player
if (this.ytPlayer.stopVideo) {
this.ytPlayer.stopVideo();
}
if (this.ytPlayer.destroy) {
this.ytPlayer.destroy();
}
} else {
//YouTube API hasn't finished loading or the player is already disposed
var index = Youtube.apiReadyQueue.indexOf(this);
if (index !== -1) {
Youtube.apiReadyQueue.splice(index, 1);
}
}
this.ytPlayer = null;
this.el_.parentNode.className = this.el_.parentNode.className
.replace(' vjs-youtube', '')
.replace(' vjs-youtube-mobile', '');
this.el_.parentNode.removeChild(this.el_);
//Needs to be called after the YouTube player is destroyed, otherwise there will be a null reference exception
Tech.prototype.dispose.call(this);
}
createEl() {
var div = document.createElement('div');
div.setAttribute('id', this.options_.techId);
div.setAttribute('style', 'width:100%;height:100%;top:0;left:0;position:absolute');
div.setAttribute('class', 'vjs-tech');
var divWrapper = document.createElement('div');
divWrapper.appendChild(div);
if (!_isOnMobile && !this.options_.ytControls) {
var divBlocker = document.createElement('div');
divBlocker.setAttribute('class', 'vjs-iframe-blocker');
divBlocker.setAttribute('style', 'position:absolute;top:0;left:0;width:100%;height:100%');
// In case the blocker is still there and we want to pause
divBlocker.onclick = function() {
this.pause();
}.bind(this);
divWrapper.appendChild(divBlocker);
}
return divWrapper;
}
initYTPlayer() {
var playerVars = {
controls: 0,
modestbranding: 1,
rel: 0,
showinfo: 0,
loop: this.options_.loop ? 1 : 0
};
// Let the user set any YouTube parameter
// https://developers.google.com/youtube/player_parameters?playerVersion=HTML5#Parameters
// To use YouTube controls, you must use ytControls instead
// To use the loop or autoplay, use the video.js settings
if (typeof this.options_.autohide !== 'undefined') {
playerVars.autohide = this.options_.autohide;
}
if (typeof this.options_['cc_load_policy'] !== 'undefined') {
playerVars['cc_load_policy'] = this.options_['cc_load_policy'];
}
if (typeof this.options_.ytControls !== 'undefined') {
playerVars.controls = this.options_.ytControls;
}
if (typeof this.options_.disablekb !== 'undefined') {
playerVars.disablekb = this.options_.disablekb;
}
if (typeof this.options_.color !== 'undefined') {
playerVars.color = this.options_.color;
}
if (!playerVars.controls) {
// Let video.js handle the fullscreen unless it is the YouTube native controls
playerVars.fs = 0;
} else if (typeof this.options_.fs !== 'undefined') {
playerVars.fs = this.options_.fs;
}
if (this.options_.source.src.indexOf('end=') !== -1) {
var srcEndTime = this.options_.source.src.match(/end=([0-9]*)/);
this.options_.end = parseInt(srcEndTime[1]);
}
if (typeof this.options_.end !== 'undefined') {
playerVars.end = this.options_.end;
}
if (typeof this.options_.hl !== 'undefined') {
playerVars.hl = this.options_.hl;
} else if (typeof this.options_.language !== 'undefined') {
// Set the YouTube player on the same language than video.js
playerVars.hl = this.options_.language.substr(0, 2);
}
if (typeof this.options_['iv_load_policy'] !== 'undefined') {
playerVars['iv_load_policy'] = this.options_['iv_load_policy'];
}
if (typeof this.options_.list !== 'undefined') {
playerVars.list = this.options_.list;
} else if (this.url && typeof this.url.listId !== 'undefined') {
playerVars.list = this.url.listId;
}
if (typeof this.options_.listType !== 'undefined') {
playerVars.listType = this.options_.listType;
}
if (typeof this.options_.modestbranding !== 'undefined') {
playerVars.modestbranding = this.options_.modestbranding;
}
if (typeof this.options_.playlist !== 'undefined') {
playerVars.playlist = this.options_.playlist;
}
if (typeof this.options_.playsinline !== 'undefined') {
playerVars.playsinline = this.options_.playsinline;
}
if (typeof this.options_.rel !== 'undefined') {
playerVars.rel = this.options_.rel;
}
if (typeof this.options_.showinfo !== 'undefined') {
playerVars.showinfo = this.options_.showinfo;
}
if (this.options_.source.src.indexOf('start=') !== -1) {
var srcStartTime = this.options_.source.src.match(/start=([0-9]*)/);
this.options_.start = parseInt(srcStartTime[1]);
}
if (typeof this.options_.start !== 'undefined') {
playerVars.start = this.options_.start;
}
if (typeof this.options_.theme !== 'undefined') {
playerVars.theme = this.options_.theme;
}
// Allow undocumented options to be passed along via customVars
if (typeof this.options_.customVars !== 'undefined') {
var customVars = this.options_.customVars;
Object.keys(customVars).forEach(function(key) {
playerVars[key] = customVars[key];
});
}
this.activeVideoId = this.url ? this.url.videoId : null;
this.activeList = playerVars.list;
var playerConfig = {
videoId: this.activeVideoId,
playerVars: playerVars,
events: {
onReady: this.onPlayerReady.bind(this),
onPlaybackQualityChange: this.onPlayerPlaybackQualityChange.bind(this),
onPlaybackRateChange: this.onPlayerPlaybackRateChange.bind(this),
onStateChange: this.onPlayerStateChange.bind(this),
onVolumeChange: this.onPlayerVolumeChange.bind(this),
onError: this.onPlayerError.bind(this)
}
};
if (typeof this.options_.enablePrivacyEnhancedMode !== 'undefined' && this.options_.enablePrivacyEnhancedMode) {
playerConfig.host = 'https://www.youtube-nocookie.com';
}
this.ytPlayer = new YT.Player(this.options_.techId, playerConfig);
}
onPlayerReady() {
if (this.options_.muted) {
this.ytPlayer.mute();
}
var playbackRates = this.ytPlayer.getAvailablePlaybackRates();
if (playbackRates.length > 1) {
this.featuresPlaybackRate = true;
}
this.playerReady_ = true;
this.triggerReady();
if (this.playOnReady) {
this.play();
} else if (this.cueOnReady) {
this.cueVideoById_(this.url.videoId);
this.activeVideoId = this.url.videoId;
}
}
onPlayerPlaybackQualityChange() {
}
onPlayerPlaybackRateChange() {
this.trigger('ratechange');
}
onPlayerStateChange(e) {
var state = e.data;
if (state === this.lastState || this.errorNumber) {
return;
}
this.lastState = state;
switch (state) {
case -1:
this.trigger('loadstart');
this.trigger('loadedmetadata');
this.trigger('durationchange');
this.trigger('ratechange');
break;
case YT.PlayerState.ENDED:
this.trigger('ended');
break;
case YT.PlayerState.PLAYING:
this.trigger('timeupdate');
this.trigger('durationchange');
this.trigger('playing');
this.trigger('play');
if (this.isSeeking) {
this.onSeeked();
}
break;
case YT.PlayerState.PAUSED:
this.trigger('canplay');
if (this.isSeeking) {
this.onSeeked();
} else {
this.trigger('pause');
}
break;
case YT.PlayerState.BUFFERING:
this.player_.trigger('timeupdate');
this.player_.trigger('waiting');
break;
}
}
onPlayerVolumeChange() {
this.trigger('volumechange');
}
onPlayerError(e) {
this.errorNumber = e.data;
this.trigger('pause');
this.trigger('error');
}
error() {
var code = 1000 + this.errorNumber; // as smaller codes are reserved
switch (this.errorNumber) {
case 5:
return { code: code, message: 'Error while trying to play the video' };
case 2:
case 100:
return { code: code, message: 'Unable to find the video' };
case 101:
case 150:
return {
code: code,
message: 'Playback on other Websites has been disabled by the video owner.'
};
}
return { code: code, message: 'YouTube unknown error (' + this.errorNumber + ')' };
}
loadVideoById_(id) {
var options = {
videoId: id
};
if (this.options_.start) {
options.startSeconds = this.options_.start;
}
if (this.options_.end) {
options.endSeconds = this.options_.end;
}
this.ytPlayer.loadVideoById(options);
}
cueVideoById_(id) {
var options = {
videoId: id
};
if (this.options_.start) {
options.startSeconds = this.options_.start;
}
if (this.options_.end) {
options.endSeconds = this.options_.end;
}
this.ytPlayer.cueVideoById(options);
}
src(src) {
if (src) {
this.setSrc({ src: src });
}
return this.source;
}
poster() {
// You can't start programmaticlly a video with a mobile
// through the iframe so we hide the poster and the play button (with CSS)
if (_isOnMobile) {
return null;
}
return this.poster_;
}
setPoster(poster) {
this.poster_ = poster;
}
setSrc(source) {
if (!source || !source.src) {
return;
}
delete this.errorNumber;
this.source = source;
this.url = Youtube.parseUrl(source.src);
if (!this.options_.poster) {
if (this.url.videoId) {
// Set the low resolution first
this.poster_ = 'https://img.youtube.com/vi/' + this.url.videoId + '/0.jpg';
this.trigger('posterchange');
// Check if their is a high res
this.checkHighResPoster();
}
}
if (this.options_.autoplay && !_isOnMobile) {
if (this.isReady_) {
this.play();
} else {
this.playOnReady = true;
}
} else if (this.activeVideoId !== this.url.videoId) {
if (this.isReady_) {
this.cueVideoById_(this.url.videoId);
this.activeVideoId = this.url.videoId;
} else {
this.cueOnReady = true;
}
}
}
autoplay() {
return this.options_.autoplay;
}
setAutoplay(val) {
this.options_.autoplay = val;
}
loop() {
return this.options_.loop;
}
setLoop(val) {
this.options_.loop = val;
}
play() {
if (!this.url || !this.url.videoId) {
return;
}
this.wasPausedBeforeSeek = false;
if (this.isReady_) {
if (this.url.listId) {
if (this.activeList === this.url.listId) {
this.ytPlayer.playVideo();
} else {
this.ytPlayer.loadPlaylist(this.url.listId);
this.activeList = this.url.listId;
}
}
if (this.activeVideoId === this.url.videoId) {
this.ytPlayer.playVideo();
} else {
this.loadVideoById_(this.url.videoId);
this.activeVideoId = this.url.videoId;
}
} else {
this.trigger('waiting');
this.playOnReady = true;
}
}
pause() {
if (this.ytPlayer) {
this.ytPlayer.pauseVideo();
}
}
paused() {
return (this.ytPlayer) ?
(this.lastState !== YT.PlayerState.PLAYING && this.lastState !== YT.PlayerState.BUFFERING)
: true;
}
currentTime() {
return this.ytPlayer ? this.ytPlayer.getCurrentTime() : 0;
}
setCurrentTime(seconds) {
if (this.lastState === YT.PlayerState.PAUSED) {
this.timeBeforeSeek = this.currentTime();
}
if (!this.isSeeking) {
this.wasPausedBeforeSeek = this.paused();
}
this.ytPlayer.seekTo(seconds, true);
this.trigger('timeupdate');
this.trigger('seeking');
this.isSeeking = true;
// A seek event during pause does not return an event to trigger a seeked event,
// so run an interval timer to look for the currentTime to change
if (this.lastState === YT.PlayerState.PAUSED && this.timeBeforeSeek !== seconds) {
clearInterval(this.checkSeekedInPauseInterval);
this.checkSeekedInPauseInterval = setInterval(function() {
if (this.lastState !== YT.PlayerState.PAUSED || !this.isSeeking) {
// If something changed while we were waiting for the currentTime to change,
// clear the interval timer
clearInterval(this.checkSeekedInPauseInterval);
} else if (this.currentTime() !== this.timeBeforeSeek) {
this.trigger('timeupdate');
this.onSeeked();
}
}.bind(this), 250);
}
}
seeking() {
return this.isSeeking;
}
seekable() {
if(!this.ytPlayer) {
return videojs.createTimeRange();
}
return videojs.createTimeRange(0, this.ytPlayer.getDuration());
}
onSeeked() {
clearInterval(this.checkSeekedInPauseInterval);
this.isSeeking = false;
if (this.wasPausedBeforeSeek) {
this.pause();
}
this.trigger('seeked');
}
playbackRate() {
return this.ytPlayer ? this.ytPlayer.getPlaybackRate() : 1;
}
setPlaybackRate(suggestedRate) {
if (!this.ytPlayer) {
return;
}
this.ytPlayer.setPlaybackRate(suggestedRate);
}
duration() {
return this.ytPlayer ? this.ytPlayer.getDuration() : 0;
}
currentSrc() {
return this.source && this.source.src;
}
ended() {
return this.ytPlayer ? (this.lastState === YT.PlayerState.ENDED) : false;
}
volume() {
return this.ytPlayer ? this.ytPlayer.getVolume() / 100.0 : 1;
}
setVolume(percentAsDecimal) {
if (!this.ytPlayer) {
return;
}
this.ytPlayer.setVolume(percentAsDecimal * 100.0);
}
muted() {
return this.ytPlayer ? this.ytPlayer.isMuted() : false;
}
setMuted(mute) {
if (!this.ytPlayer) {
return;
}
else{
this.muted(true);
}
if (mute) {
this.ytPlayer.mute();
} else {
this.ytPlayer.unMute();
}
this.setTimeout( function(){
this.trigger('volumechange');
}, 50);
}
buffered() {
if(!this.ytPlayer || !this.ytPlayer.getVideoLoadedFraction) {
return videojs.createTimeRange();
}
var bufferedEnd = this.ytPlayer.getVideoLoadedFraction() * this.ytPlayer.getDuration();
return videojs.createTimeRange(0, bufferedEnd);
}
// TODO: Can we really do something with this on YouTUbe?
preload() {}
load() {}
reset() {}
networkState() {
if (!this.ytPlayer) {
return 0; //NETWORK_EMPTY
}
switch (this.ytPlayer.getPlayerState()) {
case -1: //unstarted
return 0; //NETWORK_EMPTY
case 3: //buffering
return 2; //NETWORK_LOADING
default:
return 1; //NETWORK_IDLE
}
}
readyState() {
if (!this.ytPlayer) {
return 0; //HAVE_NOTHING
}
switch (this.ytPlayer.getPlayerState()) {
case -1: //unstarted
return 0; //HAVE_NOTHING
case 5: //video cued
return 1; //HAVE_METADATA
case 3: //buffering
return 2; //HAVE_CURRENT_DATA
default:
return 4; //HAVE_ENOUGH_DATA
}
}
supportsFullScreen() {
return document.fullscreenEnabled ||
document.webkitFullscreenEnabled ||
document.mozFullScreenEnabled ||
document.msFullscreenEnabled;
}
// Tries to get the highest resolution thumbnail available for the video
checkHighResPoster(){
var uri = 'https://img.youtube.com/vi/' + this.url.videoId + '/maxresdefault.jpg';
try {
var image = new Image();
image.onload = function(){
// Onload may still be called if YouTube returns the 120x90 error thumbnail
if('naturalHeight' in image){
if (image.naturalHeight <= 90 || image.naturalWidth <= 120) {
return;
}
} else if(image.height <= 90 || image.width <= 120) {
return;
}
this.poster_ = uri;
this.trigger('posterchange');
}.bind(this);
image.onerror = function(){};
image.src = uri;
}
catch(e){}
}
}
Youtube.isSupported = function() {
return true;
};
Youtube.canPlaySource = function(e) {
return Youtube.canPlayType(e.type);
};
Youtube.canPlayType = function(e) {
return (e === 'video/youtube');
};
Youtube.parseUrl = function(url) {
var result = {
videoId: null
};
var regex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
var match = url.match(regex);
if (match && match[2].length === 11) {
result.videoId = match[2];
}
var regPlaylist = /[?&]list=([^#\&\?]+)/;
match = url.match(regPlaylist);
if(match && match[1]) {
result.listId = match[1];
}
return result;
};
function apiLoaded() {
YT.ready(function() {
Youtube.isApiReady = true;
for (var i = 0; i < Youtube.apiReadyQueue.length; ++i) {
Youtube.apiReadyQueue[i].initYTPlayer();
}
});
}
function loadScript(src, callback) {
var loaded = false;
var tag = document.createElement('script');
var firstScriptTag = document.getElementsByTagName('script')[0];
if (!firstScriptTag) {
// when loaded in jest without jsdom setup it doesn't get any element.
// In jest it doesn't really make sense to do anything, because no one is watching youtube in jest
return;
}
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
tag.onload = function () {
if (!loaded) {
loaded = true;
callback();
}
};
tag.onreadystatechange = function () {
if (!loaded && (this.readyState === 'complete' || this.readyState === 'loaded')) {
loaded = true;
callback();
}
};
tag.src = src;
}
function injectCss() {
var css = // iframe blocker to catch mouse events
'.vjs-youtube .vjs-iframe-blocker { display: none; }' +
'.vjs-youtube.vjs-user-inactive .vjs-iframe-blocker { display: block; }' +
'.vjs-youtube .vjs-poster { background-size: cover; }' +
'.vjs-youtube-mobile .vjs-big-play-button { display: none; }';
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
}
Youtube.apiReadyQueue = [];
if (typeof document !== 'undefined'){
loadScript('https://www.youtube.com/iframe_api', apiLoaded);
injectCss();
}
// Older versions of VJS5 doesn't have the registerTech function
if (typeof videojs.registerTech !== 'undefined') {
videojs.registerTech('Youtube', Youtube);
} else {
videojs.registerComponent('Youtube', Youtube);
}
}));
+154
View File
@@ -0,0 +1,154 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Video JS loader.
*
* This takes care of applying the filter on content which was dynamically loaded.
*
* @module media_videojs/loader
* @copyright 2016 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import Ajax from 'core/ajax';
import Config from 'core/config';
import {eventTypes} from 'core_filters/events';
import LocalStorage from 'core/localstorage';
import Notification from 'core/notification';
import jQuery from 'jquery';
/** @var {bool} Whether this is the first load of videojs module */
let firstLoad;
/** @var {string} The language that is used in the player */
let language;
/** @var {object} List of languages and translations for the current page */
let langStringCache;
/**
* Initialisei teh videojs Loader.
*
* Adds the listener for the event to then notify video.js.
*
* @method
* @param {string} lang Language to be used in the player
* @listens event:filterContentUpdated
*/
export const setUp = (lang) => {
language = lang;
firstLoad = true;
// Notify Video.js about the nodes already present on the page.
notifyVideoJS({
detail: {
nodes: document.body,
}
});
// We need to call popover automatically if nodes are added to the page later.
document.addEventListener(eventTypes.filterContentUpdated, notifyVideoJS);
};
/**
* Notify video.js of new nodes.
*
* @param {Event} e The event.
*/
const notifyVideoJS = e => {
const nodes = jQuery(e.detail.nodes);
const selector = '.mediaplugin_videojs';
const langStrings = getLanguageJson();
// Find the descendants matching the expected parent of the audio and video
// tags. Then also addBack the nodes matching the same selector. Finally,
// we find the audio and video tags contained in those parents. Kind thanks
// to jQuery for the simplicity.
nodes.find(selector)
.addBack(selector)
.find('audio, video').each((index, element) => {
const id = jQuery(element).attr('id');
const config = jQuery(element).data('setup-lazy');
const modulePromises = [import('media_videojs/video-lazy')];
if (config.techOrder && config.techOrder.indexOf('youtube') !== -1) {
// Add YouTube to the list of modules we require.
modulePromises.push(import('media_videojs/Youtube-lazy'));
}
if (config.techOrder && config.techOrder.indexOf('OgvJS') !== -1) {
config.ogvjs = {
worker: true,
wasm: true,
base: Config.wwwroot + '/media/player/videojs/ogvloader.php/' + Config.jsrev + '/'
};
// Add Ogv.JS to the list of modules we require.
modulePromises.push(import('media_videojs/videojs-ogvjs-lazy'));
}
Promise.all([langStrings, ...modulePromises])
.then(([langJson, videojs]) => {
if (firstLoad) {
videojs.addLanguage(language, langJson);
firstLoad = false;
}
videojs(id, config);
return;
})
.catch(Notification.exception);
});
};
/**
* Returns the json object of the language strings to be used in the player.
*
* @returns {Promise}
*/
const getLanguageJson = () => {
if (langStringCache) {
return Promise.resolve(langStringCache);
}
const cacheKey = `media_videojs/${language}`;
const rawCacheContent = LocalStorage.get(cacheKey);
if (rawCacheContent) {
const cacheContent = JSON.parse(rawCacheContent);
langStringCache = cacheContent;
return Promise.resolve(langStringCache);
}
const request = {
methodname: 'media_videojs_get_language',
args: {
lang: language,
},
};
return Ajax.call([request])[0]
.then(langStringData => {
LocalStorage.set(cacheKey, langStringData);
return langStringData;
})
.then(result => JSON.parse(result))
.then(langStrings => {
langStringCache = langStrings;
return langStrings;
});
};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,763 @@
/**
* videojs-ogvjs
* @version 1.0.0
* @copyright 2023 Huong Nguyen <huongnv13@gmail.com>
* @license MIT
*/
define(['media_videojs/video-lazy', './local/ogv/ogv'], (function (videojs, ogv) { 'use strict';
// We can access public classes either as ogv.OGVPlayer or just OGVPlayer.
// But ogv.OGVPlayer will make the lint tools happier.
const OGVCompat = ogv.OGVCompat;
const OGVLoader = ogv.OGVLoader;
const OGVPlayer = ogv.OGVPlayer;
const Tech = videojs.getComponent('Tech');
const androidOS = 'Android';
const iPhoneOS = 'iPhoneOS';
const iPadOS = 'iPadOS';
const otherOS = 'Other';
/**
* Object.defineProperty but "lazy", which means that the value is only set after
* it retrieved the first time, rather than being set right away.
*
* @param {Object} obj the object to set the property on.
* @param {string} key the key for the property to set.
* @param {Function} getValue the function used to get the value when it is needed.
* @param {boolean} setter whether a setter should be allowed or not.
*/
const defineLazyProperty = (obj, key, getValue, setter = true) => {
const set = (value) => {
Object.defineProperty(obj, key, {value, enumerable: true, writable: true});
};
const options = {
configurable: true,
enumerable: true,
get() {
const value = getValue();
set(value);
return value;
}
};
if (setter) {
options.set = set;
}
return Object.defineProperty(obj, key, options);
};
/**
* Get the device's OS.
*
* @return {string} Device's OS.
*/
const getDeviceOS = () => {
/* global navigator */
const ua = navigator.userAgent;
if (/android/i.test(ua)) {
return androidOS;
} else if (/iPad|iPhone|iPod/.test(ua)) {
return iPhoneOS;
} else if ((navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) {
return iPadOS;
}
return otherOS;
};
/**
* OgvJS Media Controller - Wrapper for ogv.js Media API
*
* @mixes Tech~SourceHandlerAdditions
* @extends Tech
*/
class OgvJS extends Tech {
/**
* Create an instance of this Tech.
*
* @param {Object} [options] The key/value store of player options.
* @param {Component~ReadyCallback} ready Callback function to call when the `OgvJS` Tech is ready.
*/
constructor(options, ready) {
super(options, ready);
this.el_.src = options.source.src;
OgvJS.setIfAvailable(this.el_, 'autoplay', options.autoplay);
OgvJS.setIfAvailable(this.el_, 'loop', options.loop);
OgvJS.setIfAvailable(this.el_, 'poster', options.poster);
OgvJS.setIfAvailable(this.el_, 'preload', options.preload);
this.on('loadedmetadata', () => {
if (getDeviceOS() === iPhoneOS) {
// iPhoneOS add some inline styles to the canvas, we need to remove it.
const canvas = this.el_.getElementsByTagName('canvas')[0];
canvas.style.removeProperty('width');
canvas.style.removeProperty('margin');
}
});
this.triggerReady();
}
/**
* Create the 'OgvJS' Tech's DOM element.
*
* @return {Element} The element that gets created.
*/
createEl() {
const options = this.options_;
if (options.base) {
OGVLoader.base = options.base;
} else {
throw new Error('Please specify the base for the ogv.js library');
}
const el = new OGVPlayer(options);
el.className += ' vjs-tech';
options.tag = el;
return el;
}
/**
* Start playback
*
* @method play
*/
play() {
this.el_.play();
}
/**
* Get the current playback speed.
*
* @return {number}
* @method playbackRate
*/
playbackRate() {
return this.el_.playbackRate || 1;
}
/**
* Set the playback speed.
*
* @param {number} val Speed for the player to play.
* @method setPlaybackRate
*/
setPlaybackRate(val) {
if (this.el_.hasOwnProperty('playbackRate')) {
this.el_.playbackRate = val;
}
}
/**
* Returns a TimeRanges object that represents the ranges of the media resource that the user agent has played.
*
* @return {TimeRangeObject} the range of points on the media timeline that has been reached through normal playback
*/
played() {
return this.el_.played;
}
/**
* Pause playback
*
* @method pause
*/
pause() {
this.el_.pause();
}
/**
* Is the player paused or not.
*
* @return {boolean}
* @method paused
*/
paused() {
return this.el_.paused;
}
/**
* Get current playing time.
*
* @return {number}
* @method currentTime
*/
currentTime() {
return this.el_.currentTime;
}
/**
* Set current playing time.
*
* @param {number} seconds Current time of audio/video.
* @method setCurrentTime
*/
setCurrentTime(seconds) {
try {
this.el_.currentTime = seconds;
} catch (e) {
videojs.log(e, 'Media is not ready. (Video.JS)');
}
}
/**
* Get media's duration.
*
* @return {number}
* @method duration
*/
duration() {
if (this.el_.duration && this.el_.duration !== Infinity) {
return this.el_.duration;
}
return 0;
}
/**
* Get a TimeRange object that represents the intersection
* of the time ranges for which the user agent has all
* relevant media.
*
* @return {TimeRangeObject}
* @method buffered
*/
buffered() {
return this.el_.buffered;
}
/**
* Get current volume level.
*
* @return {number}
* @method volume
*/
volume() {
return this.el_.hasOwnProperty('volume') ? this.el_.volume : 1;
}
/**
* Set current playing volume level.
*
* @param {number} percentAsDecimal Volume percent as a decimal.
* @method setVolume
*/
setVolume(percentAsDecimal) {
// Apple does not allow iOS and iPadOS devices to set the volume on UI.
if (getDeviceOS() !== iPhoneOS && getDeviceOS() !== iPadOS && this.el_.hasOwnProperty('volume')) {
this.el_.volume = percentAsDecimal;
}
}
/**
* Is the player muted or not.
*
* @return {boolean}
* @method muted
*/
muted() {
return this.el_.muted;
}
/**
* Mute the player.
*
* @param {boolean} muted True to mute the player.
*/
setMuted(muted) {
this.el_.muted = !!muted;
}
/**
* Is the player muted by default or not.
*
* @return {boolean}
* @method defaultMuted
*/
defaultMuted() {
return this.el_.defaultMuted || false;
}
/**
* Get the player width.
*
* @return {number}
* @method width
*/
width() {
return this.el_.offsetWidth;
}
/**
* Get the player height.
*
* @return {number}
* @method height
*/
height() {
return this.el_.offsetHeight;
}
/**
* Get the video width.
*
* @return {number}
* @method videoWidth
*/
videoWidth() {
return this.el_.videoWidth;
}
/**
* Get the video height.
*
* @return {number}
* @method videoHeight
*/
videoHeight() {
return this.el_.videoHeight;
}
/**
* Get/set media source.
*
* @param {Object=} src Source object
* @return {Object}
* @method src
*/
src(src) {
if (typeof src === 'undefined') {
return this.el_.src;
}
this.el_.src = src;
}
/**
* Load the media into the player.
*
* @method load
*/
load() {
this.el_.load();
}
/**
* Get current media source.
*
* @return {Object}
* @method currentSrc
*/
currentSrc() {
if (this.currentSource_) {
return this.currentSource_.src;
}
return this.el_.currentSrc;
}
/**
* Get media poster URL.
*
* @return {string}
* @method poster
*/
poster() {
return this.el_.poster;
}
/**
* Set media poster URL.
*
* @param {string} url the poster image's url.
* @method
*/
setPoster(url) {
this.el_.poster = url;
}
/**
* Is the media preloaded or not.
*
* @return {string}
* @method preload
*/
preload() {
return this.el_.preload || 'none';
}
/**
* Set the media preload method.
*
* @param {string} val Value for preload attribute.
* @method setPreload
*/
setPreload(val) {
if (this.el_.hasOwnProperty('preload')) {
this.el_.preload = val;
}
}
/**
* Is the media auto-played or not.
*
* @return {boolean}
* @method autoplay
*/
autoplay() {
return this.el_.autoplay || false;
}
/**
* Set media autoplay method.
*
* @param {boolean} val Value for autoplay attribute.
* @method setAutoplay
*/
setAutoplay(val) {
if (this.el_.hasOwnProperty('autoplay')) {
this.el_.autoplay = !!val;
}
}
/**
* Does the media has controls or not.
*
* @return {boolean}
* @method controls
*/
controls() {
return this.el_.controls || false;
}
/**
* Set the media controls method.
*
* @param {boolean} val Value for controls attribute.
* @method setControls
*/
setControls(val) {
if (this.el_.hasOwnProperty('controls')) {
this.el_.controls = !!val;
}
}
/**
* Is the media looped or not.
*
* @return {boolean}
* @method loop
*/
loop() {
return this.el_.loop || false;
}
/**
* Set the media loop method.
*
* @param {boolean} val Value for loop attribute.
* @method setLoop
*/
setLoop(val) {
if (this.el_.hasOwnProperty('loop')) {
this.el_.loop = !!val;
}
}
/**
* Get a TimeRanges object that represents the
* ranges of the media resource to which it is possible
* for the user agent to seek.
*
* @return {TimeRangeObject}
* @method seekable
*/
seekable() {
return this.el_.seekable;
}
/**
* Is player in the "seeking" state or not.
*
* @return {boolean}
* @method seeking
*/
seeking() {
return this.el_.seeking;
}
/**
* Is the media ended or not.
*
* @return {boolean}
* @method ended
*/
ended() {
return this.el_.ended;
}
/**
* Get the current state of network activity
* NETWORK_EMPTY (numeric value 0)
* NETWORK_IDLE (numeric value 1)
* NETWORK_LOADING (numeric value 2)
* NETWORK_NO_SOURCE (numeric value 3)
*
* @return {number}
* @method networkState
*/
networkState() {
return this.el_.networkState;
}
/**
* Get the current state of the player.
* HAVE_NOTHING (numeric value 0)
* HAVE_METADATA (numeric value 1)
* HAVE_CURRENT_DATA (numeric value 2)
* HAVE_FUTURE_DATA (numeric value 3)
* HAVE_ENOUGH_DATA (numeric value 4)
*
* @return {number}
* @method readyState
*/
readyState() {
return this.el_.readyState;
}
/**
* Does the player support native fullscreen mode or not. (Mobile devices)
*
* @return {boolean}
*/
supportsFullScreen() {
// iOS devices have some problem with HTML5 fullscreen api so we need to fallback to fullWindow mode.
return false;
}
/**
* Get media player error.
*
* @return {string}
* @method error
*/
error() {
return this.el_.error;
}
}
/**
* List of available events of the media player.
*
* @private
* @type {Array}
*/
OgvJS.Events = [
'loadstart',
'suspend',
'abort',
'error',
'emptied',
'stalled',
'loadedmetadata',
'loadeddata',
'canplay',
'canplaythrough',
'playing',
'waiting',
'seeking',
'seeked',
'ended',
'durationchange',
'timeupdate',
'progress',
'play',
'pause',
'ratechange',
'resize',
'volumechange'
];
/**
* Set the value for the player is it has that property.
*
* @param {Element} el
* @param {string} name
* @param value
*/
OgvJS.setIfAvailable = (el, name, value) => {
if (el.hasOwnProperty(name)) {
el[name] = value;
}
};
/**
* Check if browser/device is supported by Ogv.JS.
*
* @return {boolean}
*/
OgvJS.isSupported = () => {
return OGVCompat.supported('OGVPlayer');
};
/**
* Check if the tech can support the given type.
*
* @param {string} type The mimetype to check
* @return {string} 'probably', 'maybe', or '' (empty string)
*/
OgvJS.canPlayType = (type) => {
return (type.indexOf('/ogg') !== -1 || type.indexOf('/webm')) ? 'maybe' : '';
};
/**
* Check if the tech can support the given source
*
* @param srcObj The source object
* @return {string} The options passed to the tech
*/
OgvJS.canPlaySource = (srcObj) => {
return OgvJS.canPlayType(srcObj.type);
};
/**
* Check if the volume can be changed in this browser/device.
* Volume cannot be changed in a lot of mobile devices.
* Specifically, it can't be changed on iOS and iPadOS.
*
* @return {boolean} True if volume can be controlled.
*/
OgvJS.canControlVolume = () => {
if (getDeviceOS() === iPhoneOS || getDeviceOS() === iPadOS) {
return false;
}
const p = new OGVPlayer();
return p.hasOwnProperty('volume');
};
/**
* Check if the volume can be muted in this browser/device.
*
* @return {boolean} True if volume can be muted.
*/
OgvJS.canMuteVolume = () => {
return true;
};
/**
* Check if the playback rate can be changed in this browser/device.
*
* @return {boolean} True if playback rate can be controlled.
*/
OgvJS.canControlPlaybackRate = () => {
return true;
};
/**
* Check to see if native 'TextTracks' are supported by this browser/device.
*
* @return {boolean} True if native 'TextTracks' are supported.
*/
OgvJS.supportsNativeTextTracks = () => {
return false;
};
/**
* Check if the fullscreen resize is supported by this browser/device.
*
* @return {boolean} True if the fullscreen resize is supported.
*/
OgvJS.supportsFullscreenResize = () => {
return true;
};
/**
* Check if the progress events is supported by this browser/device.
*
* @return {boolean} True if the progress events is supported.
*/
OgvJS.supportsProgressEvents = () => {
return true;
};
/**
* Check if the time update events is supported by this browser/device.
*
* @return {boolean} True if the time update events is supported.
*/
OgvJS.supportsTimeupdateEvents = () => {
return true;
};
/**
* Boolean indicating whether the 'OgvJS' tech supports volume control.
*
* @type {boolean}
* @default {@link OgvJS.canControlVolume}
*/
/**
* Boolean indicating whether the 'OgvJS' tech supports muting volume.
*
* @type {boolean}
* @default {@link OgvJS.canMuteVolume}
*/
/**
* Boolean indicating whether the 'OgvJS' tech supports changing the speed at which the media plays.
* Examples:
* - Set player to play 2x (twice) as fast.
* - Set player to play 0.5x (half) as fast.
*
* @type {boolean}
* @default {@link OgvJS.canControlPlaybackRate}
*/
/**
* Boolean indicating whether the 'OgvJS' tech currently supports native 'TextTracks'.
*
* @type {boolean}
* @default {@link OgvJS.supportsNativeTextTracks}
*/
/**
* Boolean indicating whether the 'OgvJS' tech currently supports fullscreen resize.
*
* @type {boolean}
* @default {@link OgvJS.supportsFullscreenResize}
*/
/**
* Boolean indicating whether the 'OgvJS' tech currently supports progress events.
*
* @type {boolean}
* @default {@link OgvJS.supportsProgressEvents}
*/
/**
* Boolean indicating whether the 'OgvJS' tech currently supports time update events.
*
* @type {boolean}
* @default {@link OgvJS.supportsTimeupdateEvents}
*/
[
['featuresVolumeControl', 'canControlVolume'],
['featuresMuteControl', 'canMuteVolume'],
['featuresPlaybackRate', 'canControlPlaybackRate'],
['featuresNativeTextTracks', 'supportsNativeTextTracks'],
['featuresFullscreenResize', 'supportsFullscreenResize'],
['featuresProgressEvents', 'supportsProgressEvents'],
['featuresTimeupdateEvents', 'supportsTimeupdateEvents']
].forEach(([key, fn]) => {
defineLazyProperty(OgvJS.prototype, key, () => OgvJS[fn](), true);
});
Tech.registerTech('OgvJS', OgvJS);
return OgvJS;
}));
+66
View File
@@ -0,0 +1,66 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace media_videojs\external;
use core_external\external_api;
use core_external\external_function_parameters;
use core_external\external_value;
/**
* The API to get language strings for the videojs.
*
* @package media_videojs
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class get_language extends external_api {
/**
* Returns description of parameters.
*
* @return external_function_parameters
*/
public static function execute_parameters() {
return new external_function_parameters([
'lang' => new external_value(PARAM_ALPHAEXT, 'language')
]);
}
/**
* Returns language strings in the JSON format
*
* @param string $lang The language code
* @return string
*/
public static function execute(string $lang) {
[
'lang' => $lang,
] = external_api::validate_parameters(self::execute_parameters(), [
'lang' => $lang,
]);
return \media_videojs_plugin::get_language_content($lang);
}
/**
* Returns description of method result value
*
* @return external_value
*/
public static function execute_returns() {
return new external_value(PARAM_RAW, 'language pack json');
}
}
+439
View File
@@ -0,0 +1,439 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Main class for plugin 'media_videojs'
*
* @package media_videojs
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Player that creates HTML5 <video> tag.
*
* @package media_videojs
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class media_videojs_plugin extends core_media_player_native {
/** @var array caches last moodle_page used to include AMD modules */
protected $loadedonpage = [];
/** @var string language file to use */
protected $language = 'en';
/** @var array caches supported extensions */
protected $extensions = null;
/** @var bool is this a youtube link */
protected $youtube = false;
/** @var bool Need to use Ogv.JS Tech plugin or not. */
protected $ogvtech = false;
/** @var array Ogv.JS supported extensions */
protected $ogvsupportedextensions = [
'.ogv',
'.webm',
'.oga',
'.ogg'
];
/**
* Generates code required to embed the player.
*
* @param moodle_url[] $urls
* @param string $name
* @param int $width
* @param int $height
* @param array $options
* @return string
*/
public function embed($urls, $name, $width, $height, $options) {
global $CFG;
require_once($CFG->libdir . '/filelib.php');
$sources = array();
$mediamanager = core_media_manager::instance();
$datasetup = [];
$text = null;
$isaudio = null;
$hastracks = false;
$hasposter = false;
if (array_key_exists(core_media_manager::OPTION_ORIGINAL_TEXT, $options) &&
preg_match('/^<(video|audio)\b/i', $options[core_media_manager::OPTION_ORIGINAL_TEXT], $matches)) {
// Original text already had media tag - get some data from it.
$text = $options[core_media_manager::OPTION_ORIGINAL_TEXT];
$isaudio = strtolower($matches[1]) === 'audio';
$hastracks = preg_match('/<track\b/i', $text);
$hasposter = self::get_attribute($text, 'poster') !== null;
}
// Try to guess if HTML5 player will be engaged for the user and then set it to responsive.
$responsive = (!$this->youtube) ? null : true;
// Build list of source tags.
foreach ($urls as $url) {
$extension = $mediamanager->get_extension($url);
$mimetype = $mediamanager->get_mimetype($url);
if ($mimetype === 'video/quicktime' && (core_useragent::is_chrome() || core_useragent::is_edge())) {
// Fix for VideoJS/Chrome bug https://github.com/videojs/video.js/issues/423 .
$mimetype = 'video/mp4';
}
// If this is RTMP stream, adjust mimetype to those VideoJS suggests to use (either flash or mp4).
if ($url->get_scheme() === 'rtmp') {
if ($mimetype === 'video/x-flv') {
$mimetype = 'rtmp/flv';
} else {
$mimetype = 'rtmp/mp4';
}
}
$source = html_writer::empty_tag('source', array('src' => $url, 'type' => $mimetype));
$sources[] = $source;
if ($isaudio === null) {
$isaudio = in_array('.' . $extension, file_get_typegroup('extension', 'audio'));
}
if ($responsive === null) {
$responsive = core_useragent::supports_html5($extension);
}
}
$sources = implode("\n", $sources);
// Find the title, prevent double escaping.
$title = $this->get_name($name, $urls);
$title = preg_replace(['/&amp;/', '/&gt;/', '/&lt;/'], ['&', '>', '<'], $title);
if ($this->youtube) {
$datasetup[] = '"techOrder": ["youtube"]';
$datasetup[] = '"sources": [{"type": "video/youtube", "src":"' . $urls[0] . '"}]';
// Check if we have a time parameter.
if ($time = $urls[0]->get_param('t')) {
$datasetup[] = '"youtube": {"start": "' . self::get_start_time($time) . '"}';
}
$sources = ''; // Do not specify <source> tags - it may confuse browser.
$isaudio = false; // Just in case.
}
if ($this->ogvtech) {
$datasetup[] = '"techOrder": ["OgvJS"]';
}
// Add a language.
if ($this->language) {
$datasetup[] = '"language": "' . $this->language . '"';
}
// Set responsive option.
if ($responsive) {
$datasetup[] = '"fluid": true';
}
if ($isaudio && !$hastracks) {
// We don't need a full screen toggle for the audios (except when tracks are present).
$datasetup[] = '"controlBar": {"fullscreenToggle": false}';
}
if ($isaudio && !$height && !$hastracks && !$hasposter) {
// Hide poster area for audios without tracks or poster.
// See discussion on https://github.com/videojs/video.js/issues/2777 .
// Maybe TODO: if there are only chapter tracks we still don't need poster area.
$datasetup[] = '"aspectRatio": "1:0"';
}
// Additional setup for playback rate and user actions.
$datasetup[] = '"playbackRates": [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2]';
$datasetup[] = '"userActions": {"hotkeys": true}';
// Attributes for the video/audio tag.
// We use data-setup-lazy as the attribute name for the config instead of
// data-setup because data-setup will cause video.js to load the player as soon as the library is loaded,
// which is BEFORE we have a chance to load any additional libraries (youtube).
// The data-setup-lazy is just a tag name that video.js does not recognise so we can manually initialise
// it when we are sure the dependencies are loaded.
static $playercounter = 1;
$attributes = [
'data-setup-lazy' => '{' . join(', ', $datasetup) . '}',
'id' => 'id_videojs_' . uniqid() . '_' . $playercounter++,
'class' => get_config('media_videojs', $isaudio ? 'audiocssclass' : 'videocssclass')
];
if (!$responsive) {
// Note we ignore limitsize setting if not responsive.
parent::pick_video_size($width, $height);
$attributes += ['width' => $width] + ($height ? ['height' => $height] : []);
}
if (core_useragent::is_ios(10)) {
// Hides native controls and plays videos inline instead of fullscreen,
// see https://github.com/videojs/video.js/issues/3761 and
// https://github.com/videojs/video.js/issues/3762 .
// iPhone with iOS 9 still displays double controls and plays fullscreen.
// iPhone with iOS before 9 display only native controls.
$attributes += ['playsinline' => 'true'];
}
if ($text !== null) {
// Original text already had media tag - add necessary attributes and replace sources
// with the supported URLs only.
if (($class = self::get_attribute($text, 'class')) !== null) {
$attributes['class'] .= ' ' . $class;
}
$text = self::remove_attributes($text, ['id', 'width', 'height', 'class']);
if (self::get_attribute($text, 'title') === null) {
$attributes['title'] = $title;
}
$text = self::add_attributes($text, $attributes);
$text = self::replace_sources($text, $sources);
} else {
// Create <video> or <audio> tag with necessary attributes and all sources.
// We don't want fallback to another player because list_supported_urls() is already smart.
// Otherwise we could end up with nested <audio> or <video> tags. Fallback to link only.
$attributes += ['preload' => 'auto', 'controls' => 'true', 'title' => $title];
$text = html_writer::tag($isaudio ? 'audio' : 'video', $sources . self::LINKPLACEHOLDER, $attributes);
}
// Limit the width of the video if width is specified.
// We do not do it in the width attributes of the video because it does not work well
// together with responsive behavior.
if ($responsive) {
self::pick_video_size($width, $height);
if ($width) {
$text = html_writer::div($text, null, ['style' => 'max-width:' . $width . 'px;']);
}
}
return html_writer::div($text, 'mediaplugin mediaplugin_videojs d-block');
}
/**
* Utility function that sets width and height to defaults if not specified
* as a parameter to the function (will be specified either if, (a) the calling
* code passed it, or (b) the URL included it).
* @param int $width Width passed to function (updated with final value)
* @param int $height Height passed to function (updated with final value)
*/
protected static function pick_video_size(&$width, &$height) {
if (!get_config('media_videojs', 'limitsize')) {
return;
}
parent::pick_video_size($width, $height);
}
/**
* Method to convert Youtube time parameter string, which can contain human readable time
* intervals such as '1h5m', '1m10s', etc or a numeric seconds value
*
* @param string $timestr
* @return int
*/
protected static function get_start_time(string $timestr): int {
if (is_numeric($timestr)) {
// We can return the time string itself if it's already numeric.
return (int) $timestr;
}
try {
// Parse the time string as an ISO 8601 time interval.
$timeinterval = new DateInterval('PT' . core_text::strtoupper($timestr));
return ($timeinterval->h * HOURSECS) + ($timeinterval->i * MINSECS) + $timeinterval->s;
} catch (Exception $ex) {
// Invalid time interval.
return 0;
}
}
public function get_supported_extensions() {
global $CFG;
require_once($CFG->libdir . '/filelib.php');
if ($this->extensions === null) {
// Get extensions set by user in UI config.
$filetypes = preg_split('/\s*,\s*/',
strtolower(trim(get_config('media_videojs', 'videoextensions') . ',' .
get_config('media_videojs', 'audioextensions'))));
$this->extensions = file_get_typegroup('extension', $filetypes);
if ($this->extensions) {
// Get extensions supported by player.
$supportedextensions = array_merge(file_get_typegroup('extension', 'html_video'),
file_get_typegroup('extension', 'html_audio'), file_get_typegroup('extension', 'media_source'));
$this->extensions = array_intersect($this->extensions, $supportedextensions);
}
}
return $this->extensions;
}
public function list_supported_urls(array $urls, array $options = array()) {
$result = [];
// Youtube.
$this->youtube = false;
if (count($urls) == 1 && get_config('media_videojs', 'youtube')) {
$url = reset($urls);
// Check against regex.
if (preg_match($this->get_regex_youtube(), $url->out(false), $matches)) {
$this->youtube = true;
return array($url);
}
}
$extensions = $this->get_supported_extensions();
foreach ($urls as $url) {
// Skip the URL that is using RTMP (which might have been picked to the list by its valid extension).
if ($url->get_scheme() === 'rtmp') {
continue;
}
$ext = '.' . core_media_manager::instance()->get_extension($url);
// Handle HLS and MPEG-DASH if supported.
$isstream = in_array($ext, file_get_typegroup('extension', 'media_source'));
if ($isstream && in_array($ext, $extensions) && core_useragent::supports_media_source_extensions($ext)) {
$result[] = $url;
continue;
}
// Ogv.JS Tech.
$this->ogvtech = false;
if (in_array($ext, $this->ogvsupportedextensions) &&
(core_useragent::is_safari() || core_useragent::is_ios() || core_useragent::is_chrome())) {
// Chrome has stopped supporting OGV in the latest version. Refer: https://caniuse.com/ogv.
// We need to enable Ogv.JS Tech plugin for Safari, iOS and Chrome.
$this->ogvtech = true;
$result[] = $url;
continue;
}
return parent::list_supported_urls($urls, $options);
}
return $result;
}
/**
* Default rank
* @return int
*/
public function get_rank() {
return 2000;
}
/**
* Tries to match the current language to existing language files
*
* Matched language is stored in $this->language
*
* @return string JS code with a setting
*/
protected function find_language() {
global $CFG;
$this->language = current_language();
$basedir = $CFG->dirroot . '/media/player/videojs/videojs/lang/';
$langfiles = get_directory_list($basedir);
$candidates = [];
foreach ($langfiles as $langfile) {
if (strtolower(pathinfo($langfile, PATHINFO_EXTENSION)) !== 'json') {
continue;
}
$lang = basename($langfile, '.json');
if (strtolower($langfile) === $this->language . '.json') {
// Found an exact match for the language. It is stored in $this->language.
return;
}
if (substr($this->language, 0, 2) === strtolower(substr($langfile, 0, 2))) {
// Not an exact match but similar, for example "pt_br" is similar to "pt".
$candidates[$lang] = $langfile;
}
}
if ($candidates) {
// Exact match was not found, take the first candidate.
$this->language = key($candidates);
} else {
// Could not match, use default language of video player (English).
$this->language = 'en';
}
}
/**
* Returns the requested language pack in the json format.
*
* @param string $lang The language code
* @return false|string The read data or false on failure
*/
public static function get_language_content(string $lang) {
global $CFG;
$langfile = "{$CFG->dirroot}/media/player/videojs/videojs/lang/{$lang}.json";
return file_exists($langfile) ? file_get_contents($langfile) : '';
}
public function supports($usedextensions = []) {
$supports = parent::supports($usedextensions);
if (get_config('media_videojs', 'youtube')) {
$supports .= ($supports ? '<br>' : '') . get_string('youtube', 'media_videojs');
}
return $supports;
}
public function get_embeddable_markers() {
$markers = parent::get_embeddable_markers();
// Add YouTube support if enabled.
if (get_config('media_videojs', 'youtube')) {
$markers = array_merge($markers, array('youtube.com', 'youtube-nocookie.com', 'youtu.be', 'y2u.be'));
}
return $markers;
}
/**
* Returns regular expression used to match URLs for single youtube video
* @return string PHP regular expression e.g. '~^https?://example.org/~'
*/
protected function get_regex_youtube() {
// Regex for standard youtube link.
$link = '(youtube(-nocookie)?\.com/(?:watch\?v=|v/))';
// Regex for shortened youtube link.
$shortlink = '((youtu|y2u)\.be/)';
// Initial part of link.
$start = '~^https?://(www\.)?(' . $link . '|' . $shortlink . ')';
// Middle bit: Video key value.
$middle = '([a-z0-9\-_]+)';
return $start . $middle . core_media_player_external::END_LINK_REGEX_PART;
}
/**
* Setup page requirements.
*
* @param moodle_page $page The page we are going to add requirements to.
*/
public function setup($page) {
if (during_initial_install() || is_major_upgrade_required()) {
return;
}
// Load dynamic loader. It will scan page for videojs media and load necessary modules.
// Loader will be loaded on absolutely every page, however the videojs will only be loaded
// when video is present on the page or added later to it in AJAX.
$this->find_language();
$page->requires->js_amd_inline(<<<EOT
require(["media_videojs/loader"], function(loader) {
loader.setUp('$this->language');
});
EOT
);
}
}
@@ -0,0 +1,46 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy provider implementation for media_videojs.
*
* @package media_videojs
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace media_videojs\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy provider implementation for media_videojs.
*
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason(): string {
return 'privacy:metadata';
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* VideoJS player external functions and service definitions.
*
* @package media_videojs
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die;
$functions = [
'media_videojs_get_language' => [
'classname' => 'media_videojs\external\get_language',
'classpath' => '',
'description' => 'get language.',
'type' => 'read',
'ajax' => true,
'capabilities' => '',
'loginrequired' => false,
]
];
+65
View File
@@ -0,0 +1,65 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* VideoJS media player upgrade code
*
* This file keeps track of upgrades to
* the videojs media player.
*
* Sometimes, changes between versions involve
* alterations to database structures and other
* major things that may break installations.
*
* The upgrade function in this file will attempt
* to perform all the necessary actions to upgrade
* your older installation to the current version.
*
* If there's something it cannot do itself, it
* will tell you what you need to do.
*
* The commands in here will all be database-neutral,
* using the methods of database_manager class
*
* Please do not forget to use upgrade_set_timeout()
* before any action that may take longer time to finish.
*
* @package media_videojs
* @copyright 2021 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Main upgrade tasks to be executed on plugin version bump.
*
* @param int $oldversion
* @return bool always true
*/
function xmldb_media_videojs_upgrade($oldversion) {
// Automatically generated Moodle v4.1.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.2.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.3.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
+150
View File
@@ -0,0 +1,150 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMid meet">
<defs>
<font id="VideoJS" horiz-adv-x="1792">
<font-face font-family="VideoJS"
units-per-em="1792" ascent="1792"
descent="0" />
<missing-glyph horiz-adv-x="0" />
<glyph glyph-name="play"
unicode="&#xF101;"
horiz-adv-x="1792" d=" M597.3333333333334 1418.6666666666665V373.3333333333333L1418.6666666666667 896z" />
<glyph glyph-name="play-circle"
unicode="&#xF102;"
horiz-adv-x="1792" d=" M746.6666666666667 560L1194.6666666666667 896L746.6666666666667 1232V560zM896 1642.6666666666667C483.4666666666667 1642.6666666666667 149.3333333333334 1308.5333333333333 149.3333333333334 896S483.4666666666667 149.3333333333333 896 149.3333333333333S1642.6666666666667 483.4666666666667 1642.6666666666667 896S1308.5333333333333 1642.6666666666667 896 1642.6666666666667zM896 298.6666666666665C566.72 298.6666666666665 298.6666666666667 566.7199999999998 298.6666666666667 896S566.72 1493.3333333333333 896 1493.3333333333333S1493.3333333333335 1225.28 1493.3333333333335 896S1225.2800000000002 298.6666666666665 896 298.6666666666665z" />
<glyph glyph-name="pause"
unicode="&#xF103;"
horiz-adv-x="1792" d=" M448 373.3333333333333H746.6666666666667V1418.6666666666665H448V373.3333333333333zM1045.3333333333335 1418.6666666666665V373.3333333333333H1344V1418.6666666666665H1045.3333333333335z" />
<glyph glyph-name="volume-mute"
unicode="&#xF104;"
horiz-adv-x="1792" d=" M1232 896C1232 1027.7866666666666 1155.8400000000001 1141.6533333333332 1045.3333333333335 1196.5333333333333V1031.52L1228.6399999999999 848.2133333333334C1230.88 863.8933333333334 1232 879.9466666666667 1232 896.0000000000001zM1418.6666666666667 896C1418.6666666666667 825.8133333333333 1403.3600000000001 759.7333333333333 1378.3466666666668 698.8799999999999L1491.466666666667 585.7599999999998C1540 678.72 1568 783.9999999999999 1568 896C1568 1215.5733333333333 1344.3733333333334 1482.88 1045.3333333333335 1550.8266666666666V1396.6399999999999C1261.1200000000001 1332.4266666666667 1418.6666666666667 1132.6933333333332 1418.6666666666667 896zM319.2000000000001 1568L224 1472.8L576.8 1120H224V672H522.6666666666667L896 298.6666666666665V800.8L1213.7066666666667 483.0933333333332C1163.68 444.6399999999999 1107.3066666666666 413.6533333333332 1045.3333333333335 394.9866666666665V240.7999999999998C1148 264.32 1241.7066666666667 311.3599999999997 1320.48 375.9466666666663L1472.8000000000002 224L1568 319.1999999999998L896 991.1999999999998L319.2000000000001 1568zM896 1493.3333333333333L739.9466666666667 1337.28L896 1181.2266666666667V1493.3333333333333z" />
<glyph glyph-name="volume-low"
unicode="&#xF105;"
horiz-adv-x="1792" d=" M522.6666666666667 1120V672H821.3333333333334L1194.6666666666667 298.6666666666665V1493.3333333333333L821.3333333333334 1120H522.6666666666667z" />
<glyph glyph-name="volume-mid"
unicode="&#xF106;"
horiz-adv-x="1792" d=" M1381.3333333333335 896C1381.3333333333335 1027.7866666666666 1305.1733333333334 1141.6533333333332 1194.6666666666667 1196.5333333333333V595.0933333333332C1305.1733333333334 650.3466666666666 1381.3333333333335 764.2133333333331 1381.3333333333335 896zM373.3333333333334 1120V672H672L1045.3333333333335 298.6666666666665V1493.3333333333333L672 1120H373.3333333333334z" />
<glyph glyph-name="volume-high"
unicode="&#xF107;"
horiz-adv-x="1792" d=" M224 1120V672H522.6666666666667L896 298.6666666666665V1493.3333333333333L522.6666666666667 1120H224zM1232 896C1232 1027.7866666666666 1155.8400000000001 1141.6533333333332 1045.3333333333335 1196.5333333333333V595.0933333333332C1155.8400000000001 650.3466666666666 1232 764.2133333333331 1232 896zM1045.3333333333335 1550.8266666666666V1396.6399999999999C1261.1200000000001 1332.4266666666667 1418.6666666666667 1132.6933333333332 1418.6666666666667 896S1261.1200000000001 459.5733333333333 1045.3333333333335 395.3600000000002V241.1733333333332C1344.3733333333334 309.1199999999999 1568 576.0533333333333 1568 896S1344.3733333333334 1482.88 1045.3333333333335 1550.8266666666666z" />
<glyph glyph-name="fullscreen-enter"
unicode="&#xF108;"
horiz-adv-x="1792" d=" M522.6666666666667 746.6666666666665H373.3333333333334V373.3333333333333H746.6666666666667V522.6666666666665H522.6666666666667V746.6666666666665zM373.3333333333334 1045.3333333333333H522.6666666666667V1269.3333333333333H746.6666666666667V1418.6666666666665H373.3333333333334V1045.3333333333333zM1269.3333333333335 522.6666666666665H1045.3333333333335V373.3333333333333H1418.6666666666667V746.6666666666665H1269.3333333333335V522.6666666666665zM1045.3333333333335 1418.6666666666665V1269.3333333333333H1269.3333333333335V1045.3333333333333H1418.6666666666667V1418.6666666666665H1045.3333333333335z" />
<glyph glyph-name="fullscreen-exit"
unicode="&#xF109;"
horiz-adv-x="1792" d=" M373.3333333333334 597.3333333333333H597.3333333333334V373.3333333333333H746.6666666666667V746.6666666666665H373.3333333333334V597.3333333333333zM597.3333333333334 1194.6666666666665H373.3333333333334V1045.3333333333333H746.6666666666667V1418.6666666666665H597.3333333333334V1194.6666666666665zM1045.3333333333335 373.3333333333333H1194.6666666666667V597.3333333333333H1418.6666666666667V746.6666666666665H1045.3333333333335V373.3333333333333zM1194.6666666666667 1194.6666666666665V1418.6666666666665H1045.3333333333335V1045.3333333333333H1418.6666666666667V1194.6666666666665H1194.6666666666667z" />
<glyph glyph-name="spinner"
unicode="&#xF10A;"
horiz-adv-x="1792" d=" M701.8666666666668 1008L1057.6533333333334 1624.3733333333334C1005.7600000000002 1635.9466666666667 951.6266666666666 1642.6666666666667 896 1642.6666666666667C716.8000000000001 1642.6666666666667 552.9066666666668 1579.5733333333333 424.1066666666667 1474.2933333333333L697.76 1000.5333333333334L701.8666666666666 1008zM1608.32 1120C1539.6266666666666 1338.4 1373.1200000000001 1512.7466666666667 1160.6933333333332 1593.3866666666668L887.4133333333334 1120H1608.32zM1627.7333333333336 1045.3333333333333H1068.48L1090.1333333333334 1008L1445.92 392C1567.6266666666668 524.9066666666668 1642.6666666666667 701.4933333333333 1642.6666666666667 896C1642.6666666666667 947.1466666666666 1637.44 997.1733333333332 1627.7333333333336 1045.3333333333333zM637.2800000000001 896L346.08 1400C224.3733333333333 1267.0933333333332 149.3333333333334 1090.5066666666667 149.3333333333334 896C149.3333333333334 844.8533333333332 154.56 794.8266666666666 164.2666666666667 746.6666666666665H723.5200000000001L637.2800000000002 896zM183.68 672C252.3733333333334 453.5999999999999 418.88 279.2533333333334 631.3066666666667 198.6133333333332L904.5866666666668 672H183.68zM1025.1733333333334 672L733.9733333333334 167.6266666666666C786.24 156.0533333333333 840.3733333333334 149.3333333333333 896 149.3333333333333C1075.2 149.3333333333333 1239.0933333333332 212.4266666666665 1367.8933333333334 317.7066666666665L1094.24 791.4666666666666L1025.1733333333334 672z" />
<glyph glyph-name="subtitles"
unicode="&#xF10B;"
horiz-adv-x="1792" d=" M1493.3333333333335 1493.3333333333333H298.6666666666667C216.16 1493.3333333333333 149.3333333333334 1426.5066666666667 149.3333333333334 1344V448C149.3333333333334 365.4933333333331 216.16 298.6666666666665 298.6666666666667 298.6666666666665H1493.3333333333335C1575.8400000000001 298.6666666666665 1642.6666666666667 365.4933333333331 1642.6666666666667 448V1344C1642.6666666666667 1426.5066666666667 1575.8400000000001 1493.3333333333333 1493.3333333333335 1493.3333333333333zM298.6666666666667 896H597.3333333333334V746.6666666666665H298.6666666666667V896zM1045.3333333333335 448H298.6666666666667V597.3333333333333H1045.3333333333335V448zM1493.3333333333335 448H1194.6666666666667V597.3333333333333H1493.3333333333335V448zM1493.3333333333335 746.6666666666665H746.6666666666667V896H1493.3333333333335V746.6666666666665z" />
<glyph glyph-name="captions"
unicode="&#xF10C;"
horiz-adv-x="1792" d=" M1418.6666666666667 1493.3333333333333H373.3333333333334C290.8266666666667 1493.3333333333333 224 1426.5066666666667 224 1344V448C224 365.4933333333331 290.8266666666667 298.6666666666665 373.3333333333334 298.6666666666665H1418.6666666666667C1501.1733333333334 298.6666666666665 1568 365.4933333333331 1568 448V1344C1568 1426.5066666666667 1501.1733333333334 1493.3333333333333 1418.6666666666667 1493.3333333333333zM821.3333333333334 970.6666666666666H709.3333333333334V1008H560V783.9999999999999H709.3333333333334V821.3333333333333H821.3333333333334V746.6666666666665C821.3333333333334 705.5999999999999 788.1066666666667 672 746.6666666666667 672H522.6666666666667C481.2266666666667 672 448 705.5999999999999 448 746.6666666666665V1045.3333333333333C448 1086.4 481.2266666666667 1120 522.6666666666667 1120H746.6666666666667C788.1066666666667 1120 821.3333333333334 1086.4 821.3333333333334 1045.3333333333333V970.6666666666666zM1344 970.6666666666666H1232V1008H1082.6666666666667V783.9999999999999H1232V821.3333333333333H1344V746.6666666666665C1344 705.5999999999999 1310.7733333333333 672 1269.3333333333335 672H1045.3333333333335C1003.8933333333334 672 970.6666666666669 705.5999999999999 970.6666666666669 746.6666666666665V1045.3333333333333C970.6666666666669 1086.4 1003.8933333333334 1120 1045.3333333333335 1120H1269.3333333333335C1310.7733333333333 1120 1344 1086.4 1344 1045.3333333333333V970.6666666666666z" />
<glyph glyph-name="hd"
unicode="&#xF10D;"
horiz-adv-x="1792" d=" M1418.6666666666667 1568H373.3333333333334C290.4533333333333 1568 224 1500.8 224 1418.6666666666665V373.3333333333333C224 291.1999999999998 290.4533333333334 224 373.3333333333334 224H1418.6666666666667C1500.8000000000002 224 1568 291.1999999999998 1568 373.3333333333333V1418.6666666666665C1568 1500.8 1500.8000000000002 1568 1418.6666666666667 1568zM821.3333333333334 672H709.3333333333334V821.3333333333333H560V672H448V1120H560V933.3333333333331H709.3333333333334V1120H821.3333333333334V672zM970.6666666666669 1120H1269.3333333333335C1310.4 1120 1344 1086.4 1344 1045.3333333333333V746.6666666666665C1344 705.5999999999999 1310.4 672 1269.3333333333335 672H970.6666666666669V1120zM1082.6666666666667 783.9999999999999H1232V1008H1082.6666666666667V783.9999999999999z" />
<glyph glyph-name="chapters"
unicode="&#xF10E;"
horiz-adv-x="1792" d=" M224 821.3333333333333H373.3333333333334V970.6666666666666H224V821.3333333333333zM224 522.6666666666665H373.3333333333334V672H224V522.6666666666665zM224 1120H373.3333333333334V1269.3333333333333H224V1120zM522.6666666666667 821.3333333333333H1568V970.6666666666666H522.6666666666667V821.3333333333333zM522.6666666666667 522.6666666666665H1568V672H522.6666666666667V522.6666666666665zM522.6666666666667 1269.3333333333333V1120H1568V1269.3333333333333H522.6666666666667z" />
<glyph glyph-name="downloading"
unicode="&#xF10F;"
horiz-adv-x="1792" d=" M815.7183999999999 140Q671.9999999999999 153.0816000000002 547.8591999999999 217.4592Q423.7183999999999 281.8816000000002 332.2815999999999 384.5184Q240.8 487.2 189.4592 618.7775999999999Q138.1184 750.3999999999999 138.1184 897.8815999999999Q138.1184 1192.8 332.2815999999999 1409.3183999999999Q526.4 1625.8816 817.5999999999999 1655.7184V1513.8816Q586.1184 1480.2815999999998 433.0816 1305.7408Q280 1131.2 280 897.8816000000002Q280 664.5184000000002 432.1408 490.0224000000003Q584.2816 315.4816000000001 815.7183999999999 281.8816000000002zM896 518.9184L517.0816 896L610.4 989.3184L830.6816 769.0816V1273.0816H961.3184V769.0816L1179.7184 989.3184L1273.0816 896zM976.2816 140V281.8816000000002Q1058.3999999999999 293.0816000000002 1134.9184 324.8000000000002Q1211.4816 356.5184 1276.8 408.8000000000002L1381.3183999999999 306.1184000000001Q1293.6 235.2000000000001 1190.9183999999998 192.2816000000003Q1088.2815999999998 149.3184000000001 976.2815999999998 140zM1280.5184 1385.0816Q1211.4816 1435.4816 1134.9184 1468.1408000000001Q1058.4 1500.8000000000002 976.2816 1513.8816000000002V1655.7184Q1088.2816 1644.5184 1189.9776 1601.6Q1291.7184 1558.6816 1381.3184 1489.6zM1485.8816 418.1184000000001L1385.0816 518.9184000000002Q1437.3183999999999 586.1184000000001 1468.1408 662.6816000000001Q1498.9183999999998 739.2 1510.1183999999998 821.3184000000001H1653.8816Q1640.8 709.3184000000001 1598.8224 606.6816000000001Q1556.8 504 1485.8816 418.1184000000001zM1510.1183999999998 974.4Q1497.0816 1056.5184 1467.1999999999998 1133.9776000000002Q1437.3183999999999 1211.4816 1385.0816 1276.8000000000002L1491.4816 1375.7184Q1560.5184 1289.8816000000002 1601.6 1187.2Q1642.6816 1084.5184 1653.8816 974.4z" />
<glyph glyph-name="file-download"
unicode="&#xF110;"
horiz-adv-x="1792" d=" M403.2000000000001 278.1333333333335Q352.8000000000001 278.1333333333335 314.5333333333334 315.4666666666667T276.2666666666667 405.0666666666666V692.5333333333333H403.2000000000001V405.0666666666666H1386.9333333333336V692.5333333333333H1513.866666666667V405.0666666666666Q1513.866666666667 352.8 1476.5333333333335 315.4666666666667T1386.9333333333336 278.1333333333335zM896 593.5999999999999L518.9333333333334 968.8L610.4000000000001 1060.2666666666664L832.5333333333334 838.1333333333332V1525.0666666666666H959.4666666666666V838.1333333333333L1181.6 1060.2666666666667L1273.0666666666668 968.8z" />
<glyph glyph-name="file-download-done"
unicode="&#xF111;"
horiz-adv-x="1792" d=" M365.8666666666668 280V408.8H1426.1333333333334V280zM709.3333333333334 617.8666666666666L276.2666666666667 1050.9333333333334L367.7333333333334 1138.6666666666665L709.3333333333334 797.0666666666666L1426.1333333333334 1513.8666666666668L1515.7333333333336 1424.2666666666667z" />
<glyph glyph-name="file-download-off"
unicode="&#xF112;"
horiz-adv-x="1792" d=" M182.9333333333334 1614.6666666666667L1614.6666666666667 182.9333333333332L1530.6666666666667 100.8L1353.3333333333335 278.1333333333335Q1351.466666666667 276.2666666666669 1350.5333333333333 277.2000000000001Q1349.6000000000001 278.1333333333335 1347.7333333333331 278.1333333333335H403.2000000000001Q352.8000000000001 278.1333333333335 314.5333333333334 315.4666666666667T276.2666666666667 405.0666666666666V692.5333333333333H403.2000000000001V405.0666666666666H1226.4L965.0666666666668 666.4000000000001L896 599.2L518.9333333333334 974.4L588 1043.4666666666667L100.8 1530.6666666666665zM1181.6 1065.8666666666668L1273.0666666666668 974.4L1133.0666666666668 832.5333333333333L1041.6000000000001 925.8666666666666zM959.4666666666666 1525.0666666666666V1004.2666666666667L832.5333333333334 1133.0666666666666V1525.0666666666666z" />
<glyph glyph-name="share"
unicode="&#xF113;"
horiz-adv-x="1792" d=" M1344 590.9866666666665C1287.2533333333333 590.9866666666665 1236.1066666666668 568.9599999999998 1197.2800000000002 533.4933333333331L665.2800000000001 843.7333333333333C669.3866666666667 860.5333333333333 672 878.08 672 896S669.3866666666667 931.4666666666666 665.2800000000001 948.2666666666667L1191.68 1255.52C1231.6266666666668 1218.1866666666665 1285.0133333333335 1195.04 1344 1195.04C1467.5733333333335 1195.04 1568 1295.4666666666665 1568 1419.04S1467.5733333333335 1643.04 1344 1643.04S1120 1542.6133333333332 1120 1419.04C1120 1401.12 1122.6133333333335 1383.5733333333333 1126.72 1366.773333333333L600.3199999999999 1059.5199999999998C560.3733333333333 1096.853333333333 506.9866666666666 1119.9999999999998 448 1119.9999999999998C324.4266666666666 1119.9999999999998 224 1019.5733333333332 224 895.9999999999998S324.4266666666666 671.9999999999998 448 671.9999999999998C506.9866666666666 671.9999999999998 560.3733333333333 695.1466666666665 600.3199999999999 732.4799999999998L1132.32 422.2399999999998C1128.5866666666666 406.5599999999997 1126.3466666666666 390.133333333333 1126.3466666666666 373.3333333333331C1126.3466666666666 253.1199999999997 1223.7866666666669 155.6799999999996 1344 155.6799999999996S1561.6533333333334 253.1199999999997 1561.6533333333334 373.3333333333331S1464.2133333333334 590.9866666666662 1344 590.9866666666662z" />
<glyph glyph-name="cog"
unicode="&#xF114;"
horiz-adv-x="1792" d=" M1450.7733333333333 823.1999999999999C1453.76 847.0933333333334 1456 871.3599999999999 1456 896S1453.76 944.9066666666666 1450.7733333333333 968.8L1608.6933333333336 1092.3733333333332C1622.8800000000003 1103.5733333333333 1626.986666666667 1123.7333333333331 1617.6533333333336 1140.1599999999999L1468.3200000000004 1398.8799999999999C1458.986666666667 1414.9333333333334 1439.5733333333335 1421.6533333333332 1422.7733333333338 1414.9333333333334L1236.8533333333337 1339.8933333333332C1198.4000000000003 1369.3866666666668 1156.2133333333338 1394.3999999999999 1110.6666666666672 1413.44L1082.6666666666667 1611.3066666666666C1079.3066666666668 1628.8533333333332 1064 1642.6666666666667 1045.3333333333335 1642.6666666666667H746.6666666666667C728 1642.6666666666667 712.6933333333334 1628.8533333333332 709.7066666666668 1611.3066666666666L681.7066666666668 1413.44C636.1600000000002 1394.4 593.9733333333335 1369.76 555.5200000000001 1339.8933333333332L369.6 1414.9333333333334C352.8000000000001 1421.28 333.3866666666667 1414.9333333333334 324.0533333333334 1398.88L174.72 1140.1599999999999C165.3866666666667 1124.1066666666666 169.4933333333334 1103.9466666666667 183.68 1092.3733333333332L341.2266666666667 968.8C338.2400000000001 944.9066666666666 336 920.64 336 896S338.2400000000001 847.0933333333334 341.2266666666667 823.1999999999999L183.68 699.6266666666668C169.4933333333334 688.4266666666667 165.3866666666667 668.2666666666667 174.72 651.8399999999999L324.0533333333334 393.1199999999999C333.3866666666667 377.0666666666666 352.8 370.3466666666666 369.6 377.0666666666666L555.5200000000001 452.1066666666666C593.9733333333334 422.6133333333333 636.16 397.5999999999999 681.7066666666668 378.56L709.7066666666668 180.6933333333334C712.6933333333334 163.1466666666668 728 149.3333333333333 746.6666666666667 149.3333333333333H1045.3333333333335C1064 149.3333333333333 1079.3066666666668 163.1466666666665 1082.2933333333333 180.6933333333334L1110.2933333333333 378.56C1155.84 397.5999999999999 1198.0266666666666 422.24 1236.48 452.1066666666666L1422.3999999999999 377.0666666666666C1439.2 370.7199999999998 1458.6133333333332 377.0666666666666 1467.9466666666665 393.1199999999999L1617.2799999999997 651.8399999999999C1626.6133333333332 667.8933333333332 1622.5066666666664 688.0533333333333 1608.3199999999997 699.6266666666668L1450.773333333333 823.1999999999999zM896 634.6666666666665C751.52 634.6666666666665 634.6666666666667 751.52 634.6666666666667 896S751.52 1157.3333333333333 896 1157.3333333333333S1157.3333333333335 1040.48 1157.3333333333335 896S1040.48 634.6666666666665 896 634.6666666666665z" />
<glyph glyph-name="square"
unicode="&#xF115;"
horiz-adv-x="1792" d=" M1344 1493.3333333333333H448C365.4933333333334 1493.3333333333333 298.6666666666667 1426.5066666666667 298.6666666666667 1344V448C298.6666666666667 365.4933333333331 365.4933333333334 298.6666666666665 448 298.6666666666665H1344C1426.506666666667 298.6666666666665 1493.3333333333335 365.4933333333331 1493.3333333333335 448V1344C1493.3333333333335 1426.5066666666667 1426.506666666667 1493.3333333333333 1344 1493.3333333333333zM1344 448H448V1344H1344V448z" />
<glyph glyph-name="circle"
unicode="&#xF116;"
horiz-adv-x="1792" d=" M149.3333333333334 896C149.3333333333334 483.6273867930074 483.6273867930075 149.3333333333333 896 149.3333333333333C1308.3726132069926 149.3333333333333 1642.6666666666667 483.6273867930074 1642.6666666666667 896C1642.6666666666667 1308.3726132069926 1308.3726132069926 1642.6666666666667 896 1642.6666666666667C483.6273867930075 1642.6666666666667 149.3333333333334 1308.3726132069926 149.3333333333334 896z" />
<glyph glyph-name="circle-outline"
unicode="&#xF117;"
horiz-adv-x="1792" d=" M896 1642.6666666666667C483.4666666666667 1642.6666666666667 149.3333333333334 1308.5333333333333 149.3333333333334 896S483.4666666666667 149.3333333333333 896 149.3333333333333S1642.6666666666667 483.4666666666667 1642.6666666666667 896S1308.5333333333333 1642.6666666666667 896 1642.6666666666667zM896 298.6666666666665C566.72 298.6666666666665 298.6666666666667 566.7199999999998 298.6666666666667 896S566.72 1493.3333333333333 896 1493.3333333333333S1493.3333333333335 1225.28 1493.3333333333335 896S1225.2800000000002 298.6666666666665 896 298.6666666666665z" />
<glyph glyph-name="circle-inner-circle"
unicode="&#xF118;"
horiz-adv-x="1792" d=" M896 1642.6666666666667C484.2133333333334 1642.6666666666667 149.3333333333334 1307.7866666666666 149.3333333333334 896S484.2133333333334 149.3333333333333 896 149.3333333333333S1642.6666666666667 484.2133333333331 1642.6666666666667 896S1307.7866666666669 1642.6666666666667 896 1642.6666666666667zM896 298.6666666666665C566.72 298.6666666666665 298.6666666666667 566.7199999999998 298.6666666666667 896S566.72 1493.3333333333333 896 1493.3333333333333S1493.3333333333335 1225.28 1493.3333333333335 896S1225.2800000000002 298.6666666666665 896 298.6666666666665zM1120 896C1120 772.4266666666666 1019.5733333333334 672 896 672S672 772.4266666666666 672 896S772.4266666666667 1120 896 1120S1120 1019.5733333333332 1120 896z" />
<glyph glyph-name="cancel"
unicode="&#xF119;"
horiz-adv-x="1792" d=" M896 1642.6666666666667C483.4666666666667 1642.6666666666667 149.3333333333334 1308.5333333333333 149.3333333333334 896S483.4666666666667 149.3333333333333 896 149.3333333333333S1642.6666666666667 483.4666666666667 1642.6666666666667 896S1308.5333333333333 1642.6666666666667 896 1642.6666666666667zM1269.3333333333335 628.3199999999999L1163.68 522.6666666666665L896 790.3466666666667L628.3199999999999 522.6666666666665L522.6666666666667 628.3199999999999L790.3466666666668 896L522.6666666666667 1163.68L628.3199999999999 1269.3333333333333L896 1001.6533333333332L1163.68 1269.3333333333333L1269.3333333333335 1163.68L1001.6533333333334 896L1269.3333333333335 628.3199999999999z" />
<glyph glyph-name="repeat"
unicode="&#xF11A;"
horiz-adv-x="1792" d=" M522.6666666666667 1269.3333333333333H1269.3333333333335V1045.3333333333333L1568 1344L1269.3333333333335 1642.6666666666667V1418.6666666666665H373.3333333333334V970.6666666666666H522.6666666666667V1269.3333333333333zM1269.3333333333335 522.6666666666665H522.6666666666667V746.6666666666665L224 448L522.6666666666667 149.3333333333333V373.3333333333333H1418.6666666666667V821.3333333333333H1269.3333333333335V522.6666666666665z" />
<glyph glyph-name="replay"
unicode="&#xF11B;"
horiz-adv-x="1792" d=" M896 1418.6666666666665V1717.3333333333333L522.6666666666667 1344L896 970.6666666666666V1269.3333333333333C1143.52 1269.3333333333333 1344 1068.8533333333332 1344 821.3333333333333S1143.52 373.3333333333333 896 373.3333333333333S448 573.813333333333 448 821.3333333333333H298.6666666666667C298.6666666666667 491.3066666666664 565.9733333333334 224 896 224S1493.3333333333335 491.3066666666664 1493.3333333333335 821.3333333333333S1226.0266666666669 1418.6666666666665 896 1418.6666666666665z" />
<glyph glyph-name="replay-5"
unicode="&#xF11C;"
horiz-adv-x="1792" d=" M660.3714133333334 1717.3333333333333L335.7084266666667 1392.6703466666665L660.3714133333334 1068.0069866666663L753.2063466666667 1160.7556799999998L591.9532266666668 1322.0088H640.5276266666667C824.5865600000001 1322.0088 979.1965866666668 1257.7249066666666 1104.3565866666668 1129.1780266666667C1229.5169600000002 1000.6311466666668 1292.09696 844.0435733333334 1292.09696 659.3958933333333H1424.6198400000003C1424.6198400000003 769.8312533333333 1403.987946666667 873.2897599999998 1362.7585066666668 969.736693333333C1321.5294400000002 1066.1836266666664 1264.85632 1150.4654933333334 1192.7051733333333 1222.61664C1120.5540266666667 1294.7677866666668 1036.27216 1351.4409066666665 939.8252266666668 1392.6703466666665C843.3782933333333 1433.899413333333 739.9194133333334 1454.5313066666663 629.4840533333335 1454.5313066666663H578.6666666666667L750.9629866666667 1626.8279999999995zM358.7445866666667 908.7385066666668V391.2447466666668H782.7134933333334V204.2809066666669H358.7445866666667V37.3333333333333H832.8405866666668C864.0012266666668 37.3333333333333 890.7352533333335 48.4653866666667 912.9926400000002 70.7227733333334C935.2504000000002 92.9805333333338 946.38208 119.6279466666665 946.38208 150.788586666667V441.2856000000004C946.38208 472.4462400000009 935.2504000000002 499.1802666666667 912.9926400000002 521.4376533333336C890.7352533333335 543.6950400000005 864.0012266666668 554.8270933333338 832.8405866666668 554.8270933333338H525.6921600000001V745.0695466666673H946.38208V908.7385066666671z" />
<glyph glyph-name="replay-10"
unicode="&#xF11D;"
horiz-adv-x="1792" d=" M1579.7522346666667 685.8215466666668C1579.7522346666667 872.3672533333332 1516.5291306666668 1030.5743466666665 1390.0825493333332 1160.4420799999998C1263.635968 1290.3101866666666 1107.4374453333332 1355.2440533333333 921.4866453333332 1355.2440533333333H872.395328L1035.2882399999999 1192.3512533333333L941.5690666666663 1098.6318933333332L613.5519039999998 1426.6496533333334L941.5690666666668 1754.6666666666667L1033.0569013333334 1663.17872L859.0069226666667 1489.1288533333336H910.3295786666667C1021.8998346666668 1489.1288533333336 1126.4041973333335 1468.3024533333335 1223.8426293333337 1426.6496533333334C1321.2807253333335 1384.9964799999998 1406.4460480000002 1327.7234133333332 1479.3390453333336 1254.8308266666668C1552.2316693333335 1181.9382400000004 1609.5045493333337 1096.7726933333336 1651.1573120000003 999.3345600000002C1692.8104480000004 901.896426666667 1713.6369973333335 797.3922133333334 1713.6369973333335 685.8215466666668zM305.4965498666667 74.6666666666665V808.5194133333331H118.5717866666667V978.1359466666667H478.5748426666667V74.6666666666665zM814.3472586666667 74.6666666666665C771.1928 74.6666666666665 734.9617333333334 89.3203733333328 705.654096 118.6285333333331C676.5766186666667 147.7056 662.0380853333335 183.8214933333331 662.0380853333335 226.9754666666668V825.8267733333334C662.0380853333335 868.9814933333333 676.6923146666668 905.2123733333336 705.9999520000001 934.5205333333334C735.0773920000001 963.5976000000002 771.1928000000001 978.135946666667 814.3472586666667 978.135946666667H1101.657648C1144.8117706666667 978.135946666667 1181.0428000000002 963.4822400000002 1210.3508480000003 934.1740800000003C1239.4279146666668 905.0966400000005 1253.9664480000004 868.9814933333339 1253.9664480000004 825.826773333334V226.9754666666677C1253.9664480000004 183.8214933333343 1239.3126293333335 147.5902400000016 1210.004618666667 118.2824533333346C1180.9275146666669 89.2053866666679 1144.811770666667 74.6666666666677 1101.6576480000003 74.6666666666677zM835.1163893333334 247.7451200000001H1080.888144V808.5194133333335H835.1163893333334z" />
<glyph glyph-name="replay-30"
unicode="&#xF11E;"
horiz-adv-x="1792" d=" M972.4166666666669 1754.6666666666667L646.4062453333333 1428.6563199999998L972.4166666666669 1102.645973333333L1065.604176 1195.7605333333331L903.7291573333334 1357.7084266666664H952.5104213333334C1137.3383840000001 1357.7084266666664 1292.5460426666668 1293.1251199999997 1418.2291573333334 1164.0417599999996C1543.9119733333334 1034.9580266666665 1606.7916480000001 877.7630399999995 1606.7916480000001 692.3436799999995H1739.8645973333334C1739.8645973333334 803.2404799999996 1719.1409386666667 907.0670933333328 1677.7395786666668 1003.9164799999994C1636.3382186666668 1100.7662399999992 1579.4214240000001 1185.4330133333326 1506.968736 1257.8854399999993C1434.516384 1330.3378666666663 1349.8497226666668 1387.2547733333327 1253 1428.6563199999991C1156.15024 1470.0578666666659 1052.323552 1490.781226666666 941.427088 1490.781226666666H890.3854026666668L1063.4166666666667 1663.8126399999996zM95.375 988.1666666666666V813.1666666666666H479.791648V617.1666666666665H219.2604176V442.1666666666665H479.7916480000001V249.6666666666665H95.375V74.6666666666665H498.822912C538.4290986666667 74.6666666666665 571.6348213333334 89.4114666666665 598.427088 118.9272000000001C625.2193546666666 148.4425600000004 638.604176 185.1079999999997 638.604176 228.7394666666665V834.1666666666666C638.604176 877.7981333333333 625.2193546666666 914.3907733333332 598.427088 943.906133333333C571.6348213333333 973.4214933333328 538.4290986666667 988.1666666666666 498.822912 988.1666666666666zM934.7187360000001 982.9164799999998C891.8251253333334 982.9164799999998 855.9225546666668 968.3598399999998 827.0208426666667 939.4582399999998C797.8899413333334 910.3274133333332 783.2708426666667 874.3619733333329 783.2708426666667 831.4685866666665V236.2498133333327C783.2708426666667 193.3567999999991 797.7549066666667 157.4540799999991 826.6562453333333 128.5521066666661C855.78752 99.4212799999991 891.8251253333334 84.8019199999999 934.7187360000001 84.8019199999999H1220.2604213333334C1263.1540320000001 84.8019199999999 1299.05664 99.285386666666 1327.9583146666669 128.1873600000004C1357.0892906666668 157.3181866666673 1371.6354026666668 193.3568000000003 1371.6354026666668 236.2498133333338V831.468586666667C1371.6354026666668 874.3619733333334 1357.2242506666669 910.2646933333336 1328.322912 939.1666666666672C1299.1919733333334 968.2974933333336 1263.1540320000001 982.9164800000004 1220.2604213333334 982.9164800000004zM955.354176 814.260533333333H1199.6979306666667V256.8854399999994H955.354176z" />
<glyph glyph-name="forward-5"
unicode="&#xF11F;"
horiz-adv-x="1792" d=" M1101.6480533333333 1754.6666666666667L1010.856 1663.9608533333333L1183.5338666666667 1491.2829866666668H1132.6037333333334C1021.92384 1491.2829866666668 918.23648 1470.6055466666667 821.576 1429.2850133333336C724.91552 1387.96448 640.4469866666666 1331.1659200000004 568.1360533333333 1258.8553600000005C495.8254933333333 1186.5444266666675 439.0269333333333 1102.075893333334 397.7064 1005.4154133333342C356.3858666666667 908.7553066666674 335.7084266666667 805.067573333334 335.7084266666667 694.3876800000012H468.5243733333334C468.5243733333334 879.4441600000009 531.24288 1036.3785600000012 656.6802666666666 1165.2095466666678C782.1172799999999 1294.0409066666678 937.06928 1358.4670400000014 1121.5358933333334 1358.4670400000014H1170.2178133333334L1008.6940266666666 1196.857386666668L1101.6480533333333 1103.9033600000014L1427.0297066666665 1429.2850133333347zM736.4041066666667 947.9138666666668V429.3613333333338H1161.3112V241.9834666666673H736.4041066666667V74.6666666666665H1211.5495466666666C1242.7792533333331 74.6666666666665 1269.4856533333332 85.8233600000003 1291.7926933333333 108.1300266666669C1314.0993599999997 130.4370666666669 1325.2560533333333 157.1434666666669 1325.2560533333333 188.3728000000003V479.5130666666664C1325.2560533333333 510.7427733333334 1314.09936 537.5357866666666 1291.7926933333333 559.8424533333332C1269.4856533333332 582.1491199999996 1242.7792533333331 593.3058133333334 1211.5495466666666 593.3058133333334H903.72128V783.969386666667H1325.2560533333333V947.9138666666668z" />
<glyph glyph-name="forward-10"
unicode="&#xF120;"
horiz-adv-x="1792" d=" M863.1064586666666 1754.6666666666667L774.038048 1665.6830400000001L943.437712 1496.2834133333333H893.4745866666667C784.8960373333334 1496.2834133333333 683.1768906666667 1475.9983466666665 588.3516426666667 1435.46256C493.5263573333334 1394.9263999999998 410.6614773333334 1339.2064 339.7235146666668 1268.2682133333333C268.7855146666667 1197.3303999999998 213.065328 1114.465333333333 172.5293546666667 1019.64016C131.9933813333334 924.814986666667 111.7083520000001 823.0958400000002 111.7083520000001 714.5170666666668H242.0027306666668C242.0027306666668 896.0604800000001 303.5307146666667 1050.0153066666667 426.5864213333334 1176.400586666667C549.6420906666668 1302.7858666666666 701.6524853333334 1365.9889600000004 882.6167093333335 1365.9889600000004H930.3743306666668L771.9173653333336 1207.4473600000001L863.1064586666668 1116.25808L1182.3107146666669 1435.4625600000004zM507.681104 953.8991466666668V788.8257066666666H689.5503253333334V74.6666666666665H858.0168426666667V953.8991466666668zM1184.7706826666667 953.8991466666668C1142.7737066666666 953.8991466666668 1107.6280693333333 939.7830399999998 1079.3306346666666 911.4854933333332C1050.80864 882.963573333333 1036.4929866666666 847.7033599999999 1036.4929866666666 805.7063466666664V222.8594666666663C1036.4929866666666 180.862453333333 1050.6939146666666 145.7172266666669 1078.9913493333333 117.4196800000002C1107.5133813333332 88.8977600000001 1142.7737066666666 74.6666666666665 1184.7706826666667 74.6666666666665H1464.3608C1506.3578133333333 74.6666666666665 1541.5034133333331 88.7827733333329 1569.8005866666667 117.0803199999996C1598.32288 145.6022399999997 1612.5536 180.862453333333 1612.5536 222.8594666666663V805.7063466666664C1612.5536 847.7033599999999 1598.4374933333334 882.8489599999999 1570.1399466666667 911.1465066666666C1541.6180266666668 939.6684266666668 1506.3578133333333 953.8991466666668 1464.3608 953.8991466666668zM1204.9595413333332 788.8257066666666H1444.17168V243.1333333333328H1204.9595413333332z" />
<glyph glyph-name="forward-30"
unicode="&#xF121;"
horiz-adv-x="1792" d=" M953.8155573333333 1754.6666666666667L862.8455360000002 1663.7831466666664L1035.861904 1490.7670399999997H984.8320533333334C873.935328 1490.7670399999997 770.044464 1470.0489066666662 673.1947040000001 1428.6473599999995C576.3449066666667 1387.245813333333 491.7108000000001 1330.3359999999993 419.2583360000001 1257.883573333333C346.8057973333335 1185.4311466666663 289.8959840000001 1100.7972266666661 248.4945493333334 1003.9470933333334C207.0931146666668 907.0973333333334 186.3750186666668 803.2065066666665 186.3750186666668 692.31008H319.4511786666668C319.4511786666668 877.729066666667 382.2928106666668 1034.97072 507.9757760000002 1164.0544533333334C633.6587040000002 1293.1381866666666 788.9145226666668 1357.69088 973.7423733333334 1357.69088H1022.5196426666668L860.6795680000001 1195.7638933333335L953.8155573333333 1102.6280533333336L1279.834864 1428.6473600000002zM522.53096 988.1789866666668V813.1700266666666H906.9443413333335V617.1946666666665H646.4234933333333V442.1857066666662H906.9443413333335V249.6756266666662H522.53096V74.6666666666665H926.0047253333335C965.6108746666667 74.6666666666665 998.759552 89.4234133333337 1025.5519306666667 118.9387733333329C1052.3443093333335 148.4541333333332 1065.7520533333336 185.0777599999997 1065.7520533333336 228.7092266666664V834.1364266666666C1065.7520533333336 877.7678933333333 1052.3443093333335 914.3915200000002 1025.5519306666667 943.90688C998.7595520000002 973.4222399999998 965.6108746666667 988.1789866666668 926.0047253333335 988.1789866666668zM1313.017290666667 981.9413333333335C1270.1236426666667 981.9413333333335 1234.2276800000002 967.4369600000005 1205.3260800000003 938.53536C1176.1951040000001 909.4045333333336 1161.5738400000002 873.3913066666669 1161.5738400000002 830.4975466666665V235.2937066666659C1161.5738400000002 192.3999466666655 1176.0779146666669 156.5043199999991 1204.9795146666668 127.6027199999994C1234.1104906666667 98.4718933333325 1270.1236426666667 83.9369066666657 1313.017290666667 83.9369066666657H1598.5763733333335C1641.4701333333337 83.9369066666657 1677.3661333333334 98.3546666666657 1706.2677333333338 127.2558933333319C1735.3985600000005 156.3870933333324 1749.9331733333338 192.3999466666655 1749.9331733333338 235.293706666665V830.4975466666649C1749.9331733333338 873.3913066666647 1735.5157866666668 909.2873066666648 1706.614186666667 938.188906666665C1677.4833600000002 967.3197333333314 1641.4701333333335 981.941333333332 1598.5763733333335 981.941333333332zM1333.6371253333336 813.3432533333336H1577.8701866666668V255.913653333334H1333.6371253333336z" />
<glyph glyph-name="audio"
unicode="&#xF122;"
horiz-adv-x="1792" d=" M896 1717.3333333333333C524.9066666666668 1717.3333333333333 224 1416.4266666666667 224 1045.3333333333333V522.6666666666665C224 399.0933333333333 324.4266666666667 298.6666666666665 448 298.6666666666665H672V896H373.3333333333334V1045.3333333333333C373.3333333333334 1333.92 607.4133333333334 1568 896 1568S1418.6666666666667 1333.92 1418.6666666666667 1045.3333333333333V896H1120V298.6666666666665H1344C1467.5733333333335 298.6666666666665 1568 399.0933333333333 1568 522.6666666666665V1045.3333333333333C1568 1416.4266666666667 1267.0933333333332 1717.3333333333333 896 1717.3333333333333z" />
<glyph glyph-name="next-item"
unicode="&#xF123;"
horiz-adv-x="1792" d=" M448 448L1082.6666666666667 896L448 1344V448zM1194.6666666666667 1344V448H1344V1344H1194.6666666666667z" />
<glyph glyph-name="previous-item"
unicode="&#xF124;"
horiz-adv-x="1792" d=" M448 1344H597.3333333333334V448H448zM709.3333333333334 896L1344 448V1344z" />
<glyph glyph-name="shuffle"
unicode="&#xF125;"
horiz-adv-x="1792" d=" M790.3466666666668 1107.3066666666666L404.3200000000001 1493.3333333333333L298.6666666666667 1387.6799999999998L684.6933333333334 1001.6533333333332L790.3466666666668 1107.3066666666664zM1082.6666666666667 1493.3333333333333L1235.3600000000001 1340.6399999999999L298.6666666666667 404.32L404.3200000000001 298.6666666666665L1341.0133333333335 1235.3600000000001L1493.3333333333335 1082.6666666666665V1493.3333333333333H1082.6666666666667zM1107.3066666666668 790.3466666666667L1001.6533333333334 684.6933333333334L1235.36 450.9866666666667L1082.6666666666667 298.6666666666665H1493.3333333333335V709.3333333333333L1340.6399999999999 556.6399999999999L1107.3066666666666 790.3466666666664z" />
<glyph glyph-name="cast"
unicode="&#xF126;"
horiz-adv-x="1792" d=" M1568 1568H224C141.4933333333334 1568 74.6666666666667 1501.1733333333332 74.6666666666667 1418.6666666666665V1194.6666666666665H224V1418.6666666666665H1568V373.3333333333333H1045.3333333333335V224H1568C1650.506666666667 224 1717.3333333333335 290.8266666666666 1717.3333333333335 373.3333333333333V1418.6666666666665C1717.3333333333335 1501.1733333333332 1650.506666666667 1568 1568 1568zM74.6666666666667 448V224H298.6666666666667C298.6666666666667 347.5733333333333 198.2400000000001 448 74.6666666666667 448zM74.6666666666667 746.6666666666665V597.3333333333333C280.7466666666667 597.3333333333333 448 430.0799999999997 448 224H597.3333333333334C597.3333333333334 512.5866666666668 363.2533333333334 746.6666666666665 74.6666666666667 746.6666666666665zM74.6666666666667 1045.3333333333333V896C445.76 896 746.6666666666667 595.0933333333332 746.6666666666667 224H896C896 677.5999999999999 528.2666666666668 1045.3333333333333 74.6666666666667 1045.3333333333333z" />
<glyph glyph-name="picture-in-picture-enter"
unicode="&#xF127;"
horiz-adv-x="1792" d=" M1418.6666666666667 970.6666666666666H821.3333333333334V523.0399999999997H1418.6666666666667V970.6666666666666zM1717.3333333333335 373.3333333333333V1420.1599999999999C1717.3333333333335 1502.2933333333333 1650.1333333333334 1568 1568 1568H224C141.8666666666667 1568 74.6666666666667 1502.2933333333333 74.6666666666667 1420.1599999999999V373.3333333333333C74.6666666666667 291.1999999999998 141.8666666666667 224 224 224H1568C1650.1333333333334 224 1717.3333333333335 291.1999999999998 1717.3333333333335 373.3333333333333zM1568 371.8399999999999H224V1420.9066666666668H1568V371.8399999999999z" />
<glyph glyph-name="picture-in-picture-exit"
unicode="&#xF128;"
horiz-adv-x="2190.222222222222" d=" M1792 1393.7777777777778H398.2222222222223V398.2222222222222H1792V1393.7777777777778zM2190.222222222222 199.1111111111111V1594.88C2190.222222222222 1704.391111111111 2100.6222222222223 1792 1991.1111111111113 1792H199.1111111111111C89.6 1792 0 1704.391111111111 0 1594.88V199.1111111111111C0 89.5999999999999 89.6 0 199.1111111111111 0H1991.1111111111113C2100.6222222222223 0 2190.222222222222 89.5999999999999 2190.222222222222 199.1111111111111zM1991.1111111111113 197.1200000000001H199.1111111111111V1595.8755555555556H1991.1111111111113V197.1200000000001z" />
<glyph glyph-name="facebook"
unicode="&#xF129;"
horiz-adv-x="1792" d=" M1343 1780V1516H1186Q1100 1516 1070 1480T1040 1372V1183H1333L1294 887H1040V128H734V887H479V1183H734V1401Q734 1587 838 1689.5T1115 1792Q1262 1792 1343 1780z" />
<glyph glyph-name="linkedin"
unicode="&#xF12A;"
horiz-adv-x="1792" d=" M477 1167V176H147V1167H477zM498 1473Q499 1400 447.5 1351T312 1302H310Q228 1302 178 1351T128 1473Q128 1547 179.5 1595.5T314 1644T447 1595.5T498 1473zM1664 744V176H1335V706Q1335 811 1294.5 870.5T1168 930Q1105 930 1062.5 895.5T999 810Q988 780 988 729V176H659Q661 575 661 823T660 1119L659 1167H988V1023H986Q1006 1055 1027 1079T1083.5 1131T1170.5 1174.5T1285 1190Q1456 1190 1560 1076.5T1664 744z" />
<glyph glyph-name="twitter"
unicode="&#xF12B;"
horiz-adv-x="1792" d=" M1684 1384Q1617 1286 1522 1217Q1523 1203 1523 1175Q1523 1045 1485 915.5T1369.5 667T1185 456.5T927 310.5T604 256Q333 256 108 401Q143 397 186 397Q411 397 587 535Q482 537 399 599.5T285 759Q318 754 346 754Q389 754 431 765Q319 788 245.5 876.5T172 1082V1086Q240 1048 318 1045Q252 1089 213 1160T174 1314Q174 1402 218 1477Q339 1328 512.5 1238.5T884 1139Q876 1177 876 1213Q876 1347 970.5 1441.5T1199 1536Q1339 1536 1435 1434Q1544 1455 1640 1512Q1603 1397 1498 1334Q1591 1344 1684 1384z" />
<glyph glyph-name="tumblr"
unicode="&#xF12C;"
horiz-adv-x="1792" d=" M1328 463L1408 226Q1385 191 1297 160T1120 128Q1016 126 929.5 154T787 228T692 334T636.5 454T620 572V1116H452V1331Q524 1357 581 1400.5T672 1490.5T730 1592.5T764 1691.5T779 1780Q780 1785 783.5 1788.5T791 1792H1035V1368H1368V1116H1034V598Q1034 568 1040.5 542T1063 489.5T1112.5 448T1194 434Q1272 436 1328 463z" />
<glyph glyph-name="pinterest"
unicode="&#xF12D;"
horiz-adv-x="1792" d=" M1664 896Q1664 687 1561 510.5T1281.5 231T896 128Q785 128 678 160Q737 253 756 324Q765 358 810 535Q830 496 883 467.5T997 439Q1118 439 1213 507.5T1360 696T1412 966Q1412 1080 1352.5 1180T1180 1343T925 1406Q820 1406 729 1377T574.5 1300T465.5 1189.5T398.5 1060T377 926Q377 822 417 743T534 632Q564 620 572 652Q574 659 580 683T588 713Q594 736 577 756Q526 817 526 907Q526 1058 630.5 1166.5T904 1275Q1055 1275 1139.5 1193T1224 980Q1224 810 1155.5 691T980 572Q919 572 882 615.5T859 720Q867 755 885.5 813.5T915.5 916.5T927 992Q927 1042 900 1075T823 1108Q761 1108 718 1051T675 909Q675 836 700 787L601 369Q584 299 588 192Q382 283 255 473T128 896Q128 1105 231 1281.5T510.5 1561T896 1664T1281.5 1561T1561 1281.5T1664 896z" />
<glyph glyph-name="audio-description"
unicode="&#xF12E;"
horiz-adv-x="1792" d=" M795.5138904615 457.270933L795.5138904615 1221.5248286325C971.84576475 1225.085121904 1107.39330415 1232.12360523 1207.223857 1161.5835220499998C1303.033991 1093.8857027 1377.7922305 962.20560625 1364.3373135 792.9476205000001C1350.102593 613.9029365000001 1219.6655764999998 463.4600215 1050.12389545 448.2843645000001C965.8259268 440.7398275000001 798.21890505 448.2843645000001 798.21890505 448.2843645000001C798.21890505 448.2843645000001 795.2791410655 453.016494 795.5138904615 457.270933M966.1564647 649.0863960000001C1076.16084135 644.6767075 1152.385591 707.3020429999999 1163.8910079999998 807.9351875C1179.2994744999999 942.71878505 1089.73043585 1030.3691748 960.74508635 1020.7227954L960.74508635 658.08043C960.6196169500002 652.9482330000001 962.7606933 650.3134680000001 966.1564647 649.0863960000001 M1343.2299685 457.3517725000002C1389.9059734 444.3690160000001 1404.0840274999998 496.0596970000001 1424.48294065 532.2791494999999C1469.0084255 611.2788500000001 1502.5101322 712.8584189999999 1503.0416912 828.9881705C1503.8147453000001 995.5680973 1438.8404296 1117.7973688000002 1378.4383305 1200.62456881045L1348.652139905 1200.62456881045C1346.6001063899998 1187.06858424 1356.44474056 1175.024791325 1362.18395859 1164.6588891000001C1408.2649952 1081.49431985 1450.96645015 966.7230041 1451.57490975 834.9817034999999C1452.27106325 683.8655425000002 1402.00636065 557.5072264999999 1343.2299685 457.3517725000002 M1488.0379675 457.3517725000002C1534.7139723999999 444.3690160000001 1548.8825828 496.0671625 1569.29093965 532.2791494999999C1613.8164245 611.2788500000001 1647.3113856500001 712.8584189999999 1647.8496902000002 828.9881705C1648.6227442999998 995.5680973 1583.6484286 1117.7973688000002 1523.2463295 1200.62456881045L1493.460138905 1200.62456881045C1491.40810539 1187.06858424 1501.250041305 1175.021805755 1506.9919575899999 1164.6588891000001C1553.0729942 1081.49431985 1595.7757984 966.7230041 1596.3829087499998 834.9817034999999C1597.07906225 683.8655425000002 1546.8143596500001 557.5072264999999 1488.0379675 457.3517725000002 M1631.9130380000001 457.3517725000002C1678.5890429 444.3690160000001 1692.7576533 496.0671625 1713.1660101500001 532.2791494999999C1757.691495 611.2788500000001 1791.1864561500001 712.8584189999999 1791.7247607000002 828.9881705C1792.4978148 995.5680973 1727.5234991000002 1117.7973688000002 1667.1214 1200.62456881045L1637.3352094050001 1200.62456881045C1635.28317589 1187.06858424 1645.1251118050002 1175.02329854 1650.86702809 1164.6588891000001C1696.9480647 1081.49431985 1739.64951965 966.7230041 1740.25797925 834.9817034999999C1740.95413275 683.8655425000002 1690.6894301500001 557.5072264999999 1631.9130380000001 457.3517725000002 M15.66796875 451.481947L254.03034755 451.481947L319.0356932 551.1747990000001L543.6261075 551.6487970000001C543.6261075 551.6487970000001 543.8541115 483.7032095 543.8541115 451.481947L714.4993835 451.481947L714.4993835 1230.9210795L508.643051 1230.9210795C488.8579955 1197.5411595 15.66796875 451.481947 15.66796875 451.481947L15.66796875 451.481947zM550.0048155000001 959.9708615L550.0048155000001 710.916297L408.4199 711.8642895L550.0048155000001 959.9708615L550.0048155000001 959.9708615z" />
</font>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.
Binary file not shown.
@@ -0,0 +1,41 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Strings for plugin 'media_videojs'
*
* @package media_videojs
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$string['audiocssclass'] = 'CSS class for audio';
$string['audioextensions'] = 'Audio file extensions';
$string['configaudiocssclass'] = 'A CSS class that will be added to the &lt;audio&gt; element.';
$string['configaudioextensions'] = 'A comma-separated list of supported audio file extensions. VideoJS will try to use the browser\'s native video player when available or native VideoJS functionality.';
$string['configlimitsize'] = 'If enabled, and width and height are not specified, the video will display with default width and height. Otherwise it will stretch to the maximum possible width.';
$string['configvideocssclass'] = 'A CSS class that will be added to the &lt;video&gt; element. For example, the CSS class "vjs-big-play-centered" will place the play button in the middle. For details, including how to set a custom skin, see docs.videojs.com.';
$string['configvideoextensions'] = 'A comma-separated list of supported video file extensions. VideoJS will try to use the browser\'s native video player when available.';
$string['configyoutube'] = 'Use VideoJS to play YouTube videos. Note that YouTube playlists are not yet supported by VideoJS.';
$string['limitsize'] = 'Limit size';
$string['pluginname'] = 'VideoJS player';
$string['pluginname_help'] = 'A JavaScript wrapper for video files played by the browser\'s native video player. (Format support depends on the browser.)';
$string['privacy:metadata'] = 'The VideoJS player media plugin does not store any personal data.';
$string['videoextensions'] = 'Video file extensions';
$string['videocssclass'] = 'CSS class for video';
$string['youtube'] = 'YouTube videos';
+21
View File
@@ -0,0 +1,21 @@
ogv.js wrapper and player code
Copyright (c) 2013-2019 Brion Vibber and other contributors
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.
@@ -0,0 +1,23 @@
Copyright © 2018-2019, VideoLAN and dav1d authors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,28 @@
Copyright (c) 2002, Xiph.org Foundation
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,44 @@
Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic,
Jean-Marc Valin, Timothy B. Terriberry,
CSIRO, Gregory Maxwell, Mark Borgerding,
Erik de Castro Lopo
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of Internet Society, IETF or IETF Trust, nor the
names of specific contributors, may be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Opus is subject to the royalty-free patent licenses which are
specified at:
Xiph.Org Foundation:
https://datatracker.ietf.org/ipr/1524/
Microsoft Corporation:
https://datatracker.ietf.org/ipr/1914/
Broadcom Corporation:
https://datatracker.ietf.org/ipr/1526/
@@ -0,0 +1,28 @@
Copyright (C) 2002-2009 Xiph.org Foundation
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,28 @@
Copyright (c) 2002-2018 Xiph.org Foundation
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,13 @@
Copyright © 2010 Mozilla Foundation
Permission to use, copy, modify, and 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.
@@ -0,0 +1,31 @@
Copyright (c) 2010, The WebM Project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Google, nor the WebM Project, nor the names
of its contributors may be used to endorse or promote products
derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,23 @@
Additional IP Rights Grant (Patents)
------------------------------------
"These implementations" means the copyrightable works that implement the WebM
codecs distributed by Google as part of the WebM Project.
Google hereby grants to you a perpetual, worldwide, non-exclusive, no-charge,
royalty-free, irrevocable (except as stated in this section) patent license to
make, have made, use, offer to sell, sell, import, transfer, and otherwise
run, modify and propagate the contents of these implementations of WebM, where
such license applies only to those patent claims, both currently owned by
Google and acquired in the future, licensable by Google that are necessarily
infringed by these implementations of WebM. This grant does not include claims
that would be infringed only as a consequence of further modification of these
implementations. If you or your agent or exclusive licensee institute or order
or agree to the institution of patent litigation or any other patent
enforcement activity against any entity (including a cross-claim or
counterclaim in a lawsuit) alleging that any of these implementations of WebM
or any code incorporated within any of these implementations of WebM
constitute direct or contributory patent infringement, or inducement of
patent infringement, then any patent rights granted to you under this License
for these implementations of WebM shall terminate as of the date such
litigation is filed.
+404
View File
@@ -0,0 +1,404 @@
ogv.js
======
Media decoder and player for Ogg Vorbis/Opus/Theora and WebM VP8/VP9/AV1 video.
Based around libogg, libvorbis, libtheora, libopus, libvpx, libnestegg and dav1d compiled to JavaScript and WebAssembly with Emscripten.
## Updates
1.8.9 - 2022-04-06
* Bump yuv-canvas to 1.2.11, further perf improvments for frame drawing
* Workaround gets audio working when ringer is disabled by iOS hardware switch
1.8.8 - 2022-04-04
* Bump yuv-canvas to 1.2.10, fixes WebGL scaling bug in Netscape/macOS; adjustment to prior performance tweaks.
1.8.7 - 2022-03-29
* Bump emscripten compatibility to 3.1.8
* Bump Opus to 1.3.1
* Bump yuv-canvas to 1.2.9, fixes WebGL performance regressions on some browsers
* experimental demo/threaded.php provides a COOP-COEP-CORP environment for testing threaded decoders (top-level frame and all worker JS must opt in to COOP-COEP; CORP or CORS required for most loaded resources)
1.8.6 - 2022-01-12
* Bump to yuv-canvas
* Fix demo for removal of video-canvas mode
1.8.5 - 2022-01-11
* Remove unnecessary user-agent checks
* Remove flaky, obsolete support for faking CSS `object-fit`
* Remove experimental support for streaming `<canvas>` into `<video>`
1.8.4 - 2021-07-02
* Fix for fix for OGVLoader.base fix
1.8.3 - 2021-07-02
* Fixes for build with emscripten 2.0.25
* Fix for nextTick/setImmediate-style polyfill in front-end
* Provisional fix for OGVLoader.base not working with CDNs
* the fallback code for loading a non-local worker had been broken with WebAssembly for some time, sorry!
1.8.2 - errored out
1.8.1 - 2021-02-18
* Fixed OGVCompat APIs to correctly return false without WebAssembly and Web Audio
1.8.0 - 2021-02-09
* Dropping IE support and Flash audio backend
* Updated to stream-file 0.3.0
* Updated to audio-feeder 0.5.0
* The old IE 10/11 support _no longer works_ due to the Flash plugin being disabled, and so is being removed
* Drop es6-promise shim
* Now requires WebAssembly, which requires native Promise support
* Build & fixes
* Demo fixed (removed test files that are now offline)
* Builds with emscripten 2.0.13
* Requires latest meson from git pending a fix hitting release
1.7.0 - 2020-09-28
* Builds with emscripten's LLVM upstream backend
* Updated to build with emscripten 2.0.4
* Reduced amount of memory used between GC runs by reusing frame buffers
* Removed `memoryLimit` option
* JS, Wasm, and threaded Wasm builds now all use dynamic memory growth
* Updated dav1d
* Updated libvpx to 1.8.1
* Experimental SIMD builds of AV1 decoder optional, with `make SIMD=1`
* These work in Chrome with the "WebAssembly SIMD" flag enabled in chrome://flags/
* Significant speed boost when available.
* Available with and without multithreading.
* Must enable explicitly with `simd: true` in `options`.
* Experimental SIMD work for VP9 as well, incomplete.
1.6.1 - 2019-06-18
* playbackSpeed attribute now supported
* updated audio-feeder to 0.4.21;
* mono audio is now less loud, matching native playback better
* audio resampling now uses linear interpolation for upscaling
* fix for IE in bundling scenarios that use strict mode
* tempo change support thanks to a great patch from velochy!
* updated yuv-canvas to 1.2.6;
* fixes for capturing WebGL canvas as MediaStream
* fixes for seeks on low frame rate video
* updated emscripten toolchain to 1.38.36
* drop OUTLINING_LIMIT from AV1 JS build; doesn't work in newer emscripten and not really needed
1.6.0 - 2019-02-26
* experimental support for AV1 video in WebM
* update buildchain to emscripten 1.38.28
* fix a stray global
* starting to move to ES6 classes and modules
* building with babel for ES5/IE11 compat
* updated eslint
* updated yuv-canvas to 1.2.4; fixes for software GL rendering
* updated audio-feeder to 0.4.15; fixes for resampling and Flash perf
* retooled buffer copies
* sync fix for audio packets with discard padding
* clients can pass a custom `StreamFile` instance as `{stream:foo}` in options. This can be useful for custom streaming until MSE interfaces are ready.
* refactored WebM keyframe detection
* prefill the frame pipeline as well as the audio pipeline before starting audio
* removed BINARYEN_IGNORE_IMPLICIT_TRAPS=1 option which can cause intermittent breakages
* changed download streaming method to avoid data corruption problem on certain files
* fix for seek on very short WebM files
* fix for replay-after-end-of-playback in WebM
See more details and history in [CHANGES.md](https://github.com/brion/ogv.js/blob/master/CHANGES.md)
## Current status
Note that as of 2021 ogv.js works pretty nicely but may still have some packagine oddities with tools like webpack. It should work via CDNs again as of 1.8.2 if you can't or don't want to package locally, but this is not documented well yet. Improved documentation will come with the next major update & code cleanup!
Since August 2015, ogv.js can be seen in action [on Wikipedia and Wikimedia Commons](https://commons.wikimedia.org/wiki/Commons:Video) in Safari and IE/Edge where native Ogg and WebM playback is not available. (See [technical details on MediaWiki integration](https://www.mediawiki.org/wiki/Extension:TimedMediaHandler/ogv.js).)
See also a standalone demo with performance metrics at https://brionv.com/misc/ogv.js/demo/
* streaming: yes (with Range header)
* seeking: yes for Ogg and WebM (with Range header)
* color: yes
* audio: yes, with a/v sync (requires Web Audio or Flash)
* background threading: yes (video, audio decoders in Workers)
* [GPU accelerated drawing: yes (WebGL)](https://github.com/brion/ogv.js/wiki/GPU-acceleration)
* GPU accelerated decoding: no
* SIMD acceleration: no
* Web Assembly: yes (with asm.js fallback)
* multithreaded VP8, VP9, AV1: in development (set `options.threading` to `true`; requires flags to be enabled in Firefox 65 and Chrome 72, no support yet in Safari)
* controls: no (currently provided by demo or other UI harness)
Ogg and WebM files are fairly well supported.
## Goals
Long-form goal is to create a drop-in replacement for the HTML5 video and audio tags which can be used for basic playback of Ogg Theora and Vorbis or WebM media on browsers that don't support Ogg or WebM natively.
The API isn't quite complete, but works pretty well.
## Compatibility
ogv.js requires a fast JS engine with typed arrays, and Web Audio for audio playback.
The primary target browsers are (testing 360p/30fps and up):
* Safari 6.1-12 on Mac OS X 10.7-10.14
* Safari on iOS 10-11 64-bit
Older versions of Safari have flaky JIT compilers. IE 9 and below lack typed arrays, and IE 10/11 no longer support an audio channel since the Flash plugin was sunset.
(Note that Windows and Mac OS X can support Ogg and WebM by installing codecs or alternate browsers with built-in support, but this is not possible on iOS where all browsers are really Safari.)
Testing browsers (these support .ogv and .webm natively):
* Firefox 65
* Chrome 73
## Package installation
Pre-built releases of ogv.js are available as [.zip downloads from the GitHub releases page](https://github.com/brion/ogv.js/releases) and through the npm package manager.
You can load the `ogv.js` main entry point directly in a script tag, or bundle it through whatever build process you like. The other .js files must be made available for runtime loading, together in the same directory.
ogv.js will try to auto-detect the path to its resources based on the script element that loads ogv.js or ogv-support.js. If you load ogv.js through another bundler (such as browserify or MediaWiki's ResourceLoader) you may need to override this manually before instantiating players:
```
// Path to ogv-demuxer-ogg.js, ogv-worker-audio.js, etc
OGVLoader.base = '/path/to/resources';
```
To fetch from npm:
```
npm install ogv
```
The distribution-ready files will appear in 'node_modules/ogv/dist'.
To load the player library into your browserify or webpack project:
```
var ogv = require('ogv');
// Access public classes either as ogv.OGVPlayer or just OGVPlayer.
// Your build/lint tools may be happier with ogv.OGVPlayer!
ogv.OGVLoader.base = '/path/to/resources';
var player = new ogv.OGVPlayer();
```
## Usage
The `OGVPlayer` class implements a player, and supports a subset of the events, properties and methods from [HTMLMediaElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement) and [HTMLVideoElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement).
```
// Create a new player with the constructor
var player = new OGVPlayer();
// Or with options
var player = new OGVPlayer({
debug: true,
debugFilter: /demuxer/
});
// Now treat it just like a video or audio element
containerElement.appendChild(player);
player.src = 'path/to/media.ogv';
player.play();
player.addEventListener('ended', function() {
// ta-da!
});
```
To check for compatibility before creating a player, include `ogv-support.js` and use the `OGVCompat` API:
```
if (OGVCompat.supported('OGVPlayer')) {
// go load the full player from ogv.js and instantiate stuff
}
```
This will check for typed arrays, web audio, blacklisted iOS versions, and super-slow/broken JIT compilers.
If you need a URL versioning/cache-buster parameter for dynamic loading of `ogv.js`, you can use the `OGVVersion` symbol provided by `ogv-support.js` or the even tinier `ogv-version.js`:
```
var script = document.createElement('script');
script.src = 'ogv.js?version=' + encodeURIComponent(OGVVersion);
document.querySelector('head').appendChild(script);
```
## Distribution notes
Entry points:
* `ogv.js` contains the main runtime classes, including OGVPlayer, OGVLoader, and OGVCompat.
* `ogv-support.js` contains the OGVCompat class and OGVVersion symbol, useful for checking for runtime support before loading the main `ogv.js`.
* `ogv-version.js` contains only the OGVVersion symbol.
These entry points may be loaded directly from a script element, or concatenated into a larger project, or otherwise loaded as you like.
Further code modules are loaded at runtime, which must be available with their defined names together in a directory. If the files are not hosted same-origin to the web page that includes them, you will need to set up appropriate CORS headers to allow loading of the worker JS modules.
Dynamically loaded assets:
* `ogv-worker-audio.js`, `ogv-worker-video.js`, and `*.worker.js` are Worker entry points, used to run video and audio decoders in the background.
* `ogv-demuxer-ogg-wasm.js/.wasm` are used in playing .ogg, .oga, and .ogv files.
* `ogv-demuxer-webm-wasm.js/.wasm` are used in playing .webm files.
* `ogv-decoder-audio-vorbis-wasm.js/.wasm` and `ogv-decoder-audio-opus-wasm.js/.wasm` are used in playing both Ogg and WebM files containing audio.
* `ogv-decoder-video-theora-wasm.js/.wasm` are used in playing .ogg and .ogv video files.
* `ogv-decoder-video-vp8-wasm.js/.wasm` and `ogv-decoder-video-vp9-wasm.js/.wasm` are used in playing .webm video files.
* `*-mt.js/.wasm` are the multithreaded versions of some of the above modules. They have additional support files.
If you know you will never use particular formats or codecs you can skip bundling them; for instance if you only need to play Ogg files you don't need `ogv-demuxer-webm-wasm.js` or `ogv-decoder-video-vp8-wasm.js` which are only used for WebM.
## Performance
(This section is somewhat out of date.)
As of 2015, for SD-or-less resolution basic Ogg Theora decoding speed is reliable on desktop and newer high-end mobile devices; current high-end desktops and laptops can even reach HD resolutions. Older and low-end mobile devices may have difficulty on any but audio and the lowest-resolution video files.
WebM VP8/VP9 is slower, but works pretty well at a resolution step below Theora.
AV1 is slower still, and tops out around 360p for single-threaded decoding on a fast desktop or iOS device.
*Low-res targets*
I've gotten acceptable performance for Vorbis audio and 160p/15fps Theora files on 32-bit iOS devices: iPhone 4s, iPod Touch 5th-gen and iPad 3. These have difficulty at 240p and above, and just won't keep up with higher resolutions.
Meanwhile, newer 64-bit iPhones and iPads are comparable to low-end laptops, and videos at 360p and often 480p play acceptably. Since 32-bit and 64-bit iOS devices have the same user-agent, a benchmark must be used to approximately test minimum CPU speed.
(On iOS, Safari performs significantly better than some alternative browsers that are unable to enable the JIT due to use of the old UIWebView API. Chrome 49 and Firefox for iOS are known to work using the newer WKWebView API internally. Again, a benchmark must be used to detect slow performance, as the browser remains otherwise compatible.)
Windows on 32-bit ARM platforms is similar... IE 11 on Windows RT 8.1 on a Surface tablet (NVidia Tegra 3) does not work (crashes IE), while Edge on Windows 10 Mobile works ok at low resolutions, having trouble starting around 240p.
In both cases, a native application looms as a possibly better alternative. See [OGVKit](https://github.com/brion/OGVKit) and [OgvRt](https://github.com/brion/OgvRT) projects for experiments in those directions.
Note that at these lower resolutions, Vorbis audio and Theora video decoding are about equally expensive operations -- dual-core phones and tablets should be able to eke out a little parallelism here thanks to audio and video being in separate Worker threads.
*WebGL drawing acceleration*
Accelerated YCbCr->RGB conversion and drawing is done using WebGL on supporting browsers, or through software CPU conversion if not. This is abstracted in the [yuv-canvas](https://github.com/brion/yuv-canvas) package, now separately installable.
It may be possible to do further acceleration of actual decoding operations using WebGL shaders, but this could be ... tricky. WebGL is also only available on the main thread, and there are no compute shaders yet so would have to use fragment shaders.
## Difficulties
*Threading*
Currently the video and audio codecs run in worker threads by default, while the demuxer and player logic run on the UI thread. This seems to work pretty well.
There is some overhead in extracting data out of each emscripten module's heap and in the thread-to-thread communications, but the parallelism and smoother main thread makes up for it.
*Streaming download*
Streaming buffering is done by chunking the requests at up to a megabyte each, using the HTTP Range header. For cross-site playback, this requires CORS setup to whitelist the Range header! Chunks are downloaded as ArrayBuffers, so a chunk must be loaded in full before demuxing or playback can start.
Old versions of [Safari have a bug with Range headers](https://bugs.webkit.org/show_bug.cgi?id=82672) which is worked around as necessary with a 'cache-busting' URL string parameter.
*Seeking*
Seeking is implemented via the HTTP Range: header.
For Ogg files with keyframe indices in a skeleton index, seeking is very fast. Otherwise, a bisection search is used to locate the target frame or audio position, which is very slow over the internet as it creates a lot of short-lived HTTP requests.
For WebM files with cues, efficient seeking is supported as well as of 1.1.2. WebM files without cues can be seeked in 1.5.5, but inefficiently via linear seek from the beginning. This is fine for small audio-only files, but might be improved for large files with a bisection in future.
As with chunked streaming, cross-site playback requires CORS support for the Range header.
*Audio output*
Audio output is handled through the [AudioFeeder](https://github.com/brion/audio-feeder) library, which encapsulates use of Web Audio API:
Firefox, Safari, Chrome, and Edge support the W3C Web Audio API.
IE is no longer supported; the workaround using Flash no longer works due to sunsetting of the Flash plugin.
A/V synchronization is performed on files with both audio and video, and seems to actually work. Yay!
Note that autoplay with audio doesn't work on iOS Safari due to limitations with starting audio playback from event handlers; if playback is started outside an event handler, the player will hang due to broken audio.
As of 1.1.1, muting before script-triggered playback allows things to work:
```
player = new OGVPlayer();
player.muted = true;
player.src = 'path/to/file-with-audio.ogv';
player.play();
```
You can then unmute the video in response to a touch or click handler. Alternately if audio is not required, do not include an audio track in the file.
*WebM*
WebM support was added in June 2015, with some major issues finally worked out in May 2016. Initial VP9 support was added in February 2017. It's pretty stable in production use at Wikipedia and is enabled by default as of October 2015.
Beware that performance of WebM VP8 is much slower than Ogg Theora, and VP9 is slightly slower still.
For best WebM decode speed, consider encoding VP8 with "profile 1" (simple deblocking filter) which will sacrifice quality modestly, mainly in high-motion scenes. When encoding with ffmpeg, this is the `-profile:v 1` option to the `libvpx` codec.
It is also recommended to use the `-slices` option for VP8, or `-tile-columns` for VP9, to maximize ability to use multithreaded decoding when available in the future.
*AV1*
WebM files containing the AV1 codec are supported as of 1.6.0 (February 2019) using the [dav1d](https://code.videolan.org/videolan/dav1d) decoder.
Currently this is experimental, and does not advertise support via `canPlayType`.
Performance is about 2-3x slower than VP8 or VP9, and may require bumping down a resolution step or two to maintain frame rate. There may be further optimizations that can be done to improve this a bit, but the best improvements will come from future improvements to WebAssembly multithreading and SIMD.
Currently AV1 in MP4 container is not supported.
## Upstream library notes
We've experimented with tremor (libivorbis), an integer-only variant of libvorbis. This actually does *not* decode faster, but does save about 200kb off our generated JavaScript, presumably thanks to not including an encoder in the library. However on slow devices like iPod Touch 5th-generation, it makes a significant negative impact on the decode time so we've gone back to libvorbis.
The Ogg Skeleton library (libskeleton) is a bit ... unfinished and is slightly modified here.
libvpx is slightly modified to work around emscripten threading limitations in the VP8 decoder.
## WebAssembly
WebAssembly (Wasm) builds are used exclusively as of 1.8.0, as Safari's Wasm support is pretty well established now and IE no longer works due to the Flash plugin deprecation.
## Multithreading
Experimental multithreaded VP8, VP9, and AV1 decoding up to 4 cores is in development, requiring emscripten 1.38.27 to build.
Multithreading is used only if `options.threading` is true. This requires browser support for the new `SharedArrayBuffer` and `Atomics` APIs, currently available in Firefox and Chrome with experimental flags enabled.
Threading currently requires WebAssembly; JavaScript builds are possible but perform poorly.
Speedups will only be noticeable when using the "slices" or "token partitions" option for VP8 encoding, or the "tile columns" option for VP9 encoding.
If you are making a slim build and will not use the `threading` option, you can leave out the `*-mt.*` files.
## Building JS components
Building ogv.js is known to work on Mac OS X and Linux (tested Fedora 29 and Ubuntu 18.10 with Meson manually updated).
1. You will need autoconf, automake, libtool, pkg-config, meson, ninja, and node (nodejs). These can be installed through Homebrew on Mac OS X, or through distribution-specific methods on Linux. For meson, you may need a newer version than your distro packages -- install it manually with `pip3` or from source.
2. Install [Emscripten](http://kripken.github.io/emscripten-site/docs/getting_started/Tutorial.html); currently building with 2.0.13.
3. `git submodule update --init`
4. Run `npm install` to install build utilities
5. Run `make js` to configure and build the libraries and the C wrapper
## Building the demo
If you did all the setup above, just run `make demo` or `make`. Look in build/demo/ and enjoy!
## License
libogg, libvorbis, libtheora, libopus, nestegg, libvpx, and dav1d are available under their respective licenses, and the JavaScript and C wrapper code in this repo is licensed under MIT.
Based on build scripts from https://github.com/devongovett/ogg.js
See [AUTHORS.md](https://github.com/brion/ogv.js/blob/master/AUTHORS.md) and/or the git history for a list of contributors.
@@ -0,0 +1,40 @@
var OGVDecoderAudioOpusW = (() => {
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
return (
function(OGVDecoderAudioOpusW) {
OGVDecoderAudioOpusW = OGVDecoderAudioOpusW || {};
var a;a||(a=typeof OGVDecoderAudioOpusW !== 'undefined' ? OGVDecoderAudioOpusW : {});var l,m;a.ready=new Promise(function(b,c){l=b;m=c});var q=a,t=Object.assign({},a),u="object"==typeof window,w="function"==typeof importScripts,x="",y,A,B,fs,C,D;
if("object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node)x=w?require("path").dirname(x)+"/":__dirname+"/",D=()=>{C||(fs=require("fs"),C=require("path"))},y=function(b,c){D();b=C.normalize(b);return fs.readFileSync(b,c?void 0:"utf8")},B=b=>{b=y(b,!0);b.buffer||(b=new Uint8Array(b));return b},A=(b,c,e)=>{D();b=C.normalize(b);fs.readFile(b,function(d,f){d?e(d):c(f.buffer)})},1<process.argv.length&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),
process.on("unhandledRejection",function(b){throw b;}),a.inspect=function(){return"[Emscripten Module object]"};else if(u||w)w?x=self.location.href:"undefined"!=typeof document&&document.currentScript&&(x=document.currentScript.src),_scriptDir&&(x=_scriptDir),0!==x.indexOf("blob:")?x=x.substr(0,x.replace(/[?#].*/,"").lastIndexOf("/")+1):x="",y=b=>{var c=new XMLHttpRequest;c.open("GET",b,!1);c.send(null);return c.responseText},w&&(B=b=>{var c=new XMLHttpRequest;c.open("GET",b,!1);c.responseType="arraybuffer";
c.send(null);return new Uint8Array(c.response)}),A=(b,c,e)=>{var d=new XMLHttpRequest;d.open("GET",b,!0);d.responseType="arraybuffer";d.onload=()=>{200==d.status||0==d.status&&d.response?c(d.response):e()};d.onerror=e;d.send(null)};var aa=a.print||console.log.bind(console),E=a.printErr||console.warn.bind(console);Object.assign(a,t);t=null;var F;a.wasmBinary&&(F=a.wasmBinary);var noExitRuntime=a.noExitRuntime||!0;"object"!=typeof WebAssembly&&G("no native wasm support detected");
var H,I=!1,ba="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0,ca,J,K;function da(){var b=H.buffer;ca=b;a.HEAP8=new Int8Array(b);a.HEAP16=new Int16Array(b);a.HEAP32=K=new Int32Array(b);a.HEAPU8=J=new Uint8Array(b);a.HEAPU16=new Uint16Array(b);a.HEAPU32=new Uint32Array(b);a.HEAPF32=new Float32Array(b);a.HEAPF64=new Float64Array(b)}var ea,fa=[],ha=[],ia=[];function ja(){var b=a.preRun.shift();fa.unshift(b)}var L=0,M=null,N=null;a.preloadedImages={};a.preloadedAudios={};
function G(b){if(a.onAbort)a.onAbort(b);b="Aborted("+b+")";E(b);I=!0;b=new WebAssembly.RuntimeError(b+". Build with -s ASSERTIONS=1 for more info.");m(b);throw b;}function ka(){return O.startsWith("data:application/octet-stream;base64,")}var O;O="ogv-decoder-audio-opus-wasm.wasm";if(!ka()){var la=O;O=a.locateFile?a.locateFile(la,x):x+la}function oa(){var b=O;try{if(b==O&&F)return new Uint8Array(F);if(B)return B(b);throw"both async and sync fetching of the wasm failed";}catch(c){G(c)}}
function pa(){if(!F&&(u||w)){if("function"==typeof fetch&&!O.startsWith("file://"))return fetch(O,{credentials:"same-origin"}).then(function(b){if(!b.ok)throw"failed to load wasm binary file at '"+O+"'";return b.arrayBuffer()}).catch(function(){return oa()});if(A)return new Promise(function(b,c){A(O,function(e){b(new Uint8Array(e))},c)})}return Promise.resolve().then(function(){return oa()})}
function S(b){for(;0<b.length;){var c=b.shift();if("function"==typeof c)c(a);else{var e=c.u;"number"==typeof e?void 0===c.s?qa(e)():qa(e)(c.s):e(void 0===c.s?null:c.s)}}}var T=[];function qa(b){var c=T[b];c||(b>=T.length&&(T.length=b+1),T[b]=c=ea.get(b));return c}
var ra=[null,[],[]],sa={f:function(){G("")},e:function(b,c,e){J.copyWithin(b,c,c+e)},c:function(b){var c=J.length;b>>>=0;if(2147483648<b)return!1;for(var e=1;4>=e;e*=2){var d=c*(1+.2/e);d=Math.min(d,b+100663296);var f=Math;d=Math.max(b,d);f=f.min.call(f,2147483648,d+(65536-d%65536)%65536);a:{try{H.grow(f-ca.byteLength+65535>>>16);da();var g=1;break a}catch(h){}g=void 0}if(g)return!0}return!1},d:function(){return 0},b:function(){},a:function(b,c,e,d){for(var f=0,g=0;g<e;g++){var h=K[c>>2],ma=K[c+4>>
2];c+=8;for(var P=0;P<ma;P++){var z=J[h+P],Q=ra[b];if(0===z||10===z){z=1===b?aa:E;var n=Q;for(var p=0,r=p+NaN,v=p;n[v]&&!(v>=r);)++v;if(16<v-p&&n.buffer&&ba)n=ba.decode(n.subarray(p,v));else{for(r="";p<v;){var k=n[p++];if(k&128){var R=n[p++]&63;if(192==(k&224))r+=String.fromCharCode((k&31)<<6|R);else{var na=n[p++]&63;k=224==(k&240)?(k&15)<<12|R<<6|na:(k&7)<<18|R<<12|na<<6|n[p++]&63;65536>k?r+=String.fromCharCode(k):(k-=65536,r+=String.fromCharCode(55296|k>>10,56320|k&1023))}}else r+=String.fromCharCode(k)}n=
r}z(n);Q.length=0}else Q.push(z)}f+=ma}K[d>>2]=f;return 0},g:function(b,c,e){var d=H.buffer,f=new Uint32Array(d,b,c),g=[];if(0!==b)for(b=0;b<c;b++){var h=f[b];d.slice?(h=d.slice(h,h+4*e),h=new Float32Array(h)):(h=new Float32Array(d,h,e),h=new Float32Array(h));g.push(h)}a.audioBuffer=g},h:function(b,c){a.audioFormat={channels:b,rate:c};a.loadedMetadata=!0}};
(function(){function b(f){a.asm=f.exports;H=a.asm.i;da();ea=a.asm.q;ha.unshift(a.asm.j);L--;a.monitorRunDependencies&&a.monitorRunDependencies(L);0==L&&(null!==M&&(clearInterval(M),M=null),N&&(f=N,N=null,f()))}function c(f){b(f.instance)}function e(f){return pa().then(function(g){return WebAssembly.instantiate(g,d)}).then(function(g){return g}).then(f,function(g){E("failed to asynchronously prepare wasm: "+g);G(g)})}var d={a:sa};L++;a.monitorRunDependencies&&a.monitorRunDependencies(L);if(a.instantiateWasm)try{return a.instantiateWasm(d,
b)}catch(f){return E("Module.instantiateWasm callback failed with error: "+f),!1}(function(){return F||"function"!=typeof WebAssembly.instantiateStreaming||ka()||O.startsWith("file://")||"function"!=typeof fetch?e(c):fetch(O,{credentials:"same-origin"}).then(function(f){return WebAssembly.instantiateStreaming(f,d).then(c,function(g){E("wasm streaming compile failed: "+g);E("falling back to ArrayBuffer instantiation");return e(c)})})})().catch(m);return{}})();
a.___wasm_call_ctors=function(){return(a.___wasm_call_ctors=a.asm.j).apply(null,arguments)};a._ogv_audio_decoder_init=function(){return(a._ogv_audio_decoder_init=a.asm.k).apply(null,arguments)};a._ogv_audio_decoder_process_header=function(){return(a._ogv_audio_decoder_process_header=a.asm.l).apply(null,arguments)};a._ogv_audio_decoder_process_audio=function(){return(a._ogv_audio_decoder_process_audio=a.asm.m).apply(null,arguments)};a._malloc=function(){return(a._malloc=a.asm.n).apply(null,arguments)};
a._free=function(){return(a._free=a.asm.o).apply(null,arguments)};a._ogv_audio_decoder_destroy=function(){return(a._ogv_audio_decoder_destroy=a.asm.p).apply(null,arguments)};var U;N=function ta(){U||V();U||(N=ta)};
function V(){function b(){if(!U&&(U=!0,a.calledRun=!0,!I)){S(ha);l(a);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;){var c=a.postRun.shift();ia.unshift(c)}S(ia)}}if(!(0<L)){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)ja();S(fa);0<L||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);b()},1)):b())}}a.run=V;
if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();V();var W,X;function ua(b){if(W&&X>=b)return W;W&&a._free(W);X=b;return W=a._malloc(X)}var Y;"undefined"===typeof performance||"undefined"===typeof performance.now?Y=Date.now:Y=performance.now.bind(performance);function Z(b){var c=Y();b=b();a.cpuTime+=Y()-c;return b}a.loadedMetadata=!!q.audioFormat;a.audioFormat=q.audioFormat||null;a.audioBuffer=null;a.cpuTime=0;
Object.defineProperty(a,"processing",{get:function(){return!1}});a.init=function(b){Z(function(){a._ogv_audio_decoder_init()});b()};a.processHeader=function(b,c){var e=Z(function(){var d=b.byteLength,f=ua(d);(new Uint8Array(H.buffer,f,d)).set(new Uint8Array(b));return a._ogv_audio_decoder_process_header(f,d)});c(e)};a.processAudio=function(b,c){var e=Z(function(){var d=b.byteLength,f=ua(d);(new Uint8Array(H.buffer,f,d)).set(new Uint8Array(b));return a._ogv_audio_decoder_process_audio(f,d)});c(e)};
a.close=function(){};
return OGVDecoderAudioOpusW.ready
}
);
})();
if (typeof exports === 'object' && typeof module === 'object')
module.exports = OGVDecoderAudioOpusW;
else if (typeof define === 'function' && define['amd'])
define([], function() { return OGVDecoderAudioOpusW; });
else if (typeof exports === 'object')
exports["OGVDecoderAudioOpusW"] = OGVDecoderAudioOpusW;
@@ -0,0 +1,40 @@
var OGVDecoderAudioVorbisW = (() => {
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
return (
function(OGVDecoderAudioVorbisW) {
OGVDecoderAudioVorbisW = OGVDecoderAudioVorbisW || {};
var b;b||(b=typeof OGVDecoderAudioVorbisW !== 'undefined' ? OGVDecoderAudioVorbisW : {});var h,k;b.ready=new Promise(function(a,c){h=a;k=c});var m=b,n=Object.assign({},b),p=(a,c)=>{throw c;},q="object"==typeof window,r="function"==typeof importScripts,t="",u,v,w,fs,x,y;
if("object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node)t=r?require("path").dirname(t)+"/":__dirname+"/",y=()=>{x||(fs=require("fs"),x=require("path"))},u=function(a,c){y();a=x.normalize(a);return fs.readFileSync(a,c?void 0:"utf8")},w=a=>{a=u(a,!0);a.buffer||(a=new Uint8Array(a));return a},v=(a,c,e)=>{y();a=x.normalize(a);fs.readFile(a,function(d,f){d?e(d):c(f.buffer)})},1<process.argv.length&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),
process.on("unhandledRejection",function(a){throw a;}),p=(a,c)=>{if(noExitRuntime)throw process.exitCode=a,c;c instanceof z||A("exiting due to exception: "+c);process.exit(a)},b.inspect=function(){return"[Emscripten Module object]"};else if(q||r)r?t=self.location.href:"undefined"!=typeof document&&document.currentScript&&(t=document.currentScript.src),_scriptDir&&(t=_scriptDir),0!==t.indexOf("blob:")?t=t.substr(0,t.replace(/[?#].*/,"").lastIndexOf("/")+1):t="",u=a=>{var c=new XMLHttpRequest;c.open("GET",
a,!1);c.send(null);return c.responseText},r&&(w=a=>{var c=new XMLHttpRequest;c.open("GET",a,!1);c.responseType="arraybuffer";c.send(null);return new Uint8Array(c.response)}),v=(a,c,e)=>{var d=new XMLHttpRequest;d.open("GET",a,!0);d.responseType="arraybuffer";d.onload=()=>{200==d.status||0==d.status&&d.response?c(d.response):e()};d.onerror=e;d.send(null)};b.print||console.log.bind(console);var A=b.printErr||console.warn.bind(console);Object.assign(b,n);n=null;b.quit&&(p=b.quit);var B;
b.wasmBinary&&(B=b.wasmBinary);var noExitRuntime=b.noExitRuntime||!0;"object"!=typeof WebAssembly&&C("no native wasm support detected");var D,E=!1,F,G;function H(){var a=D.buffer;F=a;b.HEAP8=new Int8Array(a);b.HEAP16=new Int16Array(a);b.HEAP32=new Int32Array(a);b.HEAPU8=G=new Uint8Array(a);b.HEAPU16=new Uint16Array(a);b.HEAPU32=new Uint32Array(a);b.HEAPF32=new Float32Array(a);b.HEAPF64=new Float64Array(a)}var I,J=[],K=[],L=[];function aa(){var a=b.preRun.shift();J.unshift(a)}var M=0,N=null,O=null;
b.preloadedImages={};b.preloadedAudios={};function C(a){if(b.onAbort)b.onAbort(a);a="Aborted("+a+")";A(a);E=!0;a=new WebAssembly.RuntimeError(a+". Build with -s ASSERTIONS=1 for more info.");k(a);throw a;}function P(){return Q.startsWith("data:application/octet-stream;base64,")}var Q;Q="ogv-decoder-audio-vorbis-wasm.wasm";if(!P()){var R=Q;Q=b.locateFile?b.locateFile(R,t):t+R}
function ba(){var a=Q;try{if(a==Q&&B)return new Uint8Array(B);if(w)return w(a);throw"both async and sync fetching of the wasm failed";}catch(c){C(c)}}
function ca(){if(!B&&(q||r)){if("function"==typeof fetch&&!Q.startsWith("file://"))return fetch(Q,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+Q+"'";return a.arrayBuffer()}).catch(function(){return ba()});if(v)return new Promise(function(a,c){v(Q,function(e){a(new Uint8Array(e))},c)})}return Promise.resolve().then(function(){return ba()})}
function S(a){for(;0<a.length;){var c=a.shift();if("function"==typeof c)c(b);else{var e=c.s;"number"==typeof e?void 0===c.o?da(e)():da(e)(c.o):e(void 0===c.o?null:c.o)}}}var T=[];function da(a){var c=T[a];c||(a>=T.length&&(T.length=a+1),T[a]=c=I.get(a));return c}
var ea={b:function(a,c,e){G.copyWithin(a,c,c+e)},a:function(a){var c=G.length;a>>>=0;if(2147483648<a)return!1;for(var e=1;4>=e;e*=2){var d=c*(1+.2/e);d=Math.min(d,a+100663296);var f=Math;d=Math.max(a,d);f=f.min.call(f,2147483648,d+(65536-d%65536)%65536);a:{try{D.grow(f-F.byteLength+65535>>>16);H();var g=1;break a}catch(l){}g=void 0}if(g)return!0}return!1},c:function(a){if(!noExitRuntime){if(b.onExit)b.onExit(a);E=!0}p(a,new z(a))},d:function(a,c,e){var d=D.buffer,f=new Uint32Array(d,a,c),g=[];if(0!==
a)for(a=0;a<c;a++){var l=f[a];d.slice?(l=d.slice(l,l+4*e),l=new Float32Array(l)):(l=new Float32Array(d,l,e),l=new Float32Array(l));g.push(l)}b.audioBuffer=g},e:function(a,c){b.audioFormat={channels:a,rate:c};b.loadedMetadata=!0}};
(function(){function a(f){b.asm=f.exports;D=b.asm.f;H();I=b.asm.n;K.unshift(b.asm.g);M--;b.monitorRunDependencies&&b.monitorRunDependencies(M);0==M&&(null!==N&&(clearInterval(N),N=null),O&&(f=O,O=null,f()))}function c(f){a(f.instance)}function e(f){return ca().then(function(g){return WebAssembly.instantiate(g,d)}).then(function(g){return g}).then(f,function(g){A("failed to asynchronously prepare wasm: "+g);C(g)})}var d={a:ea};M++;b.monitorRunDependencies&&b.monitorRunDependencies(M);if(b.instantiateWasm)try{return b.instantiateWasm(d,
a)}catch(f){return A("Module.instantiateWasm callback failed with error: "+f),!1}(function(){return B||"function"!=typeof WebAssembly.instantiateStreaming||P()||Q.startsWith("file://")||"function"!=typeof fetch?e(c):fetch(Q,{credentials:"same-origin"}).then(function(f){return WebAssembly.instantiateStreaming(f,d).then(c,function(g){A("wasm streaming compile failed: "+g);A("falling back to ArrayBuffer instantiation");return e(c)})})})().catch(k);return{}})();
b.___wasm_call_ctors=function(){return(b.___wasm_call_ctors=b.asm.g).apply(null,arguments)};b._ogv_audio_decoder_init=function(){return(b._ogv_audio_decoder_init=b.asm.h).apply(null,arguments)};b._ogv_audio_decoder_process_header=function(){return(b._ogv_audio_decoder_process_header=b.asm.i).apply(null,arguments)};b._ogv_audio_decoder_process_audio=function(){return(b._ogv_audio_decoder_process_audio=b.asm.j).apply(null,arguments)};
b._ogv_audio_decoder_destroy=function(){return(b._ogv_audio_decoder_destroy=b.asm.k).apply(null,arguments)};b._malloc=function(){return(b._malloc=b.asm.l).apply(null,arguments)};b._free=function(){return(b._free=b.asm.m).apply(null,arguments)};var U;function z(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}O=function fa(){U||V();U||(O=fa)};
function V(){function a(){if(!U&&(U=!0,b.calledRun=!0,!E)){S(K);h(b);if(b.onRuntimeInitialized)b.onRuntimeInitialized();if(b.postRun)for("function"==typeof b.postRun&&(b.postRun=[b.postRun]);b.postRun.length;){var c=b.postRun.shift();L.unshift(c)}S(L)}}if(!(0<M)){if(b.preRun)for("function"==typeof b.preRun&&(b.preRun=[b.preRun]);b.preRun.length;)aa();S(J);0<M||(b.setStatus?(b.setStatus("Running..."),setTimeout(function(){setTimeout(function(){b.setStatus("")},1);a()},1)):a())}}b.run=V;
if(b.preInit)for("function"==typeof b.preInit&&(b.preInit=[b.preInit]);0<b.preInit.length;)b.preInit.pop()();V();var W,X;function ha(a){if(W&&X>=a)return W;W&&b._free(W);X=a;return W=b._malloc(X)}var Y;"undefined"===typeof performance||"undefined"===typeof performance.now?Y=Date.now:Y=performance.now.bind(performance);function Z(a){var c=Y();a=a();b.cpuTime+=Y()-c;return a}b.loadedMetadata=!!m.audioFormat;b.audioFormat=m.audioFormat||null;b.audioBuffer=null;b.cpuTime=0;
Object.defineProperty(b,"processing",{get:function(){return!1}});b.init=function(a){Z(function(){b._ogv_audio_decoder_init()});a()};b.processHeader=function(a,c){var e=Z(function(){var d=a.byteLength,f=ha(d);(new Uint8Array(D.buffer,f,d)).set(new Uint8Array(a));return b._ogv_audio_decoder_process_header(f,d)});c(e)};b.processAudio=function(a,c){var e=Z(function(){var d=a.byteLength,f=ha(d);(new Uint8Array(D.buffer,f,d)).set(new Uint8Array(a));return b._ogv_audio_decoder_process_audio(f,d)});c(e)};
b.close=function(){};
return OGVDecoderAudioVorbisW.ready
}
);
})();
if (typeof exports === 'object' && typeof module === 'object')
module.exports = OGVDecoderAudioVorbisW;
else if (typeof define === 'function' && define['amd'])
define([], function() { return OGVDecoderAudioVorbisW; });
else if (typeof exports === 'object')
exports["OGVDecoderAudioVorbisW"] = OGVDecoderAudioVorbisW;
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
"use strict";var Module={};var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",function(data){onmessage({data:data})});var fs=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:function(f){(0,eval)(fs.readFileSync(f,"utf8"))},postMessage:function(msg){parentPort.postMessage(msg)},performance:global.performance||{now:function(){return Date.now()}}})}function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");if(ENVIRONMENT_IS_NODE){fs.writeSync(2,text+"\n");return}console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=((info,receiveInstance)=>{var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports});self.onmessage=(e=>{try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;if(typeof e.data.urlOrBlob=="string"){importScripts(e.data.urlOrBlob)}else{var objectUrl=URL.createObjectURL(e.data.urlOrBlob);importScripts(objectUrl);URL.revokeObjectURL(objectUrl)}OGVDecoderVideoAV1MTW(Module).then(function(instance){Module=instance})}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0,1);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["__emscripten_thread_exit"](result)}}catch(ex){if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["__emscripten_thread_exit"](ex.status)}}else{throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processProxyingQueue"){if(Module["_pthread_self"]()){Module["_emscripten_proxy_execute_queue"](e.data.queue)}Atomics.sub(HEAP32,e.data.queue>>2,1)}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}});
@@ -0,0 +1,43 @@
var OGVDecoderVideoAV1W = (() => {
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
return (
function(OGVDecoderVideoAV1W) {
OGVDecoderVideoAV1W = OGVDecoderVideoAV1W || {};
var a;a||(a=typeof OGVDecoderVideoAV1W !== 'undefined' ? OGVDecoderVideoAV1W : {});var aa,q;a.ready=new Promise(function(b,c){aa=b;q=c});var ba=a,ca=Object.assign({},a),da="object"==typeof window,r="function"==typeof importScripts,A="",ea,F,G,fs,I,fa;
if("object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node)A=r?require("path").dirname(A)+"/":__dirname+"/",fa=()=>{I||(fs=require("fs"),I=require("path"))},ea=function(b,c){fa();b=I.normalize(b);return fs.readFileSync(b,c?void 0:"utf8")},G=b=>{b=ea(b,!0);b.buffer||(b=new Uint8Array(b));return b},F=(b,c,f)=>{fa();b=I.normalize(b);fs.readFile(b,function(d,e){d?f(d):c(e.buffer)})},1<process.argv.length&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),
process.on("unhandledRejection",function(b){throw b;}),a.inspect=function(){return"[Emscripten Module object]"};else if(da||r)r?A=self.location.href:"undefined"!=typeof document&&document.currentScript&&(A=document.currentScript.src),_scriptDir&&(A=_scriptDir),0!==A.indexOf("blob:")?A=A.substr(0,A.replace(/[?#].*/,"").lastIndexOf("/")+1):A="",ea=b=>{var c=new XMLHttpRequest;c.open("GET",b,!1);c.send(null);return c.responseText},r&&(G=b=>{var c=new XMLHttpRequest;c.open("GET",b,!1);c.responseType=
"arraybuffer";c.send(null);return new Uint8Array(c.response)}),F=(b,c,f)=>{var d=new XMLHttpRequest;d.open("GET",b,!0);d.responseType="arraybuffer";d.onload=()=>{200==d.status||0==d.status&&d.response?c(d.response):f()};d.onerror=f;d.send(null)};var ha=a.print||console.log.bind(console),J=a.printErr||console.warn.bind(console);Object.assign(a,ca);ca=null;var K;a.wasmBinary&&(K=a.wasmBinary);var noExitRuntime=a.noExitRuntime||!0;"object"!=typeof WebAssembly&&M("no native wasm support detected");
var N,ia=!1,ja="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0,ka,O,P;function la(){var b=N.buffer;ka=b;a.HEAP8=new Int8Array(b);a.HEAP16=new Int16Array(b);a.HEAP32=P=new Int32Array(b);a.HEAPU8=O=new Uint8Array(b);a.HEAPU16=new Uint16Array(b);a.HEAPU32=new Uint32Array(b);a.HEAPF32=new Float32Array(b);a.HEAPF64=new Float64Array(b)}var ma,na=[],oa=[],pa=[];function qa(){var b=a.preRun.shift();na.unshift(b)}var Q=0,ra=null,R=null;a.preloadedImages={};a.preloadedAudios={};
function M(b){if(a.onAbort)a.onAbort(b);b="Aborted("+b+")";J(b);ia=!0;b=new WebAssembly.RuntimeError(b+". Build with -s ASSERTIONS=1 for more info.");q(b);throw b;}function sa(){return S.startsWith("data:application/octet-stream;base64,")}var S;S="ogv-decoder-video-av1-wasm.wasm";if(!sa()){var ta=S;S=a.locateFile?a.locateFile(ta,A):A+ta}function ua(){var b=S;try{if(b==S&&K)return new Uint8Array(K);if(G)return G(b);throw"both async and sync fetching of the wasm failed";}catch(c){M(c)}}
function va(){if(!K&&(da||r)){if("function"==typeof fetch&&!S.startsWith("file://"))return fetch(S,{credentials:"same-origin"}).then(function(b){if(!b.ok)throw"failed to load wasm binary file at '"+S+"'";return b.arrayBuffer()}).catch(function(){return ua()});if(F)return new Promise(function(b,c){F(S,function(f){b(new Uint8Array(f))},c)})}return Promise.resolve().then(function(){return ua()})}
function wa(b){for(;0<b.length;){var c=b.shift();if("function"==typeof c)c(a);else{var f=c.B;"number"==typeof f?void 0===c.s?Ia(f)():Ia(f)(c.s):f(void 0===c.s?null:c.s)}}}var T=[];function Ia(b){var c=T[b];c||(b>=T.length&&(T.length=b+1),T[b]=c=ma.get(b));return c}
var Ja=[null,[],[]],Ka={f:function(){M("")},e:function(b,c,f){O.copyWithin(b,c,c+f)},c:function(b){var c=O.length;b>>>=0;if(2147483648<b)return!1;for(var f=1;4>=f;f*=2){var d=c*(1+.2/f);d=Math.min(d,b+100663296);var e=Math;d=Math.max(b,d);e=e.min.call(e,2147483648,d+(65536-d%65536)%65536);a:{try{N.grow(e-ka.byteLength+65535>>>16);la();var g=1;break a}catch(w){}g=void 0}if(g)return!0}return!1},d:function(){return 0},b:function(){},a:function(b,c,f,d){for(var e=0,g=0;g<f;g++){var w=P[c>>2],u=P[c+4>>
2];c+=8;for(var y=0;y<u;y++){var n=O[w+y],x=Ja[b];if(0===n||10===n){n=1===b?ha:J;var l=x;for(var p=0,t=p+NaN,v=p;l[v]&&!(v>=t);)++v;if(16<v-p&&l.buffer&&ja)l=ja.decode(l.subarray(p,v));else{for(t="";p<v;){var h=l[p++];if(h&128){var B=l[p++]&63;if(192==(h&224))t+=String.fromCharCode((h&31)<<6|B);else{var U=l[p++]&63;h=224==(h&240)?(h&15)<<12|B<<6|U:(h&7)<<18|B<<12|U<<6|l[p++]&63;65536>h?t+=String.fromCharCode(h):(h-=65536,t+=String.fromCharCode(55296|h>>10,56320|h&1023))}}else t+=String.fromCharCode(h)}l=
t}n(l);x.length=0}else x.push(n)}e+=u}P[d>>2]=e;return 0},g:function(b,c,f,d,e,g,w,u,y,n,x,l,p,t,v,h){function B(H,k,C,xa,ya,za,Ma,Na,V){H.set(new Uint8Array(U,k,C*xa));var D,z;for(D=z=0;D<za;D++,z+=C)for(k=0;k<C;k++)H[z+k]=V;for(;D<za+Na;D++,z+=C){for(k=0;k<ya;k++)H[z+k]=V;for(k=ya+Ma;k<C;k++)H[z+k]=V}for(;D<xa;D++,z+=C)for(k=0;k<C;k++)H[z+k]=V;return H}var U=N.buffer,m=a.videoFormat,Aa=(p&-2)*y/w,Ba=(t&-2)*n/u,Ca=x*y/w,Da=l*n/u;x===m.cropWidth&&l===m.cropHeight&&(v=m.displayWidth,h=m.displayHeight);
for(var Ea=a.recycledFrames,E,Fa=u*c,Ga=n*d,Ha=n*g;0<Ea.length;){var L=Ea.shift();m=L.format;if(m.width===w&&m.height===u&&m.chromaWidth===y&&m.chromaHeight===n&&m.cropLeft===p&&m.cropTop===t&&m.cropWidth===x&&m.cropHeight===l&&m.displayWidth===v&&m.displayHeight===h&&L.y.bytes.length===Fa&&L.u.bytes.length===Ga&&L.v.bytes.length===Ha){E=L;break}}E||(E={format:{width:w,height:u,chromaWidth:y,chromaHeight:n,cropLeft:p,cropTop:t,cropWidth:x,cropHeight:l,displayWidth:v,displayHeight:h},y:{bytes:new Uint8Array(Fa),
stride:c},u:{bytes:new Uint8Array(Ga),stride:d},v:{bytes:new Uint8Array(Ha),stride:g}});B(E.y.bytes,b,c,u,p,t,x,l,0);B(E.u.bytes,f,d,n,Aa,Ba,Ca,Da,128);B(E.v.bytes,e,g,n,Aa,Ba,Ca,Da,128);a.frameBuffer=E}};
(function(){function b(e){a.asm=e.exports;N=a.asm.h;la();ma=a.asm.p;oa.unshift(a.asm.i);Q--;a.monitorRunDependencies&&a.monitorRunDependencies(Q);0==Q&&(null!==ra&&(clearInterval(ra),ra=null),R&&(e=R,R=null,e()))}function c(e){b(e.instance)}function f(e){return va().then(function(g){return WebAssembly.instantiate(g,d)}).then(function(g){return g}).then(e,function(g){J("failed to asynchronously prepare wasm: "+g);M(g)})}var d={a:Ka};Q++;a.monitorRunDependencies&&a.monitorRunDependencies(Q);if(a.instantiateWasm)try{return a.instantiateWasm(d,
b)}catch(e){return J("Module.instantiateWasm callback failed with error: "+e),!1}(function(){return K||"function"!=typeof WebAssembly.instantiateStreaming||sa()||S.startsWith("file://")||"function"!=typeof fetch?f(c):fetch(S,{credentials:"same-origin"}).then(function(e){return WebAssembly.instantiateStreaming(e,d).then(c,function(g){J("wasm streaming compile failed: "+g);J("falling back to ArrayBuffer instantiation");return f(c)})})})().catch(q);return{}})();
a.___wasm_call_ctors=function(){return(a.___wasm_call_ctors=a.asm.i).apply(null,arguments)};a._ogv_video_decoder_init=function(){return(a._ogv_video_decoder_init=a.asm.j).apply(null,arguments)};a._ogv_video_decoder_async=function(){return(a._ogv_video_decoder_async=a.asm.k).apply(null,arguments)};a._ogv_video_decoder_destroy=function(){return(a._ogv_video_decoder_destroy=a.asm.l).apply(null,arguments)};
a._ogv_video_decoder_process_header=function(){return(a._ogv_video_decoder_process_header=a.asm.m).apply(null,arguments)};a._ogv_video_decoder_process_frame=function(){return(a._ogv_video_decoder_process_frame=a.asm.n).apply(null,arguments)};a._free=function(){return(a._free=a.asm.o).apply(null,arguments)};a._malloc=function(){return(a._malloc=a.asm.q).apply(null,arguments)};var W;R=function La(){W||Oa();W||(R=La)};
function Oa(){function b(){if(!W&&(W=!0,a.calledRun=!0,!ia)){wa(oa);aa(a);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;){var c=a.postRun.shift();pa.unshift(c)}wa(pa)}}if(!(0<Q)){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)qa();wa(na);0<Q||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);b()},1)):b())}}a.run=Oa;
if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();Oa();var X,Pa,Y;"undefined"===typeof performance||"undefined"===typeof performance.now?Y=Date.now:Y=performance.now.bind(performance);function Z(b){var c=Y();b=b();a.cpuTime+=Y()-c;return b}a.loadedMetadata=!!ba.videoFormat;a.videoFormat=ba.videoFormat||null;a.frameBuffer=null;a.cpuTime=0;Object.defineProperty(a,"processing",{get:function(){return!1}});
a.init=function(b){Z(function(){a._ogv_video_decoder_init()});b()};a.processHeader=function(b,c){var f=Z(function(){var d=b.byteLength;X&&Pa>=d||(X&&a._free(X),Pa=d,X=a._malloc(Pa));var e=X;(new Uint8Array(N.buffer,e,d)).set(new Uint8Array(b));return a._ogv_video_decoder_process_header(e,d)});c(f)};a.A=[];
a.processFrame=function(b,c){function f(u){a._free(g);c(u)}var d=a._ogv_video_decoder_async(),e=b.byteLength,g=a._malloc(e);d&&a.A.push(f);var w=Z(function(){(new Uint8Array(N.buffer,g,e)).set(new Uint8Array(b));return a._ogv_video_decoder_process_frame(g,e)});d||f(w)};a.close=function(){};a.sync=function(){a._ogv_video_decoder_async()&&(a.A.push(function(){}),Z(function(){a._ogv_video_decoder_process_frame(0,0)}))};a.recycledFrames=[];
a.recycleFrame=function(b){var c=a.recycledFrames;c.push(b);16<c.length&&c.shift()};
return OGVDecoderVideoAV1W.ready
}
);
})();
if (typeof exports === 'object' && typeof module === 'object')
module.exports = OGVDecoderVideoAV1W;
else if (typeof define === 'function' && define['amd'])
define([], function() { return OGVDecoderVideoAV1W; });
else if (typeof exports === 'object')
exports["OGVDecoderVideoAV1W"] = OGVDecoderVideoAV1W;
@@ -0,0 +1,42 @@
var OGVDecoderVideoTheoraW = (() => {
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
return (
function(OGVDecoderVideoTheoraW) {
OGVDecoderVideoTheoraW = OGVDecoderVideoTheoraW || {};
var a;a||(a=typeof OGVDecoderVideoTheoraW !== 'undefined' ? OGVDecoderVideoTheoraW : {});var ca,l;a.ready=new Promise(function(b,c){ca=b;l=c});var da=a,ea=Object.assign({},a),fa="object"==typeof window,m="function"==typeof importScripts,t="",y,B,C,fs,D,E;
if("object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node)t=m?require("path").dirname(t)+"/":__dirname+"/",E=()=>{D||(fs=require("fs"),D=require("path"))},y=function(b,c){E();b=D.normalize(b);return fs.readFileSync(b,c?void 0:"utf8")},C=b=>{b=y(b,!0);b.buffer||(b=new Uint8Array(b));return b},B=(b,c,e)=>{E();b=D.normalize(b);fs.readFile(b,function(d,f){d?e(d):c(f.buffer)})},1<process.argv.length&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),
process.on("unhandledRejection",function(b){throw b;}),a.inspect=function(){return"[Emscripten Module object]"};else if(fa||m)m?t=self.location.href:"undefined"!=typeof document&&document.currentScript&&(t=document.currentScript.src),_scriptDir&&(t=_scriptDir),0!==t.indexOf("blob:")?t=t.substr(0,t.replace(/[?#].*/,"").lastIndexOf("/")+1):t="",y=b=>{var c=new XMLHttpRequest;c.open("GET",b,!1);c.send(null);return c.responseText},m&&(C=b=>{var c=new XMLHttpRequest;c.open("GET",b,!1);c.responseType="arraybuffer";
c.send(null);return new Uint8Array(c.response)}),B=(b,c,e)=>{var d=new XMLHttpRequest;d.open("GET",b,!0);d.responseType="arraybuffer";d.onload=()=>{200==d.status||0==d.status&&d.response?c(d.response):e()};d.onerror=e;d.send(null)};a.print||console.log.bind(console);var H=a.printErr||console.warn.bind(console);Object.assign(a,ea);ea=null;var I;a.wasmBinary&&(I=a.wasmBinary);var noExitRuntime=a.noExitRuntime||!0;"object"!=typeof WebAssembly&&J("no native wasm support detected");var K,ha=!1,ia,L;
function ja(){var b=K.buffer;ia=b;a.HEAP8=new Int8Array(b);a.HEAP16=new Int16Array(b);a.HEAP32=new Int32Array(b);a.HEAPU8=L=new Uint8Array(b);a.HEAPU16=new Uint16Array(b);a.HEAPU32=new Uint32Array(b);a.HEAPF32=new Float32Array(b);a.HEAPF64=new Float64Array(b)}var ka,la=[],ma=[],na=[];function oa(){var b=a.preRun.shift();la.unshift(b)}var P=0,Q=null,R=null;a.preloadedImages={};a.preloadedAudios={};
function J(b){if(a.onAbort)a.onAbort(b);b="Aborted("+b+")";H(b);ha=!0;b=new WebAssembly.RuntimeError(b+". Build with -s ASSERTIONS=1 for more info.");l(b);throw b;}function pa(){return S.startsWith("data:application/octet-stream;base64,")}var S;S="ogv-decoder-video-theora-wasm.wasm";if(!pa()){var qa=S;S=a.locateFile?a.locateFile(qa,t):t+qa}function ra(){var b=S;try{if(b==S&&I)return new Uint8Array(I);if(C)return C(b);throw"both async and sync fetching of the wasm failed";}catch(c){J(c)}}
function sa(){if(!I&&(fa||m)){if("function"==typeof fetch&&!S.startsWith("file://"))return fetch(S,{credentials:"same-origin"}).then(function(b){if(!b.ok)throw"failed to load wasm binary file at '"+S+"'";return b.arrayBuffer()}).catch(function(){return ra()});if(B)return new Promise(function(b,c){B(S,function(e){b(new Uint8Array(e))},c)})}return Promise.resolve().then(function(){return ra()})}
function T(b){for(;0<b.length;){var c=b.shift();if("function"==typeof c)c(a);else{var e=c.A;"number"==typeof e?void 0===c.o?ta(e)():ta(e)(c.o):e(void 0===c.o?null:c.o)}}}var U=[];function ta(b){var c=U[b];c||(b>=U.length&&(U.length=b+1),U[b]=c=ka.get(b));return c}
var Fa={b:function(b,c,e){L.copyWithin(b,c,c+e)},a:function(b){var c=L.length;b>>>=0;if(2147483648<b)return!1;for(var e=1;4>=e;e*=2){var d=c*(1+.2/e);d=Math.min(d,b+100663296);var f=Math;d=Math.max(b,d);f=f.min.call(f,2147483648,d+(65536-d%65536)%65536);a:{try{K.grow(f-ia.byteLength+65535>>>16);ja();var g=1;break a}catch(q){}g=void 0}if(g)return!0}return!1},c:function(b,c,e,d,f,g,q,n,z,p,u,F,M,N,Z,aa){function ba(A,h,v,ua,va,wa,Ha,Ia,O){A.set(new Uint8Array(Ja,h,v*ua));var w,r;for(w=r=0;w<wa;w++,
r+=v)for(h=0;h<v;h++)A[r+h]=O;for(;w<wa+Ia;w++,r+=v){for(h=0;h<va;h++)A[r+h]=O;for(h=va+Ha;h<v;h++)A[r+h]=O}for(;w<ua;w++,r+=v)for(h=0;h<v;h++)A[r+h]=O;return A}var Ja=K.buffer,k=a.videoFormat,xa=(M&-2)*z/q,ya=(N&-2)*p/n,za=u*z/q,Aa=F*p/n;u===k.cropWidth&&F===k.cropHeight&&(Z=k.displayWidth,aa=k.displayHeight);for(var Ba=a.recycledFrames,x,Ca=n*c,Da=p*d,Ea=p*g;0<Ba.length;){var G=Ba.shift();k=G.format;if(k.width===q&&k.height===n&&k.chromaWidth===z&&k.chromaHeight===p&&k.cropLeft===M&&k.cropTop===
N&&k.cropWidth===u&&k.cropHeight===F&&k.displayWidth===Z&&k.displayHeight===aa&&G.y.bytes.length===Ca&&G.u.bytes.length===Da&&G.v.bytes.length===Ea){x=G;break}}x||(x={format:{width:q,height:n,chromaWidth:z,chromaHeight:p,cropLeft:M,cropTop:N,cropWidth:u,cropHeight:F,displayWidth:Z,displayHeight:aa},y:{bytes:new Uint8Array(Ca),stride:c},u:{bytes:new Uint8Array(Da),stride:d},v:{bytes:new Uint8Array(Ea),stride:g}});ba(x.y.bytes,b,c,n,M,N,u,F,0);ba(x.u.bytes,e,d,p,xa,ya,za,Aa,128);ba(x.v.bytes,f,g,p,
xa,ya,za,Aa,128);a.frameBuffer=x},d:function(b,c,e,d,f,g,q,n,z,p,u){a.videoFormat={width:b,height:c,chromaWidth:e,chromaHeight:d,cropLeft:n,cropTop:z,cropWidth:g,cropHeight:q,displayWidth:p,displayHeight:u,fps:f};a.loadedMetadata=!0}};
(function(){function b(f){a.asm=f.exports;K=a.asm.e;ja();ka=a.asm.n;ma.unshift(a.asm.f);P--;a.monitorRunDependencies&&a.monitorRunDependencies(P);0==P&&(null!==Q&&(clearInterval(Q),Q=null),R&&(f=R,R=null,f()))}function c(f){b(f.instance)}function e(f){return sa().then(function(g){return WebAssembly.instantiate(g,d)}).then(function(g){return g}).then(f,function(g){H("failed to asynchronously prepare wasm: "+g);J(g)})}var d={a:Fa};P++;a.monitorRunDependencies&&a.monitorRunDependencies(P);if(a.instantiateWasm)try{return a.instantiateWasm(d,
b)}catch(f){return H("Module.instantiateWasm callback failed with error: "+f),!1}(function(){return I||"function"!=typeof WebAssembly.instantiateStreaming||pa()||S.startsWith("file://")||"function"!=typeof fetch?e(c):fetch(S,{credentials:"same-origin"}).then(function(f){return WebAssembly.instantiateStreaming(f,d).then(c,function(g){H("wasm streaming compile failed: "+g);H("falling back to ArrayBuffer instantiation");return e(c)})})})().catch(l);return{}})();
a.___wasm_call_ctors=function(){return(a.___wasm_call_ctors=a.asm.f).apply(null,arguments)};a._ogv_video_decoder_init=function(){return(a._ogv_video_decoder_init=a.asm.g).apply(null,arguments)};a._ogv_video_decoder_async=function(){return(a._ogv_video_decoder_async=a.asm.h).apply(null,arguments)};a._ogv_video_decoder_process_header=function(){return(a._ogv_video_decoder_process_header=a.asm.i).apply(null,arguments)};
a._ogv_video_decoder_process_frame=function(){return(a._ogv_video_decoder_process_frame=a.asm.j).apply(null,arguments)};a._ogv_video_decoder_destroy=function(){return(a._ogv_video_decoder_destroy=a.asm.k).apply(null,arguments)};a._malloc=function(){return(a._malloc=a.asm.l).apply(null,arguments)};a._free=function(){return(a._free=a.asm.m).apply(null,arguments)};var V;R=function Ga(){V||Ka();V||(R=Ga)};
function Ka(){function b(){if(!V&&(V=!0,a.calledRun=!0,!ha)){T(ma);ca(a);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;){var c=a.postRun.shift();na.unshift(c)}T(na)}}if(!(0<P)){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)oa();T(la);0<P||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);b()},1)):b())}}a.run=Ka;
if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();Ka();var W,La,X;"undefined"===typeof performance||"undefined"===typeof performance.now?X=Date.now:X=performance.now.bind(performance);function Y(b){var c=X();b=b();a.cpuTime+=X()-c;return b}a.loadedMetadata=!!da.videoFormat;a.videoFormat=da.videoFormat||null;a.frameBuffer=null;a.cpuTime=0;Object.defineProperty(a,"processing",{get:function(){return!1}});
a.init=function(b){Y(function(){a._ogv_video_decoder_init()});b()};a.processHeader=function(b,c){var e=Y(function(){var d=b.byteLength;W&&La>=d||(W&&a._free(W),La=d,W=a._malloc(La));var f=W;(new Uint8Array(K.buffer,f,d)).set(new Uint8Array(b));return a._ogv_video_decoder_process_header(f,d)});c(e)};a.s=[];
a.processFrame=function(b,c){function e(n){a._free(g);c(n)}var d=a._ogv_video_decoder_async(),f=b.byteLength,g=a._malloc(f);d&&a.s.push(e);var q=Y(function(){(new Uint8Array(K.buffer,g,f)).set(new Uint8Array(b));return a._ogv_video_decoder_process_frame(g,f)});d||e(q)};a.close=function(){};a.sync=function(){a._ogv_video_decoder_async()&&(a.s.push(function(){}),Y(function(){a._ogv_video_decoder_process_frame(0,0)}))};a.recycledFrames=[];
a.recycleFrame=function(b){var c=a.recycledFrames;c.push(b);16<c.length&&c.shift()};
return OGVDecoderVideoTheoraW.ready
}
);
})();
if (typeof exports === 'object' && typeof module === 'object')
module.exports = OGVDecoderVideoTheoraW;
else if (typeof define === 'function' && define['amd'])
define([], function() { return OGVDecoderVideoTheoraW; });
else if (typeof exports === 'object')
exports["OGVDecoderVideoTheoraW"] = OGVDecoderVideoTheoraW;
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
"use strict";var Module={};var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",function(data){onmessage({data:data})});var fs=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:function(f){(0,eval)(fs.readFileSync(f,"utf8"))},postMessage:function(msg){parentPort.postMessage(msg)},performance:global.performance||{now:function(){return Date.now()}}})}function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");if(ENVIRONMENT_IS_NODE){fs.writeSync(2,text+"\n");return}console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=((info,receiveInstance)=>{var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports});self.onmessage=(e=>{try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;if(typeof e.data.urlOrBlob=="string"){importScripts(e.data.urlOrBlob)}else{var objectUrl=URL.createObjectURL(e.data.urlOrBlob);importScripts(objectUrl);URL.revokeObjectURL(objectUrl)}OGVDecoderVideoVP8MTW(Module).then(function(instance){Module=instance})}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0,1);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["__emscripten_thread_exit"](result)}}catch(ex){if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["__emscripten_thread_exit"](ex.status)}}else{throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processProxyingQueue"){if(Module["_pthread_self"]()){Module["_emscripten_proxy_execute_queue"](e.data.queue)}Atomics.sub(HEAP32,e.data.queue>>2,1)}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}});
@@ -0,0 +1,44 @@
var OGVDecoderVideoVP8W = (() => {
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
return (
function(OGVDecoderVideoVP8W) {
OGVDecoderVideoVP8W = OGVDecoderVideoVP8W || {};
var a;a||(a=typeof OGVDecoderVideoVP8W !== 'undefined' ? OGVDecoderVideoVP8W : {});var aa,m;a.ready=new Promise(function(b,c){aa=b;m=c});var ba=a,ca=Object.assign({},a),ha="object"==typeof window,n="function"==typeof importScripts,t="",x,y,A,fs,B,C;
if("object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node)t=n?require("path").dirname(t)+"/":__dirname+"/",C=()=>{B||(fs=require("fs"),B=require("path"))},x=function(b,c){C();b=B.normalize(b);return fs.readFileSync(b,c?void 0:"utf8")},A=b=>{b=x(b,!0);b.buffer||(b=new Uint8Array(b));return b},y=(b,c,e)=>{C();b=B.normalize(b);fs.readFile(b,function(d,f){d?e(d):c(f.buffer)})},1<process.argv.length&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),
process.on("unhandledRejection",function(b){throw b;}),a.inspect=function(){return"[Emscripten Module object]"};else if(ha||n)n?t=self.location.href:"undefined"!=typeof document&&document.currentScript&&(t=document.currentScript.src),_scriptDir&&(t=_scriptDir),0!==t.indexOf("blob:")?t=t.substr(0,t.replace(/[?#].*/,"").lastIndexOf("/")+1):t="",x=b=>{var c=new XMLHttpRequest;c.open("GET",b,!1);c.send(null);return c.responseText},n&&(A=b=>{var c=new XMLHttpRequest;c.open("GET",b,!1);c.responseType="arraybuffer";
c.send(null);return new Uint8Array(c.response)}),y=(b,c,e)=>{var d=new XMLHttpRequest;d.open("GET",b,!0);d.responseType="arraybuffer";d.onload=()=>{200==d.status||0==d.status&&d.response?c(d.response):e()};d.onerror=e;d.send(null)};a.print||console.log.bind(console);var D=a.printErr||console.warn.bind(console);Object.assign(a,ca);ca=null;var ia=0,E;a.wasmBinary&&(E=a.wasmBinary);var noExitRuntime=a.noExitRuntime||!0;"object"!=typeof WebAssembly&&F("no native wasm support detected");
var G,ja=!1,ka,la;function ma(){var b=G.buffer;ka=b;a.HEAP8=new Int8Array(b);a.HEAP16=new Int16Array(b);a.HEAP32=new Int32Array(b);a.HEAPU8=la=new Uint8Array(b);a.HEAPU16=new Uint16Array(b);a.HEAPU32=new Uint32Array(b);a.HEAPF32=new Float32Array(b);a.HEAPF64=new Float64Array(b)}var na,oa=[],pa=[],qa=[];function ra(){var b=a.preRun.shift();oa.unshift(b)}var K=0,sa=null,L=null;a.preloadedImages={};a.preloadedAudios={};
function F(b){if(a.onAbort)a.onAbort(b);b="Aborted("+b+")";D(b);ja=!0;b=new WebAssembly.RuntimeError(b+". Build with -s ASSERTIONS=1 for more info.");m(b);throw b;}function ta(){return M.startsWith("data:application/octet-stream;base64,")}var M;M="ogv-decoder-video-vp8-wasm.wasm";if(!ta()){var ua=M;M=a.locateFile?a.locateFile(ua,t):t+ua}function va(){var b=M;try{if(b==M&&E)return new Uint8Array(E);if(A)return A(b);throw"both async and sync fetching of the wasm failed";}catch(c){F(c)}}
function wa(){if(!E&&(ha||n)){if("function"==typeof fetch&&!M.startsWith("file://"))return fetch(M,{credentials:"same-origin"}).then(function(b){if(!b.ok)throw"failed to load wasm binary file at '"+M+"'";return b.arrayBuffer()}).catch(function(){return va()});if(y)return new Promise(function(b,c){y(M,function(e){b(new Uint8Array(e))},c)})}return Promise.resolve().then(function(){return va()})}
function xa(b){for(;0<b.length;){var c=b.shift();if("function"==typeof c)c(a);else{var e=c.C;"number"==typeof e?void 0===c.A?N(e)():N(e)(c.A):e(void 0===c.A?null:c.A)}}}var O=[];function N(b){var c=O[b];c||(b>=O.length&&(O.length=b+1),O[b]=c=na.get(b));return c}
var Oa={e:function(){throw Infinity;},g:function(b,c,e){la.copyWithin(b,c,c+e)},f:function(b){var c=la.length;b>>>=0;if(2147483648<b)return!1;for(var e=1;4>=e;e*=2){var d=c*(1+.2/e);d=Math.min(d,b+100663296);var f=Math;d=Math.max(b,d);f=f.min.call(f,2147483648,d+(65536-d%65536)%65536);a:{try{G.grow(f-ka.byteLength+65535>>>16);ma();var g=1;break a}catch(l){}g=void 0}if(g)return!0}return!1},a:function(){return ia},d:Ja,i:Ka,j:La,h:Ma,c:Na,k:function(b,c,e,d,f,g,l,p,P,q,H,I,Q,R,da,ea){function fa(z,
h,u,ya,za,Aa,Ra,Sa,S){z.set(new Uint8Array(Ta,h,u*ya));var v,r;for(v=r=0;v<Aa;v++,r+=u)for(h=0;h<u;h++)z[r+h]=S;for(;v<Aa+Sa;v++,r+=u){for(h=0;h<za;h++)z[r+h]=S;for(h=za+Ra;h<u;h++)z[r+h]=S}for(;v<ya;v++,r+=u)for(h=0;h<u;h++)z[r+h]=S;return z}var Ta=G.buffer,k=a.videoFormat,Ba=(Q&-2)*P/l,Ca=(R&-2)*q/p,Da=H*P/l,Ea=I*q/p;H===k.cropWidth&&I===k.cropHeight&&(da=k.displayWidth,ea=k.displayHeight);for(var Fa=a.recycledFrames,w,Ga=p*c,Ha=q*d,Ia=q*g;0<Fa.length;){var J=Fa.shift();k=J.format;if(k.width===
l&&k.height===p&&k.chromaWidth===P&&k.chromaHeight===q&&k.cropLeft===Q&&k.cropTop===R&&k.cropWidth===H&&k.cropHeight===I&&k.displayWidth===da&&k.displayHeight===ea&&J.y.bytes.length===Ga&&J.u.bytes.length===Ha&&J.v.bytes.length===Ia){w=J;break}}w||(w={format:{width:l,height:p,chromaWidth:P,chromaHeight:q,cropLeft:Q,cropTop:R,cropWidth:H,cropHeight:I,displayWidth:da,displayHeight:ea},y:{bytes:new Uint8Array(Ga),stride:c},u:{bytes:new Uint8Array(Ha),stride:d},v:{bytes:new Uint8Array(Ia),stride:g}});
fa(w.y.bytes,b,c,p,Q,R,H,I,0);fa(w.u.bytes,e,d,q,Ba,Ca,Da,Ea,128);fa(w.v.bytes,f,g,q,Ba,Ca,Da,Ea,128);a.frameBuffer=w},b:function(b){ia=b}};
(function(){function b(f){a.asm=f.exports;G=a.asm.l;ma();na=a.asm.s;pa.unshift(a.asm.m);K--;a.monitorRunDependencies&&a.monitorRunDependencies(K);0==K&&(null!==sa&&(clearInterval(sa),sa=null),L&&(f=L,L=null,f()))}function c(f){b(f.instance)}function e(f){return wa().then(function(g){return WebAssembly.instantiate(g,d)}).then(function(g){return g}).then(f,function(g){D("failed to asynchronously prepare wasm: "+g);F(g)})}var d={a:Oa};K++;a.monitorRunDependencies&&a.monitorRunDependencies(K);if(a.instantiateWasm)try{return a.instantiateWasm(d,
b)}catch(f){return D("Module.instantiateWasm callback failed with error: "+f),!1}(function(){return E||"function"!=typeof WebAssembly.instantiateStreaming||ta()||M.startsWith("file://")||"function"!=typeof fetch?e(c):fetch(M,{credentials:"same-origin"}).then(function(f){return WebAssembly.instantiateStreaming(f,d).then(c,function(g){D("wasm streaming compile failed: "+g);D("falling back to ArrayBuffer instantiation");return e(c)})})})().catch(m);return{}})();
a.___wasm_call_ctors=function(){return(a.___wasm_call_ctors=a.asm.m).apply(null,arguments)};a._ogv_video_decoder_init=function(){return(a._ogv_video_decoder_init=a.asm.n).apply(null,arguments)};a._ogv_video_decoder_async=function(){return(a._ogv_video_decoder_async=a.asm.o).apply(null,arguments)};a._ogv_video_decoder_destroy=function(){return(a._ogv_video_decoder_destroy=a.asm.p).apply(null,arguments)};
a._ogv_video_decoder_process_header=function(){return(a._ogv_video_decoder_process_header=a.asm.q).apply(null,arguments)};a._ogv_video_decoder_process_frame=function(){return(a._ogv_video_decoder_process_frame=a.asm.r).apply(null,arguments)};a._malloc=function(){return(a._malloc=a.asm.t).apply(null,arguments)};a._free=function(){return(a._free=a.asm.u).apply(null,arguments)};
var T=a._setThrew=function(){return(T=a._setThrew=a.asm.v).apply(null,arguments)},U=a.stackSave=function(){return(U=a.stackSave=a.asm.w).apply(null,arguments)},V=a.stackRestore=function(){return(V=a.stackRestore=a.asm.x).apply(null,arguments)},Pa=a.dynCall_iiiij=function(){return(Pa=a.dynCall_iiiij=a.asm.y).apply(null,arguments)};function Na(b,c,e,d,f){var g=U();try{N(b)(c,e,d,f)}catch(l){V(g);if(l!==l+0)throw l;T(1,0)}}
function Ja(b,c,e){var d=U();try{return N(b)(c,e)}catch(f){V(d);if(f!==f+0)throw f;T(1,0)}}function Ka(b,c,e,d){var f=U();try{return N(b)(c,e,d)}catch(g){V(f);if(g!==g+0)throw g;T(1,0)}}function Ma(b,c){var e=U();try{N(b)(c)}catch(d){V(e);if(d!==d+0)throw d;T(1,0)}}function La(b,c,e,d,f,g){var l=U();try{return Pa(b,c,e,d,f,g)}catch(p){V(l);if(p!==p+0)throw p;T(1,0)}}var W;L=function Qa(){W||Ua();W||(L=Qa)};
function Ua(){function b(){if(!W&&(W=!0,a.calledRun=!0,!ja)){xa(pa);aa(a);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;){var c=a.postRun.shift();qa.unshift(c)}xa(qa)}}if(!(0<K)){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)ra();xa(oa);0<K||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);b()},1)):b())}}a.run=Ua;
if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();Ua();var X,Va,Y;"undefined"===typeof performance||"undefined"===typeof performance.now?Y=Date.now:Y=performance.now.bind(performance);function Z(b){var c=Y();b=b();a.cpuTime+=Y()-c;return b}a.loadedMetadata=!!ba.videoFormat;a.videoFormat=ba.videoFormat||null;a.frameBuffer=null;a.cpuTime=0;Object.defineProperty(a,"processing",{get:function(){return!1}});
a.init=function(b){Z(function(){a._ogv_video_decoder_init()});b()};a.processHeader=function(b,c){var e=Z(function(){var d=b.byteLength;X&&Va>=d||(X&&a._free(X),Va=d,X=a._malloc(Va));var f=X;(new Uint8Array(G.buffer,f,d)).set(new Uint8Array(b));return a._ogv_video_decoder_process_header(f,d)});c(e)};a.B=[];
a.processFrame=function(b,c){function e(p){a._free(g);c(p)}var d=a._ogv_video_decoder_async(),f=b.byteLength,g=a._malloc(f);d&&a.B.push(e);var l=Z(function(){(new Uint8Array(G.buffer,g,f)).set(new Uint8Array(b));return a._ogv_video_decoder_process_frame(g,f)});d||e(l)};a.close=function(){};a.sync=function(){a._ogv_video_decoder_async()&&(a.B.push(function(){}),Z(function(){a._ogv_video_decoder_process_frame(0,0)}))};a.recycledFrames=[];
a.recycleFrame=function(b){var c=a.recycledFrames;c.push(b);16<c.length&&c.shift()};
return OGVDecoderVideoVP8W.ready
}
);
})();
if (typeof exports === 'object' && typeof module === 'object')
module.exports = OGVDecoderVideoVP8W;
else if (typeof define === 'function' && define['amd'])
define([], function() { return OGVDecoderVideoVP8W; });
else if (typeof exports === 'object')
exports["OGVDecoderVideoVP8W"] = OGVDecoderVideoVP8W;
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
"use strict";var Module={};var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",function(data){onmessage({data:data})});var fs=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:function(f){(0,eval)(fs.readFileSync(f,"utf8"))},postMessage:function(msg){parentPort.postMessage(msg)},performance:global.performance||{now:function(){return Date.now()}}})}function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");if(ENVIRONMENT_IS_NODE){fs.writeSync(2,text+"\n");return}console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=((info,receiveInstance)=>{var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports});self.onmessage=(e=>{try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;if(typeof e.data.urlOrBlob=="string"){importScripts(e.data.urlOrBlob)}else{var objectUrl=URL.createObjectURL(e.data.urlOrBlob);importScripts(objectUrl);URL.revokeObjectURL(objectUrl)}OGVDecoderVideoVP9MTW(Module).then(function(instance){Module=instance})}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.threadInfoStruct,0,0,1);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInit();try{var result=Module["invokeEntryPoint"](e.data.start_routine,e.data.arg);if(Module["keepRuntimeAlive"]()){Module["PThread"].setExitStatus(result)}else{Module["__emscripten_thread_exit"](result)}}catch(ex){if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["__emscripten_thread_exit"](ex.status)}}else{throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processProxyingQueue"){if(Module["_pthread_self"]()){Module["_emscripten_proxy_execute_queue"](e.data.queue)}Atomics.sub(HEAP32,e.data.queue>>2,1)}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}});
@@ -0,0 +1,45 @@
var OGVDecoderVideoVP9W = (() => {
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
return (
function(OGVDecoderVideoVP9W) {
OGVDecoderVideoVP9W = OGVDecoderVideoVP9W || {};
var a;a||(a=typeof OGVDecoderVideoVP9W !== 'undefined' ? OGVDecoderVideoVP9W : {});var aa,n;a.ready=new Promise(function(b,c){aa=b;n=c});var ba=a,ca=Object.assign({},a),ha="object"==typeof window,p="function"==typeof importScripts,q="",v,w,x,fs,z,D;
if("object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node)q=p?require("path").dirname(q)+"/":__dirname+"/",D=()=>{z||(fs=require("fs"),z=require("path"))},v=function(b,c){D();b=z.normalize(b);return fs.readFileSync(b,c?void 0:"utf8")},x=b=>{b=v(b,!0);b.buffer||(b=new Uint8Array(b));return b},w=(b,c,e)=>{D();b=z.normalize(b);fs.readFile(b,function(d,f){d?e(d):c(f.buffer)})},1<process.argv.length&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),
process.on("unhandledRejection",function(b){throw b;}),a.inspect=function(){return"[Emscripten Module object]"};else if(ha||p)p?q=self.location.href:"undefined"!=typeof document&&document.currentScript&&(q=document.currentScript.src),_scriptDir&&(q=_scriptDir),0!==q.indexOf("blob:")?q=q.substr(0,q.replace(/[?#].*/,"").lastIndexOf("/")+1):q="",v=b=>{var c=new XMLHttpRequest;c.open("GET",b,!1);c.send(null);return c.responseText},p&&(x=b=>{var c=new XMLHttpRequest;c.open("GET",b,!1);c.responseType="arraybuffer";
c.send(null);return new Uint8Array(c.response)}),w=(b,c,e)=>{var d=new XMLHttpRequest;d.open("GET",b,!0);d.responseType="arraybuffer";d.onload=()=>{200==d.status||0==d.status&&d.response?c(d.response):e()};d.onerror=e;d.send(null)};a.print||console.log.bind(console);var F=a.printErr||console.warn.bind(console);Object.assign(a,ca);ca=null;var ia=0,G;a.wasmBinary&&(G=a.wasmBinary);var noExitRuntime=a.noExitRuntime||!0;"object"!=typeof WebAssembly&&H("no native wasm support detected");
var I,ja=!1,ka,la;function ma(){var b=I.buffer;ka=b;a.HEAP8=new Int8Array(b);a.HEAP16=new Int16Array(b);a.HEAP32=new Int32Array(b);a.HEAPU8=la=new Uint8Array(b);a.HEAPU16=new Uint16Array(b);a.HEAPU32=new Uint32Array(b);a.HEAPF32=new Float32Array(b);a.HEAPF64=new Float64Array(b)}var na,oa=[],pa=[],qa=[];function ra(){var b=a.preRun.shift();oa.unshift(b)}var L=0,sa=null,M=null;a.preloadedImages={};a.preloadedAudios={};
function H(b){if(a.onAbort)a.onAbort(b);b="Aborted("+b+")";F(b);ja=!0;b=new WebAssembly.RuntimeError(b+". Build with -s ASSERTIONS=1 for more info.");n(b);throw b;}function ta(){return N.startsWith("data:application/octet-stream;base64,")}var N;N="ogv-decoder-video-vp9-wasm.wasm";if(!ta()){var ua=N;N=a.locateFile?a.locateFile(ua,q):q+ua}function va(){var b=N;try{if(b==N&&G)return new Uint8Array(G);if(x)return x(b);throw"both async and sync fetching of the wasm failed";}catch(c){H(c)}}
function wa(){if(!G&&(ha||p)){if("function"==typeof fetch&&!N.startsWith("file://"))return fetch(N,{credentials:"same-origin"}).then(function(b){if(!b.ok)throw"failed to load wasm binary file at '"+N+"'";return b.arrayBuffer()}).catch(function(){return va()});if(w)return new Promise(function(b,c){w(N,function(e){b(new Uint8Array(e))},c)})}return Promise.resolve().then(function(){return va()})}
function xa(b){for(;0<b.length;){var c=b.shift();if("function"==typeof c)c(a);else{var e=c.D;"number"==typeof e?void 0===c.B?O(e)():O(e)(c.B):e(void 0===c.B?null:c.B)}}}var P=[];function O(b){var c=P[b];c||(b>=P.length&&(P.length=b+1),P[b]=c=na.get(b));return c}
var Ra={k:function(){throw Infinity;},m:function(b,c,e){la.copyWithin(b,c,c+e)},l:function(b){var c=la.length;b>>>=0;if(2147483648<b)return!1;for(var e=1;4>=e;e*=2){var d=c*(1+.2/e);d=Math.min(d,b+100663296);var f=Math;d=Math.max(b,d);f=f.min.call(f,2147483648,d+(65536-d%65536)%65536);a:{try{I.grow(f-ka.byteLength+65535>>>16);ma();var g=1;break a}catch(h){}g=void 0}if(g)return!0}return!1},a:function(){return ia},d:Ja,f:Ka,i:La,g:Ma,e:Na,c:Oa,j:Pa,h:Qa,n:function(b,c,e,d,f,g,h,l,r,t,u,J,Q,R,da,ea){function fa(E,
k,A,ya,za,Aa,Ta,Ua,S){E.set(new Uint8Array(Va,k,A*ya));var B,y;for(B=y=0;B<Aa;B++,y+=A)for(k=0;k<A;k++)E[y+k]=S;for(;B<Aa+Ua;B++,y+=A){for(k=0;k<za;k++)E[y+k]=S;for(k=za+Ta;k<A;k++)E[y+k]=S}for(;B<ya;B++,y+=A)for(k=0;k<A;k++)E[y+k]=S;return E}var Va=I.buffer,m=a.videoFormat,Ba=(Q&-2)*r/h,Ca=(R&-2)*t/l,Da=u*r/h,Ea=J*t/l;u===m.cropWidth&&J===m.cropHeight&&(da=m.displayWidth,ea=m.displayHeight);for(var Fa=a.recycledFrames,C,Ga=l*c,Ha=t*d,Ia=t*g;0<Fa.length;){var K=Fa.shift();m=K.format;if(m.width===
h&&m.height===l&&m.chromaWidth===r&&m.chromaHeight===t&&m.cropLeft===Q&&m.cropTop===R&&m.cropWidth===u&&m.cropHeight===J&&m.displayWidth===da&&m.displayHeight===ea&&K.y.bytes.length===Ga&&K.u.bytes.length===Ha&&K.v.bytes.length===Ia){C=K;break}}C||(C={format:{width:h,height:l,chromaWidth:r,chromaHeight:t,cropLeft:Q,cropTop:R,cropWidth:u,cropHeight:J,displayWidth:da,displayHeight:ea},y:{bytes:new Uint8Array(Ga),stride:c},u:{bytes:new Uint8Array(Ha),stride:d},v:{bytes:new Uint8Array(Ia),stride:g}});
fa(C.y.bytes,b,c,l,Q,R,u,J,0);fa(C.u.bytes,e,d,t,Ba,Ca,Da,Ea,128);fa(C.v.bytes,f,g,t,Ba,Ca,Da,Ea,128);a.frameBuffer=C},b:function(b){ia=b}};
(function(){function b(f){a.asm=f.exports;I=a.asm.o;ma();na=a.asm.v;pa.unshift(a.asm.p);L--;a.monitorRunDependencies&&a.monitorRunDependencies(L);0==L&&(null!==sa&&(clearInterval(sa),sa=null),M&&(f=M,M=null,f()))}function c(f){b(f.instance)}function e(f){return wa().then(function(g){return WebAssembly.instantiate(g,d)}).then(function(g){return g}).then(f,function(g){F("failed to asynchronously prepare wasm: "+g);H(g)})}var d={a:Ra};L++;a.monitorRunDependencies&&a.monitorRunDependencies(L);if(a.instantiateWasm)try{return a.instantiateWasm(d,
b)}catch(f){return F("Module.instantiateWasm callback failed with error: "+f),!1}(function(){return G||"function"!=typeof WebAssembly.instantiateStreaming||ta()||N.startsWith("file://")||"function"!=typeof fetch?e(c):fetch(N,{credentials:"same-origin"}).then(function(f){return WebAssembly.instantiateStreaming(f,d).then(c,function(g){F("wasm streaming compile failed: "+g);F("falling back to ArrayBuffer instantiation");return e(c)})})})().catch(n);return{}})();
a.___wasm_call_ctors=function(){return(a.___wasm_call_ctors=a.asm.p).apply(null,arguments)};a._ogv_video_decoder_init=function(){return(a._ogv_video_decoder_init=a.asm.q).apply(null,arguments)};a._ogv_video_decoder_async=function(){return(a._ogv_video_decoder_async=a.asm.r).apply(null,arguments)};a._ogv_video_decoder_destroy=function(){return(a._ogv_video_decoder_destroy=a.asm.s).apply(null,arguments)};
a._ogv_video_decoder_process_header=function(){return(a._ogv_video_decoder_process_header=a.asm.t).apply(null,arguments)};a._ogv_video_decoder_process_frame=function(){return(a._ogv_video_decoder_process_frame=a.asm.u).apply(null,arguments)};a._malloc=function(){return(a._malloc=a.asm.w).apply(null,arguments)};a._free=function(){return(a._free=a.asm.x).apply(null,arguments)};
var T=a._setThrew=function(){return(T=a._setThrew=a.asm.y).apply(null,arguments)},U=a.stackSave=function(){return(U=a.stackSave=a.asm.z).apply(null,arguments)},V=a.stackRestore=function(){return(V=a.stackRestore=a.asm.A).apply(null,arguments)};function La(b,c,e,d,f){var g=U();try{return O(b)(c,e,d,f)}catch(h){V(g);if(h!==h+0)throw h;T(1,0)}}function Oa(b,c,e,d,f){var g=U();try{O(b)(c,e,d,f)}catch(h){V(g);if(h!==h+0)throw h;T(1,0)}}
function Qa(b,c,e,d,f,g,h,l,r){var t=U();try{O(b)(c,e,d,f,g,h,l,r)}catch(u){V(t);if(u!==u+0)throw u;T(1,0)}}function Ma(b,c,e,d,f,g){var h=U();try{return O(b)(c,e,d,f,g)}catch(l){V(h);if(l!==l+0)throw l;T(1,0)}}function Ka(b,c,e,d){var f=U();try{return O(b)(c,e,d)}catch(g){V(f);if(g!==g+0)throw g;T(1,0)}}function Pa(b,c,e,d,f,g,h){var l=U();try{O(b)(c,e,d,f,g,h)}catch(r){V(l);if(r!==r+0)throw r;T(1,0)}}function Ja(b,c,e){var d=U();try{return O(b)(c,e)}catch(f){V(d);if(f!==f+0)throw f;T(1,0)}}
function Na(b,c){var e=U();try{O(b)(c)}catch(d){V(e);if(d!==d+0)throw d;T(1,0)}}var W;M=function Sa(){W||Wa();W||(M=Sa)};
function Wa(){function b(){if(!W&&(W=!0,a.calledRun=!0,!ja)){xa(pa);aa(a);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;){var c=a.postRun.shift();qa.unshift(c)}xa(qa)}}if(!(0<L)){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)ra();xa(oa);0<L||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);b()},1)):b())}}a.run=Wa;
if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();Wa();var X,Xa,Y;"undefined"===typeof performance||"undefined"===typeof performance.now?Y=Date.now:Y=performance.now.bind(performance);function Z(b){var c=Y();b=b();a.cpuTime+=Y()-c;return b}a.loadedMetadata=!!ba.videoFormat;a.videoFormat=ba.videoFormat||null;a.frameBuffer=null;a.cpuTime=0;Object.defineProperty(a,"processing",{get:function(){return!1}});
a.init=function(b){Z(function(){a._ogv_video_decoder_init()});b()};a.processHeader=function(b,c){var e=Z(function(){var d=b.byteLength;X&&Xa>=d||(X&&a._free(X),Xa=d,X=a._malloc(Xa));var f=X;(new Uint8Array(I.buffer,f,d)).set(new Uint8Array(b));return a._ogv_video_decoder_process_header(f,d)});c(e)};a.C=[];
a.processFrame=function(b,c){function e(l){a._free(g);c(l)}var d=a._ogv_video_decoder_async(),f=b.byteLength,g=a._malloc(f);d&&a.C.push(e);var h=Z(function(){(new Uint8Array(I.buffer,g,f)).set(new Uint8Array(b));return a._ogv_video_decoder_process_frame(g,f)});d||e(h)};a.close=function(){};a.sync=function(){a._ogv_video_decoder_async()&&(a.C.push(function(){}),Z(function(){a._ogv_video_decoder_process_frame(0,0)}))};a.recycledFrames=[];
a.recycleFrame=function(b){var c=a.recycledFrames;c.push(b);16<c.length&&c.shift()};
return OGVDecoderVideoVP9W.ready
}
);
})();
if (typeof exports === 'object' && typeof module === 'object')
module.exports = OGVDecoderVideoVP9W;
else if (typeof define === 'function' && define['amd'])
define([], function() { return OGVDecoderVideoVP9W; });
else if (typeof exports === 'object')
exports["OGVDecoderVideoVP9W"] = OGVDecoderVideoVP9W;
@@ -0,0 +1,43 @@
var OGVDemuxerOggW = (() => {
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
return (
function(OGVDemuxerOggW) {
OGVDemuxerOggW = OGVDemuxerOggW || {};
var a;a||(a=typeof OGVDemuxerOggW !== 'undefined' ? OGVDemuxerOggW : {});var h,k;a.ready=new Promise(function(b,c){h=b;k=c});var l=Object.assign({},a),m="object"==typeof window,n="function"==typeof importScripts,p="",q,r,t,fs,u,v;
if("object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node)p=n?require("path").dirname(p)+"/":__dirname+"/",v=()=>{u||(fs=require("fs"),u=require("path"))},q=function(b,c){v();b=u.normalize(b);return fs.readFileSync(b,c?void 0:"utf8")},t=b=>{b=q(b,!0);b.buffer||(b=new Uint8Array(b));return b},r=(b,c,d)=>{v();b=u.normalize(b);fs.readFile(b,function(e,f){e?d(e):c(f.buffer)})},1<process.argv.length&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),
process.on("unhandledRejection",function(b){throw b;}),a.inspect=function(){return"[Emscripten Module object]"};else if(m||n)n?p=self.location.href:"undefined"!=typeof document&&document.currentScript&&(p=document.currentScript.src),_scriptDir&&(p=_scriptDir),0!==p.indexOf("blob:")?p=p.substr(0,p.replace(/[?#].*/,"").lastIndexOf("/")+1):p="",q=b=>{var c=new XMLHttpRequest;c.open("GET",b,!1);c.send(null);return c.responseText},n&&(t=b=>{var c=new XMLHttpRequest;c.open("GET",b,!1);c.responseType="arraybuffer";
c.send(null);return new Uint8Array(c.response)}),r=(b,c,d)=>{var e=new XMLHttpRequest;e.open("GET",b,!0);e.responseType="arraybuffer";e.onload=()=>{200==e.status||0==e.status&&e.response?c(e.response):d()};e.onerror=d;e.send(null)};a.print||console.log.bind(console);var w=a.printErr||console.warn.bind(console);Object.assign(a,l);l=null;var x;a.wasmBinary&&(x=a.wasmBinary);var noExitRuntime=a.noExitRuntime||!0;"object"!=typeof WebAssembly&&y("no native wasm support detected");var z,A=!1;
"undefined"!=typeof TextDecoder&&new TextDecoder("utf8");var B,C,D;function E(){var b=z.buffer;B=b;a.HEAP8=new Int8Array(b);a.HEAP16=new Int16Array(b);a.HEAP32=D=new Int32Array(b);a.HEAPU8=C=new Uint8Array(b);a.HEAPU16=new Uint16Array(b);a.HEAPU32=new Uint32Array(b);a.HEAPF32=new Float32Array(b);a.HEAPF64=new Float64Array(b)}var F,G=[],H=[],I=[];function aa(){var b=a.preRun.shift();G.unshift(b)}var J=0,K=null,L=null;a.preloadedImages={};a.preloadedAudios={};
function y(b){if(a.onAbort)a.onAbort(b);b="Aborted("+b+")";w(b);A=!0;b=new WebAssembly.RuntimeError(b+". Build with -s ASSERTIONS=1 for more info.");k(b);throw b;}function M(){return N.startsWith("data:application/octet-stream;base64,")}var N;N="ogv-demuxer-ogg-wasm.wasm";if(!M()){var O=N;N=a.locateFile?a.locateFile(O,p):p+O}function P(){var b=N;try{if(b==N&&x)return new Uint8Array(x);if(t)return t(b);throw"both async and sync fetching of the wasm failed";}catch(c){y(c)}}
function ba(){if(!x&&(m||n)){if("function"==typeof fetch&&!N.startsWith("file://"))return fetch(N,{credentials:"same-origin"}).then(function(b){if(!b.ok)throw"failed to load wasm binary file at '"+N+"'";return b.arrayBuffer()}).catch(function(){return P()});if(r)return new Promise(function(b,c){r(N,function(d){b(new Uint8Array(d))},c)})}return Promise.resolve().then(function(){return P()})}
function Q(b){for(;0<b.length;){var c=b.shift();if("function"==typeof c)c(a);else{var d=c.B;"number"==typeof d?void 0===c.v?R(d)():R(d)(c.v):d(void 0===c.v?null:c.v)}}}var S=[];function R(b){var c=S[b];c||(b>=S.length&&(S.length=b+1),S[b]=c=F.get(b));return c}
var T={},ca={f:function(b,c,d){C.copyWithin(b,c,c+d)},d:function(b){var c=C.length;b>>>=0;if(2147483648<b)return!1;for(var d=1;4>=d;d*=2){var e=c*(1+.2/d);e=Math.min(e,b+100663296);var f=Math;e=Math.max(b,e);f=f.min.call(f,2147483648,e+(65536-e%65536)%65536);a:{try{z.grow(f-B.byteLength+65535>>>16);E();var g=1;break a}catch(ea){}g=void 0}if(g)return!0}return!1},e:function(b,c,d,e){b=T.C(b);c=T.A(b,c,d);D[e>>2]=c;return 0},a:function(b,c,d,e){var f=z.buffer;a.audioPackets.push({data:f.slice?f.slice(b,
b+c):(new Uint8Array(new Uint8Array(f,b,c))).buffer,timestamp:d,discardPadding:e})},c:function(b,c){function d(e){for(var f="",g=new Uint8Array(z.buffer);0!=g[e];e++)f+=String.fromCharCode(g[e]);return f}b&&(a.videoCodec=d(b));c&&(a.audioCodec=d(c));b=a._ogv_demuxer_media_duration();a.duration=0<=b?b:NaN;a.loadedMetadata=!0},b:function(b,c,d,e,f){var g=z.buffer;a.videoPackets.push({data:g.slice?g.slice(b,b+c):(new Uint8Array(new Uint8Array(g,b,c))).buffer,timestamp:d,keyframeTimestamp:e,isKeyframe:!!f})}};
(function(){function b(f){a.asm=f.exports;z=a.asm.g;E();F=a.asm.s;H.unshift(a.asm.h);J--;a.monitorRunDependencies&&a.monitorRunDependencies(J);0==J&&(null!==K&&(clearInterval(K),K=null),L&&(f=L,L=null,f()))}function c(f){b(f.instance)}function d(f){return ba().then(function(g){return WebAssembly.instantiate(g,e)}).then(function(g){return g}).then(f,function(g){w("failed to asynchronously prepare wasm: "+g);y(g)})}var e={a:ca};J++;a.monitorRunDependencies&&a.monitorRunDependencies(J);if(a.instantiateWasm)try{return a.instantiateWasm(e,
b)}catch(f){return w("Module.instantiateWasm callback failed with error: "+f),!1}(function(){return x||"function"!=typeof WebAssembly.instantiateStreaming||M()||N.startsWith("file://")||"function"!=typeof fetch?d(c):fetch(N,{credentials:"same-origin"}).then(function(f){return WebAssembly.instantiateStreaming(f,e).then(c,function(g){w("wasm streaming compile failed: "+g);w("falling back to ArrayBuffer instantiation");return d(c)})})})().catch(k);return{}})();
a.___wasm_call_ctors=function(){return(a.___wasm_call_ctors=a.asm.h).apply(null,arguments)};a._ogv_demuxer_init=function(){return(a._ogv_demuxer_init=a.asm.i).apply(null,arguments)};a._ogv_demuxer_receive_input=function(){return(a._ogv_demuxer_receive_input=a.asm.j).apply(null,arguments)};a._ogv_demuxer_process=function(){return(a._ogv_demuxer_process=a.asm.k).apply(null,arguments)};a._ogv_demuxer_destroy=function(){return(a._ogv_demuxer_destroy=a.asm.l).apply(null,arguments)};
a._ogv_demuxer_media_length=function(){return(a._ogv_demuxer_media_length=a.asm.m).apply(null,arguments)};a._ogv_demuxer_media_duration=function(){return(a._ogv_demuxer_media_duration=a.asm.n).apply(null,arguments)};a._ogv_demuxer_seekable=function(){return(a._ogv_demuxer_seekable=a.asm.o).apply(null,arguments)};a._ogv_demuxer_keypoint_offset=function(){return(a._ogv_demuxer_keypoint_offset=a.asm.p).apply(null,arguments)};
a._ogv_demuxer_seek_to_keypoint=function(){return(a._ogv_demuxer_seek_to_keypoint=a.asm.q).apply(null,arguments)};a._ogv_demuxer_flush=function(){return(a._ogv_demuxer_flush=a.asm.r).apply(null,arguments)};a._malloc=function(){return(a._malloc=a.asm.t).apply(null,arguments)};a._free=function(){return(a._free=a.asm.u).apply(null,arguments)};var U;L=function da(){U||V();U||(L=da)};
function V(){function b(){if(!U&&(U=!0,a.calledRun=!0,!A)){Q(H);h(a);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;){var c=a.postRun.shift();I.unshift(c)}Q(I)}}if(!(0<J)){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)aa();Q(G);0<J||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);b()},1)):b())}}a.run=V;
if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();V();var W,X,Y;"undefined"===typeof performance||"undefined"===typeof performance.now?Y=Date.now:Y=performance.now.bind(performance);function Z(b){var c=Y();b=b();c=Y()-c;a.cpuTime+=c;return b}a.loadedMetadata=!1;a.videoCodec=null;a.audioCodec=null;a.duration=NaN;a.onseek=null;a.cpuTime=0;a.audioPackets=[];Object.defineProperty(a,"hasAudio",{get:function(){return a.loadedMetadata&&a.audioCodec}});
Object.defineProperty(a,"audioReady",{get:function(){return 0<a.audioPackets.length}});Object.defineProperty(a,"audioTimestamp",{get:function(){return 0<a.audioPackets.length?a.audioPackets[0].timestamp:-1}});a.videoPackets=[];Object.defineProperty(a,"hasVideo",{get:function(){return a.loadedMetadata&&a.videoCodec}});Object.defineProperty(a,"frameReady",{get:function(){return 0<a.videoPackets.length}});
Object.defineProperty(a,"frameTimestamp",{get:function(){return 0<a.videoPackets.length?a.videoPackets[0].timestamp:-1}});Object.defineProperty(a,"keyframeTimestamp",{get:function(){return 0<a.videoPackets.length?a.videoPackets[0].keyframeTimestamp:-1}});Object.defineProperty(a,"nextKeyframeTimestamp",{get:function(){for(var b=0;b<a.videoPackets.length;b++){var c=a.videoPackets[b];if(c.isKeyframe)return c.timestamp}return-1}});Object.defineProperty(a,"processing",{get:function(){return!1}});
Object.defineProperty(a,"seekable",{get:function(){return!!a._ogv_demuxer_seekable()}});a.init=function(b){Z(function(){a._ogv_demuxer_init()});b()};a.receiveInput=function(b,c){Z(function(){var d=b.byteLength;W&&X>=d||(W&&a._free(W),X=d,W=a._malloc(X));var e=W;(new Uint8Array(z.buffer,e,d)).set(new Uint8Array(b));a._ogv_demuxer_receive_input(e,d)});c()};a.process=function(b){var c=Z(function(){return a._ogv_demuxer_process()});b(!!c)};
a.dequeueVideoPacket=function(b){if(a.videoPackets.length){var c=a.videoPackets.shift().data;b(c)}else b(null)};a.dequeueAudioPacket=function(b){if(a.audioPackets.length){var c=a.audioPackets.shift();b(c.data,c.discardPadding)}else b(null)};a.getKeypointOffset=function(b,c){var d=Z(function(){return a._ogv_demuxer_keypoint_offset(1E3*b)});c(d)};
a.seekToKeypoint=function(b,c){var d=Z(function(){return a._ogv_demuxer_seek_to_keypoint(1E3*b)});d&&(a.audioPackets.splice(0,a.audioPackets.length),a.videoPackets.splice(0,a.videoPackets.length));c(!!d)};a.flush=function(b){Z(function(){a.audioPackets.splice(0,a.audioPackets.length);a.videoPackets.splice(0,a.videoPackets.length);a._ogv_demuxer_flush()});b()};a.close=function(){};
return OGVDemuxerOggW.ready
}
);
})();
if (typeof exports === 'object' && typeof module === 'object')
module.exports = OGVDemuxerOggW;
else if (typeof define === 'function' && define['amd'])
define([], function() { return OGVDemuxerOggW; });
else if (typeof exports === 'object')
exports["OGVDemuxerOggW"] = OGVDemuxerOggW;
Binary file not shown.
@@ -0,0 +1,47 @@
var OGVDemuxerWebMW = (() => {
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
return (
function(OGVDemuxerWebMW) {
OGVDemuxerWebMW = OGVDemuxerWebMW || {};
var a;a||(a=typeof OGVDemuxerWebMW !== 'undefined' ? OGVDemuxerWebMW : {});var h,k;a.ready=new Promise(function(b,c){h=b;k=c});var l=Object.assign({},a),n="object"==typeof window,p="function"==typeof importScripts,q="",r,t,u,fs,v,w;
if("object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node)q=p?require("path").dirname(q)+"/":__dirname+"/",w=()=>{v||(fs=require("fs"),v=require("path"))},r=function(b,c){w();b=v.normalize(b);return fs.readFileSync(b,c?void 0:"utf8")},u=b=>{b=r(b,!0);b.buffer||(b=new Uint8Array(b));return b},t=(b,c,d)=>{w();b=v.normalize(b);fs.readFile(b,function(e,f){e?d(e):c(f.buffer)})},1<process.argv.length&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),
process.on("unhandledRejection",function(b){throw b;}),a.inspect=function(){return"[Emscripten Module object]"};else if(n||p)p?q=self.location.href:"undefined"!=typeof document&&document.currentScript&&(q=document.currentScript.src),_scriptDir&&(q=_scriptDir),0!==q.indexOf("blob:")?q=q.substr(0,q.replace(/[?#].*/,"").lastIndexOf("/")+1):q="",r=b=>{var c=new XMLHttpRequest;c.open("GET",b,!1);c.send(null);return c.responseText},p&&(u=b=>{var c=new XMLHttpRequest;c.open("GET",b,!1);c.responseType="arraybuffer";
c.send(null);return new Uint8Array(c.response)}),t=(b,c,d)=>{var e=new XMLHttpRequest;e.open("GET",b,!0);e.responseType="arraybuffer";e.onload=()=>{200==e.status||0==e.status&&e.response?c(e.response):d()};e.onerror=d;e.send(null)};var aa=a.print||console.log.bind(console),A=a.printErr||console.warn.bind(console);Object.assign(a,l);l=null;var B;a.wasmBinary&&(B=a.wasmBinary);var noExitRuntime=a.noExitRuntime||!0;"object"!=typeof WebAssembly&&C("no native wasm support detected");
var D,E=!1,F="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0;
function H(b,c,d){var e=c+d;for(d=c;b[d]&&!(d>=e);)++d;if(16<d-c&&b.buffer&&F)return F.decode(b.subarray(c,d));for(e="";c<d;){var f=b[c++];if(f&128){var g=b[c++]&63;if(192==(f&224))e+=String.fromCharCode((f&31)<<6|g);else{var m=b[c++]&63;f=224==(f&240)?(f&15)<<12|g<<6|m:(f&7)<<18|g<<12|m<<6|b[c++]&63;65536>f?e+=String.fromCharCode(f):(f-=65536,e+=String.fromCharCode(55296|f>>10,56320|f&1023))}}else e+=String.fromCharCode(f)}return e}function I(b){return b?H(J,b,void 0):""}var K,J,L;
function M(){var b=D.buffer;K=b;a.HEAP8=new Int8Array(b);a.HEAP16=new Int16Array(b);a.HEAP32=L=new Int32Array(b);a.HEAPU8=J=new Uint8Array(b);a.HEAPU16=new Uint16Array(b);a.HEAPU32=new Uint32Array(b);a.HEAPF32=new Float32Array(b);a.HEAPF64=new Float64Array(b)}var N,ba=[],ca=[],da=[];function ea(){var b=a.preRun.shift();ba.unshift(b)}var O=0,P=null,Q=null;a.preloadedImages={};a.preloadedAudios={};
function C(b){if(a.onAbort)a.onAbort(b);b="Aborted("+b+")";A(b);E=!0;b=new WebAssembly.RuntimeError(b+". Build with -s ASSERTIONS=1 for more info.");k(b);throw b;}function fa(){return R.startsWith("data:application/octet-stream;base64,")}var R;R="ogv-demuxer-webm-wasm.wasm";if(!fa()){var ha=R;R=a.locateFile?a.locateFile(ha,q):q+ha}function ia(){var b=R;try{if(b==R&&B)return new Uint8Array(B);if(u)return u(b);throw"both async and sync fetching of the wasm failed";}catch(c){C(c)}}
function ja(){if(!B&&(n||p)){if("function"==typeof fetch&&!R.startsWith("file://"))return fetch(R,{credentials:"same-origin"}).then(function(b){if(!b.ok)throw"failed to load wasm binary file at '"+R+"'";return b.arrayBuffer()}).catch(function(){return ia()});if(t)return new Promise(function(b,c){t(R,function(d){b(new Uint8Array(d))},c)})}return Promise.resolve().then(function(){return ia()})}
function S(b){for(;0<b.length;){var c=b.shift();if("function"==typeof c)c(a);else{var d=c.B;"number"==typeof d?void 0===c.A?ka(d)():ka(d)(c.A):d(void 0===c.A?null:c.A)}}}var T=[];function ka(b){var c=T[b];c||(b>=T.length&&(T.length=b+1),T[b]=c=N.get(b));return c}
var la=[null,[],[]],ma={a:function(b,c,d,e){C("Assertion failed: "+I(b)+", at: "+[c?I(c):"unknown filename",d,e?I(e):"unknown function"])},f:function(){C("")},e:function(b,c,d){J.copyWithin(b,c,c+d)},d:function(b){var c=J.length;b>>>=0;if(2147483648<b)return!1;for(var d=1;4>=d;d*=2){var e=c*(1+.2/d);e=Math.min(e,b+100663296);var f=Math;e=Math.max(b,e);f=f.min.call(f,2147483648,e+(65536-e%65536)%65536);a:{try{D.grow(f-K.byteLength+65535>>>16);M();var g=1;break a}catch(m){}g=void 0}if(g)return!0}return!1},
b:function(b,c,d,e){for(var f=0,g=0;g<d;g++){var m=L[c>>2],G=L[c+4>>2];c+=8;for(var x=0;x<G;x++){var y=J[m+x],z=la[b];0===y||10===y?((1===b?aa:A)(H(z,0)),z.length=0):z.push(y)}f+=G}L[e>>2]=f;return 0},c:function(b,c,d,e){var f=D.buffer;a.audioPackets.push({data:f.slice?f.slice(b,b+c):(new Uint8Array(new Uint8Array(f,b,c))).buffer,timestamp:d,discardPadding:e})},j:function(b,c,d,e,f,g,m,G,x,y,z){a.videoFormat={width:b,height:c,chromaWidth:d,chromaHeight:e,cropLeft:G,cropTop:x,cropWidth:g,cropHeight:m,
displayWidth:y,displayHeight:z,fps:f}},h:function(b,c){function d(e){for(var f="",g=new Uint8Array(D.buffer);0!=g[e];e++)f+=String.fromCharCode(g[e]);return f}b&&(a.videoCodec=d(b));c&&(a.audioCodec=d(c));b=a._ogv_demuxer_media_duration();a.duration=0<=b?b:NaN;a.loadedMetadata=!0},i:function(b,c){if(a.onseek)a.onseek(b+4294967296*c)},g:function(b,c,d,e,f){var g=D.buffer;a.videoPackets.push({data:g.slice?g.slice(b,b+c):(new Uint8Array(new Uint8Array(g,b,c))).buffer,timestamp:d,keyframeTimestamp:e,
isKeyframe:!!f})}};
(function(){function b(f){a.asm=f.exports;D=a.asm.k;M();N=a.asm.w;ca.unshift(a.asm.l);O--;a.monitorRunDependencies&&a.monitorRunDependencies(O);0==O&&(null!==P&&(clearInterval(P),P=null),Q&&(f=Q,Q=null,f()))}function c(f){b(f.instance)}function d(f){return ja().then(function(g){return WebAssembly.instantiate(g,e)}).then(function(g){return g}).then(f,function(g){A("failed to asynchronously prepare wasm: "+g);C(g)})}var e={a:ma};O++;a.monitorRunDependencies&&a.monitorRunDependencies(O);if(a.instantiateWasm)try{return a.instantiateWasm(e,
b)}catch(f){return A("Module.instantiateWasm callback failed with error: "+f),!1}(function(){return B||"function"!=typeof WebAssembly.instantiateStreaming||fa()||R.startsWith("file://")||"function"!=typeof fetch?d(c):fetch(R,{credentials:"same-origin"}).then(function(f){return WebAssembly.instantiateStreaming(f,e).then(c,function(g){A("wasm streaming compile failed: "+g);A("falling back to ArrayBuffer instantiation");return d(c)})})})().catch(k);return{}})();
a.___wasm_call_ctors=function(){return(a.___wasm_call_ctors=a.asm.l).apply(null,arguments)};a._ogv_demuxer_init=function(){return(a._ogv_demuxer_init=a.asm.m).apply(null,arguments)};a._ogv_demuxer_receive_input=function(){return(a._ogv_demuxer_receive_input=a.asm.n).apply(null,arguments)};a._ogv_demuxer_process=function(){return(a._ogv_demuxer_process=a.asm.o).apply(null,arguments)};a._ogv_demuxer_destroy=function(){return(a._ogv_demuxer_destroy=a.asm.p).apply(null,arguments)};
a._ogv_demuxer_flush=function(){return(a._ogv_demuxer_flush=a.asm.q).apply(null,arguments)};a._ogv_demuxer_media_length=function(){return(a._ogv_demuxer_media_length=a.asm.r).apply(null,arguments)};a._ogv_demuxer_media_duration=function(){return(a._ogv_demuxer_media_duration=a.asm.s).apply(null,arguments)};a._ogv_demuxer_seekable=function(){return(a._ogv_demuxer_seekable=a.asm.t).apply(null,arguments)};
a._ogv_demuxer_keypoint_offset=function(){return(a._ogv_demuxer_keypoint_offset=a.asm.u).apply(null,arguments)};a._ogv_demuxer_seek_to_keypoint=function(){return(a._ogv_demuxer_seek_to_keypoint=a.asm.v).apply(null,arguments)};a._malloc=function(){return(a._malloc=a.asm.x).apply(null,arguments)};a._free=function(){return(a._free=a.asm.y).apply(null,arguments)};var U;Q=function na(){U||V();U||(Q=na)};
function V(){function b(){if(!U&&(U=!0,a.calledRun=!0,!E)){S(ca);h(a);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;){var c=a.postRun.shift();da.unshift(c)}S(da)}}if(!(0<O)){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)ea();S(ba);0<O||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);b()},1)):b())}}a.run=V;
if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();V();var W,X,Y;"undefined"===typeof performance||"undefined"===typeof performance.now?Y=Date.now:Y=performance.now.bind(performance);function Z(b){var c=Y();b=b();c=Y()-c;a.cpuTime+=c;return b}a.loadedMetadata=!1;a.videoCodec=null;a.audioCodec=null;a.duration=NaN;a.onseek=null;a.cpuTime=0;a.audioPackets=[];Object.defineProperty(a,"hasAudio",{get:function(){return a.loadedMetadata&&a.audioCodec}});
Object.defineProperty(a,"audioReady",{get:function(){return 0<a.audioPackets.length}});Object.defineProperty(a,"audioTimestamp",{get:function(){return 0<a.audioPackets.length?a.audioPackets[0].timestamp:-1}});a.videoPackets=[];Object.defineProperty(a,"hasVideo",{get:function(){return a.loadedMetadata&&a.videoCodec}});Object.defineProperty(a,"frameReady",{get:function(){return 0<a.videoPackets.length}});
Object.defineProperty(a,"frameTimestamp",{get:function(){return 0<a.videoPackets.length?a.videoPackets[0].timestamp:-1}});Object.defineProperty(a,"keyframeTimestamp",{get:function(){return 0<a.videoPackets.length?a.videoPackets[0].keyframeTimestamp:-1}});Object.defineProperty(a,"nextKeyframeTimestamp",{get:function(){for(var b=0;b<a.videoPackets.length;b++){var c=a.videoPackets[b];if(c.isKeyframe)return c.timestamp}return-1}});Object.defineProperty(a,"processing",{get:function(){return!1}});
Object.defineProperty(a,"seekable",{get:function(){return!!a._ogv_demuxer_seekable()}});a.init=function(b){Z(function(){a._ogv_demuxer_init()});b()};a.receiveInput=function(b,c){Z(function(){var d=b.byteLength;W&&X>=d||(W&&a._free(W),X=d,W=a._malloc(X));var e=W;(new Uint8Array(D.buffer,e,d)).set(new Uint8Array(b));a._ogv_demuxer_receive_input(e,d)});c()};a.process=function(b){var c=Z(function(){return a._ogv_demuxer_process()});b(!!c)};
a.dequeueVideoPacket=function(b){if(a.videoPackets.length){var c=a.videoPackets.shift().data;b(c)}else b(null)};a.dequeueAudioPacket=function(b){if(a.audioPackets.length){var c=a.audioPackets.shift();b(c.data,c.discardPadding)}else b(null)};a.getKeypointOffset=function(b,c){var d=Z(function(){return a._ogv_demuxer_keypoint_offset(1E3*b)});c(d)};
a.seekToKeypoint=function(b,c){var d=Z(function(){return a._ogv_demuxer_seek_to_keypoint(1E3*b)});d&&(a.audioPackets.splice(0,a.audioPackets.length),a.videoPackets.splice(0,a.videoPackets.length));c(!!d)};a.flush=function(b){Z(function(){a.audioPackets.splice(0,a.audioPackets.length);a.videoPackets.splice(0,a.videoPackets.length);a._ogv_demuxer_flush()});b()};a.close=function(){};
return OGVDemuxerWebMW.ready
}
);
})();
if (typeof exports === 'object' && typeof module === 'object')
module.exports = OGVDemuxerWebMW;
else if (typeof define === 'function' && define['amd'])
define([], function() { return OGVDemuxerWebMW; });
else if (typeof exports === 'object')
exports["OGVDemuxerWebMW"] = OGVDemuxerWebMW;
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
(()=>{var e={575:e=>{e.exports=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},e.exports.__esModule=!0,e.exports.default=e.exports},913:e=>{function t(e,t){for(var o=0;o<t.length;o++){var r=t[o];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}e.exports=function(e,o,r){return o&&t(e.prototype,o),r&&t(e,r),Object.defineProperty(e,"prototype",{writable:!1}),e},e.exports.__esModule=!0,e.exports.default=e.exports},318:e=>{e.exports=function(e){return e&&e.__esModule?e:{default:e}},e.exports.__esModule=!0,e.exports.default=e.exports},8:e=>{function t(o){return e.exports=t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e.exports.__esModule=!0,e.exports.default=e.exports,t(o)}e.exports=t,e.exports.__esModule=!0,e.exports.default=e.exports},523:(e,t,o)=>{"use strict";var r=o(318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=r(o(575)),u=r(o(913)),s=new(function(){function e(){(0,n.default)(this,e)}return(0,u.default)(e,[{key:"hasTypedArrays",value:function(){return!!window.Uint32Array}},{key:"hasWebAssembly",value:function(){return!!window.WebAssembly}},{key:"hasWebAudio",value:function(){return!(!window.AudioContext&&!window.webkitAudioContext)}},{key:"hasFlash",value:function(){return!1}},{key:"hasAudio",value:function(){return this.hasWebAudio()}},{key:"isBlacklisted",value:function(e){return!1}},{key:"isSlow",value:function(){return!1}},{key:"isTooSlow",value:function(){return!1}},{key:"supported",value:function(e){return"OGVDecoder"===e?this.hasWebAssembly():"OGVPlayer"===e&&this.supported("OGVDecoder")&&this.hasAudio()}}]),e}());t.default=s}},t={};function o(r){var n=t[r];if(void 0!==n)return n.exports;var u=t[r]={exports:{}};return e[r](u,u.exports,o),u.exports}(()=>{"use strict";var e=o(318),t=e(o(8)),r=e(o(523));"object"===("undefined"==typeof window?"undefined":(0,t.default)(window))&&(window.OGVCompat=r.default,window.OGVVersion="1.8.9-20220406232920-cb5f7ff")})()})();
@@ -0,0 +1 @@
(()=>{var e={318:e=>{e.exports=function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}},e.exports.__esModule=!0,e.exports.default=e.exports},8:e=>{function _typeof(o){return e.exports=_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e.exports.__esModule=!0,e.exports.default=e.exports,_typeof(o)}e.exports=_typeof,e.exports.__esModule=!0,e.exports.default=e.exports}},o={};function __webpack_require__(t){var r=o[t];if(void 0!==r)return r.exports;var p=o[t]={exports:{}};return e[t](p,p.exports,__webpack_require__),p.exports}(()=>{"use strict";var e=__webpack_require__(318)(__webpack_require__(8)),o="1.8.9-20220406232920-cb5f7ff";"object"===("undefined"==typeof window?"undefined":(0,e.default)(window))&&(window.OGVVersion=o)})()})();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,10 @@
ogv.js 1.8.9
--------------
https://github.com/brion/ogv.js
Instructions to import ogv.js library into Moodle:
1. Download the latest release from https://github.com/brion/ogv.js/releases
(do not choose "Source code")
2. copy 'ogv-es2017.js' into 'amd/src/local/ogv/ogv.js'.
3. copy all the wasm and js files into 'ogvjs/' folder.
+182
View File
@@ -0,0 +1,182 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file is serving optimised JS and WASM for ogv.js.
*
* @package media_videojs
* @copyright 2021 Huong Nguyen <huongnv13@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// Disable moodle specific debug messages and any errors in output,
// comment out when debugging or better look into error log!
define('NO_DEBUG_DISPLAY', true);
// We need just the values from config.php and minlib.php.
define('ABORT_AFTER_CONFIG', true);
require_once('../../../config.php'); // This stops immediately at the beginning of lib/setup.php.
require_once($CFG->dirroot . '/lib/jslib.php');
require_once($CFG->dirroot . '/lib/wasmlib.php');
$slashargument = min_get_slash_argument();
if (!$slashargument) {
// The above call to min_get_slash_argument should always work.
die('Invalid request');
}
$slashargument = ltrim($slashargument, '/');
if (substr_count($slashargument, '/') < 1) {
header('HTTP/1.0 404 not found');
die('Slash argument must contain both a revision and a file path');
}
// Get all the library files (js and wasm) of the OGV.
$basepath = $CFG->dirroot . '/media/player/videojs/ogvjs/';
$jsfiles = [];
$files = glob("{$basepath}*.{js,wasm}", GLOB_BRACE);
foreach ($files as $file) {
$jsfiles[] = basename($file);
}
// Split into revision and module name.
list($rev, $file) = explode('/', $slashargument, 2);
$rev = min_clean_param($rev, 'INT');
$file = min_clean_param($file, 'SAFEPATH');
if (empty($jsfiles) || !in_array($file, $jsfiles)) {
// We can't find the requested file.
header('HTTP/1.0 404 not found');
exit(0);
}
// Check if the requesting file is Javascript or Web Assembly.
$iswasm = media_videojs_ogvloader_is_wasm_file($file);
// Use the caching only for meaningful revision numbers which prevents future cache poisoning.
if ($rev > 0 and $rev < (time() + 60 * 60)) {
// We are lazy loading a single file - so include the filename in the etag.
$etag = sha1($rev . '/' . $file);
$candidate = $CFG->localcachedir . '/ogvloader/' . $etag;
if (file_exists($candidate)) {
// Cache exist.
if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) || !empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
// We do not actually need to verify the etag value because our files
// never change in cache because we increment the rev parameter.
media_videojs_ogvloader_send_unmodified($iswasm, $candidate, $etag);
}
media_videojs_ogvloader_send_cached($iswasm, $candidate, $etag);
exit(0);
} else {
// Cache does not exist. Create one.
$filecontent = file_get_contents($basepath . $file);
if ($filecontent === false) {
error_log('Failed to load the library ' . $file);
$filecontent = "/* Failed to load library file {$file}. */\n";
}
$filecontent = media_videojs_ogvloader_add_module_module_name_if_necessary($iswasm, $filecontent);
media_videojs_ogvloader_write_cache_file_content($iswasm, $candidate, $filecontent);
// Verify nothing failed in cache file creation.
clearstatcache();
if (file_exists($candidate)) {
media_videojs_ogvloader_send_cached($iswasm, $candidate, $etag);
exit(0);
}
}
}
// If we've made it here then we're in "dev mode" where everything is lazy loaded.
// So all files will be served one at a time.
$filecontent = file_get_contents($basepath . $file);
$filecontent = rtrim($filecontent);
$filecontent = media_videojs_ogvloader_add_module_module_name_if_necessary($iswasm, $filecontent);
media_videojs_ogvloader_send_uncached($iswasm, $filecontent);
/**
* Check the given file is a Web Assembly file or not
*
* @param string $filename File name to check
* @return bool Whether the file is Web Assembly or not
*/
function media_videojs_ogvloader_is_wasm_file(string $filename): bool {
$ext = pathinfo($filename, PATHINFO_EXTENSION);
return $ext == 'wasm';
}
/**
* Add Moodle module name to the Javascript module if necessary
*
* @param bool $iswasm Whether the file is Web Assembly or not
* @param string $content File content
* @return string
*/
function media_videojs_ogvloader_add_module_module_name_if_necessary(bool $iswasm, string $content): string {
if (!$iswasm && preg_match('/define\(\s*(\[|function)/', $content)) {
// If the JavaScript module has been defined without specifying a name then we'll
// add the Moodle module name now.
$replace = 'define(\'media_videojs/video-lazy\', ';
$search = 'define(';
// Replace only the first occurrence.
$content = implode($replace, explode($search, $content, 2));
}
return $content;
}
/**
* Create cache file content
*
* @param bool $iswasm Whether the file is Web Assembly or not
* @param string $candidate Full file path to cache file
* @param string $filecontent File content
*/
function media_videojs_ogvloader_write_cache_file_content(bool $iswasm, string $candidate, string $filecontent): void {
$iswasm ? wasm_write_cache_file_content($candidate, $filecontent) : js_write_cache_file_content($candidate, $filecontent);
}
/**
* Send file content with as much caching as possible
*
* @param bool $iswasm Whether the file is Web Assembly or not
* @param string $candidate Full file path to cache file
* @param string $etag Etag
*/
function media_videojs_ogvloader_send_cached(bool $iswasm, string $candidate, string $etag): void {
$iswasm ? wasm_send_cached($candidate, $etag, 'ogvloader.php') : js_send_cached($candidate, $etag, 'ogvloader.php');
}
/**
* Send file without any caching
*
* @param bool $iswasm Whether the file is Web Assembly or not
* @param string $ilecontent File content
*/
function media_videojs_ogvloader_send_uncached(bool $iswasm, string $ilecontent): void {
$iswasm ? wasm_send_uncached($ilecontent, 'ogvloader.php') : js_send_uncached($ilecontent, 'ogvloader.php');
}
/**
* Send the file not modified headers
*
* @param bool $iswasm Whether the file is Web Assembly or not
* @param int $candidate Full file path to cache file
* @param string $etag Etag
*/
function media_videojs_ogvloader_send_unmodified(bool $iswasm, int $candidate, string $etag): void {
$iswasm ? wasm_send_unmodified(filemtime($candidate), $etag) : js_send_unmodified(filemtime($candidate), $etag);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 927 B

+44
View File
@@ -0,0 +1,44 @@
VideoJS 8.10.0
--------------
https://github.com/videojs/video.js
Instructions to import VideoJS player into Moodle:
1. Download the latest release from https://github.com/videojs/video.js/releases
(do not choose "Source code")
2. copy 'video.js' into 'amd/src/video-lazy.js'
3. copy 'font/' into 'fonts/' folder
4. copy 'video-js.css' into 'styles.css'
Add /* stylelint-disable */ in the beginning.
Maintain the css after "/* Modifications of player made by Moodle: */" to the end of the styles file.
Check status of:
https://github.com/videojs/video.js/issues/2777
6. copy 'lang/' into 'videojs/' subfolder (so the result will be media/player/videojs/videojs/lang).
Import plugins:
YouTube Playback Technology for VideoJS 3.0.1
---------------------------------------------
https://github.com/videojs/videojs-youtube
Instructions to import YouTube Playback Technology into Moodle:
1. Copy https://github.com/videojs/videojs-youtube/blob/master/dist/Youtube.js into 'amd/src/Youtube-lazy.js'
In the beginning of the js file replace
define(['videojs']
with
define(['media_videojs/video-lazy']
Ogv.js Playback Technology for VideoJS 1.0.0
---------------------------------------------
https://github.com/HuongNV13/videojs-ogvjs
Instructions to import Ogv.js Playback Technology into Moodle:
1. Download the latest release from https://github.com/HuongNV13/videojs-ogvjs/releases
(do not choose "Source code")
2. Copy Videojs-Ogvjs.amd.js into 'amd/src/videojs-ogvjs-lazy.js'
In the beginning of the js file:
Replace
define(['video.js', 'ogv']
with
define(['media_videojs/video-lazy', './local/ogv/ogv']
+56
View File
@@ -0,0 +1,56 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Settings file for plugin 'media_videojs'
*
* @package media_videojs
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
if ($ADMIN->fulltree) {
$settings->add(new admin_setting_filetypes('media_videojs/videoextensions',
new lang_string('videoextensions', 'media_videojs'),
new lang_string('configvideoextensions', 'media_videojs'),
'html_video,media_source,.f4v,.flv',
array('onlytypes' => array('video', 'web_video', 'html_video', 'media_source'))));
$settings->add(new admin_setting_filetypes('media_videojs/audioextensions',
new lang_string('audioextensions', 'media_videojs'),
new lang_string('configaudioextensions', 'media_videojs'),
'html_audio',
array('onlytypes' => array('audio', 'web_audio', 'html_audio'))));
$settings->add(new admin_setting_configcheckbox('media_videojs/youtube',
new lang_string('youtube', 'media_videojs'),
new lang_string('configyoutube', 'media_videojs'), 1));
$settings->add(new admin_setting_configtext('media_videojs/videocssclass',
new lang_string('videocssclass', 'media_videojs'),
new lang_string('configvideocssclass', 'media_videojs'), 'video-js'));
$settings->add(new admin_setting_configtext('media_videojs/audiocssclass',
new lang_string('audiocssclass', 'media_videojs'),
new lang_string('configaudiocssclass', 'media_videojs'), 'video-js'));
$settings->add(new admin_setting_configcheckbox('media_videojs/limitsize',
new lang_string('limitsize', 'media_videojs'),
new lang_string('configlimitsize', 'media_videojs'), 1));
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,54 @@
@media @media_videojs @_file_upload
Feature: Embed videos without the media filter
In order to add helpful resources for students
As a teacher
I need to be able to embed videos URL, file and lesson modules
Background:
Given I log in as "admin"
And I am on site homepage
And I turn editing mode on
@javascript
Scenario: Add a video in a URL resource. Make sure media filters work
Given the following "activity" exists:
| activity | url |
| course | Acceptance test site |
| name | Video URL |
| intro | Example of a video url |
| externalurl | http://download.moodle.org/mediatest/quicktime_320_180.mov |
| section | 1 |
When I am on the "Video URL" "url activity" page
Then ".video-js" "css_element" should exist
And I am on site homepage
@javascript
Scenario: Add a video as a File resource. Make sure media filters work
When I add a "File" to section "1" using the activity chooser
And I set the following fields to these values:
| Name | Video File |
| Description | Example of a video file |
And I upload "media/player/videojs/tests/fixtures/test.mov" file to "Select files" filemanager
And I press "Save and display"
Then ".video-js" "css_element" should exist
@javascript
Scenario: Add a video as content to a lesson. Make sure media filters work
Given the following "activities" exist:
| activity | course | section | name |
| lesson | Acceptance test site | 1 | Lesson with video |
When I am on the "Lesson with video" "lesson activity editing" page
And I expand all fieldsets
And I upload "media/player/videojs/tests/fixtures/test.mov" file to "Linked media" filemanager
And I press "Save and display"
And I follow "Add a content page"
And I set the following fields to these values:
| Page title | Placeholder content |
| Description | Just so we can preview the lesson |
And I press "Save page"
And I am on site homepage
And I follow "Lesson"
And I follow "Click here to view"
And I switch to "lessonmediafile" window
Then ".video-js" "css_element" should exist
And I switch to the main window
Binary file not shown.
+356
View File
@@ -0,0 +1,356 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Test classes for handling embedded media.
*
* @package media_videojs
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace media_videojs;
use core_media_manager;
use html_writer;
use media_videojs_plugin;
use moodle_url;
/**
* Test script for media embedding.
*
* @package media_videojs
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class player_test extends \advanced_testcase {
/**
* Pre-test setup. Preserves $CFG.
*/
public function setUp(): void {
parent::setUp();
// Reset $CFG and $SERVER.
$this->resetAfterTest();
// Consistent initial setup: all players disabled.
\core\plugininfo\media::set_enabled_plugins('videojs');
// Pretend to be using Firefox browser (must support ogg for tests to work).
\core_useragent::instance(true, 'Mozilla/5.0 (X11; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0 ');
}
/**
* Test that plugin is returned as enabled media plugin.
*/
public function test_is_installed(): void {
$sortorder = \core\plugininfo\media::get_enabled_plugins();
$this->assertEquals(['videojs' => 'videojs'], $sortorder);
}
/**
* Test method get_supported_extensions()
*/
public function test_supported_extensions(): void {
$supportedextensions = array_merge(file_get_typegroup('extension', 'html_video'),
file_get_typegroup('extension', 'html_audio'), file_get_typegroup('extension', 'media_source'));
// Make sure that the list of extensions from the setting is filtered to HTML5 natively supported extensions.
$player = new media_videojs_plugin();
$this->assertTrue(in_array('.mp3', $player->get_supported_extensions()));
$this->assertEmpty(array_diff($player->get_supported_extensions(), $supportedextensions));
// Try to set the audioextensions to something non-native (.ra) and make sure it is not returned as supported.
set_config('audioextensions', '.mp3,.wav,.ra', 'media_videojs');
$player = new media_videojs_plugin();
$this->assertNotEmpty($player->get_supported_extensions());
$this->assertTrue(in_array('.mp3', $player->get_supported_extensions()));
$this->assertFalse(in_array('.ra', $player->get_supported_extensions()));
$this->assertEmpty(array_diff($player->get_supported_extensions(), $supportedextensions));
// Check flash extensions are not returned as supported.
set_config('videoextensions', '.flv,.f4v', 'media_videojs');
$player = new media_videojs_plugin();
$this->assertFalse(in_array('.flv', $player->get_supported_extensions()));
$this->assertFalse(in_array('.f4v', $player->get_supported_extensions()));
}
/**
* Test embedding without media filter (for example for displaying file resorce).
*/
public function test_embed_url(): void {
global $CFG;
$url = new moodle_url('http://example.org/1.webm');
$manager = core_media_manager::instance();
$embedoptions = array(
core_media_manager::OPTION_TRUSTED => true,
core_media_manager::OPTION_BLOCK => true,
);
$this->assertTrue($manager->can_embed_url($url, $embedoptions));
$content = $manager->embed_url($url, 'Test & file', 0, 0, $embedoptions);
$this->assertMatchesRegularExpression('~mediaplugin_videojs~', $content);
$this->assertMatchesRegularExpression('~</video>~', $content);
$this->assertMatchesRegularExpression('~title="Test &amp; file"~', $content);
$this->assertMatchesRegularExpression('~style="max-width:' . $CFG->media_default_width . 'px;~', $content);
// Repeat sending the specific size to the manager.
$content = $manager->embed_url($url, 'New file', 123, 50, $embedoptions);
$this->assertMatchesRegularExpression('~style="max-width:123px;~', $content);
// Repeat without sending the size and with unchecked setting to limit the video size.
set_config('limitsize', false, 'media_videojs');
$manager = core_media_manager::instance();
$content = $manager->embed_url($url, 'Test & file', 0, 0, $embedoptions);
$this->assertDoesNotMatchRegularExpression('~style="max-width:~', $content);
}
/**
* Test that mediaplugin filter replaces a link to the supported file with media tag.
*
* filter_mediaplugin is enabled by default.
*/
public function test_embed_link(): void {
global $CFG;
$url = new moodle_url('http://example.org/some_filename.mp4');
$text = html_writer::link($url, 'Watch this one');
$content = format_text($text, FORMAT_HTML);
$this->assertMatchesRegularExpression('~mediaplugin_videojs~', $content);
$this->assertMatchesRegularExpression('~</video>~', $content);
$this->assertMatchesRegularExpression('~title="Watch this one"~', $content);
$this->assertDoesNotMatchRegularExpression('~<track\b~i', $content);
$this->assertMatchesRegularExpression('~style="max-width:' . $CFG->media_default_width . 'px;~', $content);
}
/**
* Test that only supported URLs are listed as sources but all URLs are present in links fallbacks.
*/
public function test_fallback(): void {
$urls = [
new moodle_url('http://example.org/1.rv'), // Not supported.
new moodle_url('http://example.org/2.webm'), // Supported.
new moodle_url('http://example.org/3.ogv'), // Supported.
];
$manager = core_media_manager::instance();
$content = $manager->embed_alternatives($urls, '', 0, 0, []);
$this->assertMatchesRegularExpression('~mediaplugin_videojs~', $content);
$this->assertMatchesRegularExpression('~</video>~', $content);
// Title is taken from the name of the first supported file.
$this->assertMatchesRegularExpression('~title="2"~', $content);
// Only supported files are in <source>'s.
$this->assertDoesNotMatchRegularExpression('~<source src="http://example.org/1.rv"~', $content);
$this->assertMatchesRegularExpression('~<source src="http://example.org/2.webm"~', $content);
$this->assertMatchesRegularExpression('~<source src="http://example.org/3.ogv"~', $content);
// Links to all files are included.
$this->assertMatchesRegularExpression(
'~<a class="mediafallbacklink" href="http://example.org/1.rv">1.rv</a>~', $content);
$this->assertMatchesRegularExpression(
'~<a class="mediafallbacklink" href="http://example.org/2.webm">2.webm</a>~', $content);
$this->assertMatchesRegularExpression(
'~<a class="mediafallbacklink" href="http://example.org/3.ogv">3.ogv</a>~', $content);
}
/**
* Assert other players do not apply after videojs was applied.
*/
public function test_prevent_other_players(): void {
\core\plugininfo\media::set_enabled_plugins('videojs,html5video');
$url = new moodle_url('http://example.org/some_filename.webm');
$text = html_writer::link($url, 'Apply one player only');
$content = format_text($text, FORMAT_HTML);
$this->assertMatchesRegularExpression('~mediaplugin_videojs~', $content);
$this->assertEquals(1, substr_count($content, '</video>'));
$this->assertDoesNotMatchRegularExpression('~mediaplugin_html5video~', $content);
$this->assertMatchesRegularExpression(
'~<a class="mediafallbacklink" href="http://example.org/some_filename.webm">Apply one player only</a>~', $content);
}
/**
* Test that mediaplugin filter adds player code on top of <video> tags.
*
* filter_mediaplugin is enabled by default.
*/
public function test_embed_media(): void {
global $CFG;
$url = new moodle_url('http://example.org/some_filename.mp4');
$trackurl = new moodle_url('http://example.org/some_filename.vtt');
$text = '<video controls="true"><source src="'.$url.'"/><source src="somethinginvalid"/>' .
'<track src="'.$trackurl.'">Unsupported text</video>';
$content = format_text($text, FORMAT_HTML);
$this->assertMatchesRegularExpression('~mediaplugin_videojs~', $content);
$this->assertMatchesRegularExpression('~</video>~', $content);
$this->assertMatchesRegularExpression('~title="some_filename.mp4"~', $content);
$this->assertMatchesRegularExpression('~style="max-width:' . $CFG->media_default_width . 'px;~', $content);
// Unsupported text and tracks are preserved.
$this->assertMatchesRegularExpression('~Unsupported text~', $content);
$this->assertMatchesRegularExpression('~<track\b~i', $content);
// Invalid sources are removed.
$this->assertDoesNotMatchRegularExpression('~somethinginvalid~i', $content);
// Video with dimensions and source specified as src attribute without <source> tag.
$text = '<video controls="true" width="123" height="35" src="'.$url.'">Unsupported text</video>';
$content = format_text($text, FORMAT_HTML);
$this->assertMatchesRegularExpression('~mediaplugin_videojs~', $content);
$this->assertMatchesRegularExpression('~</video>~', $content);
$this->assertMatchesRegularExpression('~<source\b~', $content);
$this->assertMatchesRegularExpression('~style="max-width:123px;~', $content);
$this->assertDoesNotMatchRegularExpression('~width="~', $content);
$this->assertDoesNotMatchRegularExpression('~height="~', $content);
// Audio tag.
$url = new moodle_url('http://example.org/some_filename.mp3');
$trackurl = new moodle_url('http://example.org/some_filename.vtt');
$text = '<audio controls="true"><source src="'.$url.'"/><source src="somethinginvalid"/>' .
'<track src="'.$trackurl.'">Unsupported text</audio>';
$content = format_text($text, FORMAT_HTML);
$this->assertMatchesRegularExpression('~mediaplugin_videojs~', $content);
$this->assertDoesNotMatchRegularExpression('~</video>~', $content);
$this->assertMatchesRegularExpression('~</audio>~', $content);
$this->assertMatchesRegularExpression('~title="some_filename.mp3"~', $content);
$this->assertMatchesRegularExpression('~style="max-width:' . $CFG->media_default_width . 'px;~', $content);
// Unsupported text and tracks are preserved.
$this->assertMatchesRegularExpression('~Unsupported text~', $content);
$this->assertMatchesRegularExpression('~<track\b~i', $content);
// Invalid sources are removed.
$this->assertDoesNotMatchRegularExpression('~somethinginvalid~i', $content);
}
/**
* Helper function for testing youtube videos embedding.
*
* @param string $t output of core_media_manager::embed_url.
*/
protected function youtube_plugin_engaged($t) {
$this->assertStringContainsString('mediaplugin_videojs', $t);
$this->assertStringContainsString('data-setup-lazy="{&quot;techOrder&quot;: [&quot;youtube&quot;]', $t);
}
/**
* Test that VideoJS can embed youtube videos.
*/
public function test_youtube(): void {
set_config('youtube', 1, 'media_videojs');
$manager = core_media_manager::instance();
// Format: youtube.
$url = new moodle_url('http://www.youtube.com/watch?v=vyrwMmsufJc');
$t = $manager->embed_url($url);
$this->youtube_plugin_engaged($t);
$url = new moodle_url('http://www.youtube.com/v/vyrwMmsufJc');
$t = $manager->embed_url($url);
$this->youtube_plugin_engaged($t);
// Format: youtube video within playlist - this will be played by video.js but without tracks selection.
$url = new moodle_url('https://www.youtube.com/watch?v=dv2f_xfmbD8&index=4&list=PLxcO_MFWQBDcyn9xpbmx601YSDlDcTcr0');
$t = $manager->embed_url($url);
$this->youtube_plugin_engaged($t);
$this->assertStringContainsString('list=PLxcO_MFWQBDcyn9xpbmx601YSDlDcTcr0', $t);
// Format: youtube playlist - not supported.
$url = new moodle_url('http://www.youtube.com/view_play_list?p=PL6E18E2927047B662');
$t = $manager->embed_url($url);
$this->assertStringNotContainsString('mediaplugin_videojs', $t);
$url = new moodle_url('http://www.youtube.com/playlist?list=PL6E18E2927047B662');
$t = $manager->embed_url($url);
$this->assertStringNotContainsString('mediaplugin_videojs', $t);
$url = new moodle_url('http://www.youtube.com/p/PL6E18E2927047B662');
$t = $manager->embed_url($url);
$this->assertStringNotContainsString('mediaplugin_videojs', $t);
}
/**
* Data provider for {@see test_youtube_start_time}
*
* @return array
*/
public function youtube_start_time_provider(): array {
return [
['https://www.youtube.com/watch?v=JNJMF1l3udM&t=1h11s', 3611],
['https://www.youtube.com/watch?v=dv2f_xfmbD8&index=4&list=PLxcO_MFWQBDcyn9xpbmx601YSDlDcTcr0&t=1m5s', 65],
['https://www.youtube.com/watch?v=JNJMF1l3udM&t=1h10m30s', 4230],
['https://www.youtube.com/watch?v=JNJMF1l3udM&t=3m', 180],
['https://www.youtube.com/watch?v=JNJMF1l3udM&t=43s', 43],
['https://www.youtube.com/watch?v=JNJMF1l3udM&t=1234', 1234],
['https://www.youtube.com/watch?v=JNJMF1l3udM&t=invalid', 0],
];
}
/**
* Test Youtube video embedding with URL's containing start time interval
*
* @param string $url
* @param int $expectedstart
*
* @dataProvider youtube_start_time_provider
*/
public function test_youtube_start_time(string $url, int $expectedstart): void {
set_config('youtube', 1, 'media_videojs');
$embedcode = core_media_manager::instance()->embed_url(new moodle_url($url));
$this->youtube_plugin_engaged($embedcode);
$this->assertStringContainsString("&quot;youtube&quot;: {&quot;start&quot;: &quot;{$expectedstart}&quot;}", $embedcode);
}
/**
* Helper function for testing flash videos embedding.
*
* @param string $t output of core_media_manager::embed_url.
*/
protected function flash_plugin_engaged($t) {
$this->assertStringContainsString('mediaplugin_videojs', $t);
$this->assertStringContainsString('data-setup-lazy="{&quot;techOrder&quot;: [&quot;flash&quot;, &quot;html5&quot;]', $t);
}
/**
* Test that VideoJS can not embed flash videos.
*/
public function test_flash_behaviour(): void {
$manager = core_media_manager::instance();
$url = new moodle_url('http://example.org/some_filename.flv');
$t = $manager->embed_url($url);
$this->assertStringNotContainsString('mediaplugin_videojs', $t);
$this->assertMatchesRegularExpression(
'~<a class="mediafallbacklink" href="http://example.org/some_filename.flv">some_filename.flv</a>~', $t);
}
/**
* Test that VideoJS can not embed RTMP streams.
*/
public function test_rtmp_behaviour(): void {
$manager = core_media_manager::instance();
$url = new moodle_url('rtmp://example.com/fms&mp4:path/to/file.mp4');
$t = $manager->embed_url($url);
$this->assertStringNotContainsString('mediaplugin_videojs', $t);
$this->assertMatchesRegularExpression(
'~<a class="mediafallbacklink" href="rtmp://example.com/fms&mp4:path/to/file.mp4">file.mp4</a>~', $t);
}
}
+73
View File
@@ -0,0 +1,73 @@
<?xml version="1.0"?>
<libraries>
<library>
<location>amd/src/video-lazy.js</location>
<name>VideoJS</name>
<description>JavaScript library that makes it easier to work with and build on HTML5 video.</description>
<version>8.10.0</version>
<license>Apache</license>
<licenseversion>2.0</licenseversion>
<repository>https://github.com/videojs/video.js</repository>
<copyrights>
<copyright>Brightcove, Inc</copyright>
</copyrights>
<customised/>
</library>
<library>
<location>amd/src/Youtube-lazy.js</location>
<name>videojs-youtube</name>
<description>YouTube Playback Technology for Video.js.</description>
<version>3.0.1</version>
<license>MIT</license>
<repository>https://github.com/videojs/videojs-youtube</repository>
<copyrights>
<copyright>2014-2015 Benoit Tremblay &lt;trembl.ben@gmail.com&gt;</copyright>
</copyrights>
</library>
<library>
<location>videojs</location>
<name>VideoJS support files</name>
<description>JavaScript library that makes it easier to work with and build on HTML5 video</description>
<version>8.10.0</version>
<license>Apache</license>
<licenseversion>2.0</licenseversion>
<repository>https://github.com/videojs/video.js</repository>
<copyrights>
<copyright>Brightcove, Inc</copyright>
</copyrights>
<customised/>
</library>
<library>
<location>amd/src/local/ogv/ogv.js</location>
<name>ogv.js</name>
<description>Javascript media decoder and player for Ogg Vorbis/Opus/Theora and WebM VP8/VP9/AV1 video.</description>
<version>1.8.9</version>
<license>MIT</license>
<repository>https://github.com/brion/ogv.js/</repository>
<copyrights>
<copyright>Brion Vibber</copyright>
</copyrights>
</library>
<library>
<location>ogvjs</location>
<name>ogv.js support files</name>
<description>JavaScript media decoder and player for Ogg Vorbis/Opus/Theora and WebM VP8/VP9/AV1 video.</description>
<license>MIT</license>
<version>1.8.9</version>
<repository>https://github.com/brion/ogv.js/</repository>
<copyrights>
<copyright>Brion Vibber</copyright>
</copyrights>
</library>
<library>
<location>amd/src/videojs-ogvjs-lazy.js</location>
<name>ogv.js Tech plugin for Video.JS</name>
<description>The ogv.js tech plugin for VideoJS</description>
<version>1.0.0</version>
<license>MIT</license>
<repository>https://github.com/HuongNV13/videojs-ogvjs</repository>
<copyrights>
<copyright>2021 Huong Nguyen huongnv13@gmail.com</copyright>
</copyrights>
</library>
</libraries>
+29
View File
@@ -0,0 +1,29 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Version details
*
* @package media_videojs
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2024042200; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2024041600; // Requires this Moodle version.
$plugin->component = 'media_videojs'; // Full name of the plugin (used for diagnostics).
+94
View File
@@ -0,0 +1,94 @@
videojs.addLanguage('ar', {
"Play": "تشغيل",
"Pause": "إيقاف",
"Current Time": "الوقت الحالي",
"Duration": "مدة",
"Remaining Time": "الوقت المتبقي",
"Stream Type": "نوع التيار",
"LIVE": "مباشر",
"Loaded": "تم التحميل",
"Progress": "التقدم",
"Fullscreen": "ملء الشاشة",
"Exit Fullscreen": "تعطيل ملء الشاشة",
"Mute": "صامت",
"Unmute": "غير الصامت",
"Playback Rate": "معدل التشغيل",
"Subtitles": "الترجمة",
"subtitles off": "إيقاف الترجمة",
"Captions": "التعليقات",
"captions off": "إيقاف التعليقات",
"Chapters": "فصول",
"You aborted the media playback": "لقد ألغيت تشغيل الفيديو",
"A network error caused the media download to fail part-way.": "تسبب خطأ في الشبكة بفشل تحميل الفيديو بالكامل.",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "لا يمكن تحميل الفيديو بسبب فشل في الخادوم أو الشبكة ، أو فشل بسبب عدم إمكانية قراءة تنسيق الفيديو.",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "تم إيقاف تشغيل الفيديو بسبب مشكلة فساد أو لأن الفيديو المستخدم يستخدم ميزات غير مدعومة من متصفحك.",
"No compatible source was found for this media.": "فشل العثور على أي مصدر متوافق مع هذا الفيديو.",
"Play Video": "تشغيل الفيديو",
"Close": "أغلق",
"Modal Window": "نافذة مشروطة",
"This is a modal window": "هذه نافذة مشروطة",
"This modal can be closed by pressing the Escape key or activating the close button.": "يمكن غلق هذه النافذة المشروطة عن طريق الضغط على زر الخروج أو تفعيل زر الإغلاق",
", opens captions settings dialog": ", تفتح نافذة خيارات التعليقات",
", opens subtitles settings dialog": ", تفتح نافذة خيارات الترجمة",
", selected": ", مختار",
"Audio Player": "مشغل الصوت",
"Video Player": "مشغل الفيديو",
"Replay": "إعادة التشغيل",
"Seek to live, currently behind live": "ذهاب إلى نقطة البث المباشر، متأخر عن البث المباشر حاليًا",
"Seek to live, currently playing live": "ذهاب إلى نقطة البث المباشر، البث المباشر قيد التشغيل حاليًا",
"Progress Bar": "شريط التقدم",
"progress bar timing: currentTime={1} duration={2}": "{1} من {2}",
"Descriptions": "الأوصاف",
"descriptions off": "إخفاء الأوصاف",
"Audio Track": "المسار الصوتي",
"Volume Level": "مستوى الصوت",
"The media is encrypted and we do not have the keys to decrypt it.": "الوسائط مشفرة وليس لدينا الرموز اللازمة لفك شفرتها.",
"Close Modal Dialog": "إغلاق مربع الحوار المشروط",
", opens descriptions settings dialog": "، يفتح مربع حوار إعدادات الأوصاف",
"captions settings": "إعدادات التعليقات التوضيحية",
"subtitles settings": "إعدادات الترجمات",
"descriptions settings": "إعدادات الأوصاف",
"Text": "النص",
"White": "أبيض",
"Black": "أسود",
"Red": "أحمر",
"Green": "أخضر",
"Blue": "أزرق",
"Yellow": "أصفر",
"Magenta": "أرجواني",
"Cyan": "أزرق سماوي",
"Background": "الخلفية",
"Window": "نافذة",
"Transparent": "شفاف",
"Semi-Transparent": "نصف شفاف",
"Opaque": "معتم",
"Font Size": "حجم الخط",
"Text Edge Style": "نمط حواف النص",
"None": "لا شيء",
"Raised": "بارز",
"Depressed": "منخفض",
"Uniform": "منتظم",
"Drop shadow": "ظل خلفي",
"Font Family": "عائلة الخطوط",
"Proportional Sans-Serif": "Proportional Sans-Serif",
"Monospace Sans-Serif": "Monospace Sans-Serif",
"Proportional Serif": "Proportional Serif",
"Monospace Serif": "Monospace Serif",
"Casual": "Casual",
"Script": "Script",
"Small Caps": "Small Caps",
"Reset": "إعادة الضبط",
"restore all settings to the default values": "استعادة كل الإعدادات إلى القيم الافتراضية",
"Done": "تم",
"Caption Settings Dialog": "مربع حوار إعدادات التعليقات التوضيحية",
"Beginning of dialog window. Escape will cancel and close the window.": "بداية نافذة مربع حوار. الضغط على زر \"Escape\" سيؤدي إلى الإلغاء وإغلاق النافذة.",
"End of dialog window.": "نهاية نافذة مربع حوار.",
"{1} is loading.": "{1} قيد التحميل.",
"Exit Picture-in-Picture": "خرج من وضع صورة داخل صورة",
"Picture-in-Picture": "صورة داخل صورة",
"No content": "لا يوجد محتوى",
"Color": "اللون",
"Opacity": "معدل الشفافية",
"Text Background": "خلفية النص",
"Caption Area Background": "خلفية منطقة التسمية التوضيحية"
});
+94
View File
@@ -0,0 +1,94 @@
{
"Play": "تشغيل",
"Pause": "إيقاف",
"Current Time": "الوقت الحالي",
"Duration": "مدة",
"Remaining Time": "الوقت المتبقي",
"Stream Type": "نوع التيار",
"LIVE": "مباشر",
"Loaded": "تم التحميل",
"Progress": "التقدم",
"Fullscreen": "ملء الشاشة",
"Exit Fullscreen": "تعطيل ملء الشاشة",
"Mute": "صامت",
"Unmute": "غير الصامت",
"Playback Rate": "معدل التشغيل",
"Subtitles": "الترجمة",
"subtitles off": "إيقاف الترجمة",
"Captions": "التعليقات",
"captions off": "إيقاف التعليقات",
"Chapters": "فصول",
"You aborted the media playback": "لقد ألغيت تشغيل الفيديو",
"A network error caused the media download to fail part-way.": "تسبب خطأ في الشبكة بفشل تحميل الفيديو بالكامل.",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "لا يمكن تحميل الفيديو بسبب فشل في الخادوم أو الشبكة ، أو فشل بسبب عدم إمكانية قراءة تنسيق الفيديو.",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "تم إيقاف تشغيل الفيديو بسبب مشكلة فساد أو لأن الفيديو المستخدم يستخدم ميزات غير مدعومة من متصفحك.",
"No compatible source was found for this media.": "فشل العثور على أي مصدر متوافق مع هذا الفيديو.",
"Play Video": "تشغيل الفيديو",
"Close": "أغلق",
"Modal Window": "نافذة مشروطة",
"This is a modal window": "هذه نافذة مشروطة",
"This modal can be closed by pressing the Escape key or activating the close button.": "يمكن غلق هذه النافذة المشروطة عن طريق الضغط على زر الخروج أو تفعيل زر الإغلاق",
", opens captions settings dialog": ", تفتح نافذة خيارات التعليقات",
", opens subtitles settings dialog": ", تفتح نافذة خيارات الترجمة",
", selected": ", مختار",
"Audio Player": "مشغل الصوت",
"Video Player": "مشغل الفيديو",
"Replay": "إعادة التشغيل",
"Seek to live, currently behind live": "ذهاب إلى نقطة البث المباشر، متأخر عن البث المباشر حاليًا",
"Seek to live, currently playing live": "ذهاب إلى نقطة البث المباشر، البث المباشر قيد التشغيل حاليًا",
"Progress Bar": "شريط التقدم",
"progress bar timing: currentTime={1} duration={2}": "{1} من {2}",
"Descriptions": "الأوصاف",
"descriptions off": "إخفاء الأوصاف",
"Audio Track": "المسار الصوتي",
"Volume Level": "مستوى الصوت",
"The media is encrypted and we do not have the keys to decrypt it.": "الوسائط مشفرة وليس لدينا الرموز اللازمة لفك شفرتها.",
"Close Modal Dialog": "إغلاق مربع الحوار المشروط",
", opens descriptions settings dialog": "، يفتح مربع حوار إعدادات الأوصاف",
"captions settings": "إعدادات التعليقات التوضيحية",
"subtitles settings": "إعدادات الترجمات",
"descriptions settings": "إعدادات الأوصاف",
"Text": "النص",
"White": "أبيض",
"Black": "أسود",
"Red": "أحمر",
"Green": "أخضر",
"Blue": "أزرق",
"Yellow": "أصفر",
"Magenta": "أرجواني",
"Cyan": "أزرق سماوي",
"Background": "الخلفية",
"Window": "نافذة",
"Transparent": "شفاف",
"Semi-Transparent": "نصف شفاف",
"Opaque": "معتم",
"Font Size": "حجم الخط",
"Text Edge Style": "نمط حواف النص",
"None": "لا شيء",
"Raised": "بارز",
"Depressed": "منخفض",
"Uniform": "منتظم",
"Drop shadow": "ظل خلفي",
"Font Family": "عائلة الخطوط",
"Proportional Sans-Serif": "Proportional Sans-Serif",
"Monospace Sans-Serif": "Monospace Sans-Serif",
"Proportional Serif": "Proportional Serif",
"Monospace Serif": "Monospace Serif",
"Casual": "Casual",
"Script": "Script",
"Small Caps": "Small Caps",
"Reset": "إعادة الضبط",
"restore all settings to the default values": "استعادة كل الإعدادات إلى القيم الافتراضية",
"Done": "تم",
"Caption Settings Dialog": "مربع حوار إعدادات التعليقات التوضيحية",
"Beginning of dialog window. Escape will cancel and close the window.": "بداية نافذة مربع حوار. الضغط على زر \"Escape\" سيؤدي إلى الإلغاء وإغلاق النافذة.",
"End of dialog window.": "نهاية نافذة مربع حوار.",
"{1} is loading.": "{1} قيد التحميل.",
"Exit Picture-in-Picture": "خرج من وضع صورة داخل صورة",
"Picture-in-Picture": "صورة داخل صورة",
"No content": "لا يوجد محتوى",
"Color": "اللون",
"Opacity": "معدل الشفافية",
"Text Background": "خلفية النص",
"Caption Area Background": "خلفية منطقة التسمية التوضيحية"
}
+97
View File
@@ -0,0 +1,97 @@
videojs.addLanguage('az', {
"Audio Player": "Audiopleyer",
"Video Player": "Videopleyer",
"Play": "Oynat",
"Pause": "Pauza",
"Replay": "Yenidən oynat",
"Current Time": "Cari Vaxt",
"Duration": "Müddət",
"Remaining Time": "Qalan vaxt",
"Stream Type": "Yayım növü",
"LIVE": "CANLI",
"Seek to live, currently behind live": "Canlı yayım axtarışı, hal-hazırda canlı yayımdan geridədir",
"Seek to live, currently playing live": "Canlı yayım axtarışı, hal-hazırda canlı yayım göstərilir",
"Loaded": "Yükləndi",
"Progress": "Yüklənmə",
"Progress Bar": "Yüklənmə göstəricisi",
"progress bar timing: currentTime={1} duration={2}": "{1} / {2}",
"Fullscreen": "Tam ekran",
"Exit Fullscreen": "Tam ekrandan çıx",
"Mute": "Səssizi qoş",
"Unmute": "Səssizi söndür",
"Playback Rate": "Oynatma sürəti",
"Subtitles": "Alt yazılar",
"subtitles off": "Alt yazıları söndür",
"Captions": "Başlıqlar",
"captions off": "Başlıqları söndür",
"Chapters": "Fəsillər",
"Descriptions": "Təsvirlər",
"descriptions off": "Təsvirləri söndür",
"Audio Track": "Audio Trek",
"Volume Level": "Səs Səviyyəsi",
"You aborted the media playback": "Siz medianın oxudulmasını dayandırdınız",
"A network error caused the media download to fail part-way.": "Şəbəkə xətası səbəbindən medianın endirilməsi yarıda qaldı.",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "Yükləmə xətası.",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "Media faylının korlanması səbəbilə və ya media faylın brauzerinizin dəstəkləmədiyi funksiyalardan istifadə etdiyinə görə medianın oxudulması dayandırılıb.",
"No compatible source was found for this media.": "Bu media üçün uyğun mənbə tapılmadı.",
"The media is encrypted and we do not have the keys to decrypt it.": "Media faylı şifrələnib və onun şifrəsini açmaq üçün açarlar yoxdur.",
"Play Video": "Videonu oynat",
"Close": "Bağla",
"Close Modal Dialog": "Modal dialoqunu bağla",
"Modal Window": "Modal pəncərəsi",
"This is a modal window": "Bu modal pəncərəsidir",
"This modal can be closed by pressing the Escape key or activating the close button.": "Bu modal Escape düyməsini basmaqla və ya bağlama düyməsini sıxmaqla bağlana bilər.",
", opens captions settings dialog": ", başlıq parametrləri dialoqunu açır",
", opens subtitles settings dialog": ", altyazı parametrləri dialoqunu açır",
", opens descriptions settings dialog": ", təsvir parametrləri dialoqunu açır",
", selected": ", seçilmiş",
"captions settings": "başlıq parametrləri",
"subtitles settings": "altyazı parametrləri",
"descriptions settings": "təsvir parametrləri",
"Text": "Tekst",
"White": "Ağ",
"Black": "Qara",
"Red": "Qırmızı",
"Green": "Yaşıl",
"Blue": "Göy",
"Yellow": "Sarı",
"Magenta": "Bənövşəyi",
"Cyan": "Mavi",
"Background": "Fon",
"Window": "Pəncərə",
"Transparent": "Şəffaf",
"Semi-Transparent": "Yarım-Şəffaf",
"Opaque": "Qeyri-şəffaf",
"Font Size": "Şrift Ölçüsü",
"Text Edge Style": "Mətnin kənarlarının üslubu",
"None": "Heç biri",
"Raised": "Artırılmış",
"Depressed": "Azaldılmış",
"Uniform": "Ümumiləşdirilmiş",
"Drop shadow": "Arxa kölgə",
"Font Family": "Şrift Ailəsi",
"Proportional Sans-Serif": "Proporsional Sans-Serif",
"Monospace Sans-Serif": "Birenli Sans-Serif",
"Proportional Serif": "Proporsional Serif",
"Monospace Serif": "Birenli Serif",
"Casual": "Gündəlik",
"Script": "Skript",
"Small Caps": "Kiçik böyük hərflər",
"Reset": "Sıfırla",
"restore all settings to the default values": "bütün parametrləri susmaya görə bərpa edin",
"Done": "Bitdi",
"Caption Settings Dialog": "Başlıq Parametrləri Dialoqu",
"Beginning of dialog window. Escape will cancel and close the window.": "Dialoq pəncərəsinin başlanğıcı. Escape düyməsi ləğv edəcək və pəncərəni bağlayacaq.",
"End of dialog window.": "Dialoq pəncərəsinin sonu.",
"{1} is loading.": "{1} yüklənir.",
"Exit Picture-in-Picture": "Şəkil içində şəkil rejimindən çıxın",
"Picture-in-Picture": "Şəkil içində şəkil rejimi",
"No content": "Məzmun yoxdur",
"Color": "Rəng",
"Opacity": "Qeyri-şəffaflıq",
"Text Background": "Tekst Fonu",
"Caption Area Background": "Başlıq Sahəsinin Fonu",
"Playing in Picture-in-Picture": "Şəkil içində şəkil rejimində oynayır",
"Skip backward {1} seconds": "{1} saniyə geriyə keçin",
"Skip forward {1} seconds": "{1} saniyə qabağa keçin"
});
+97
View File
@@ -0,0 +1,97 @@
{
"Audio Player": "Audiopleyer",
"Video Player": "Videopleyer",
"Play": "Oynat",
"Pause": "Pauza",
"Replay": "Yenidən oynat",
"Current Time": "Cari Vaxt",
"Duration": "Müddət",
"Remaining Time": "Qalan vaxt",
"Stream Type": "Yayım növü",
"LIVE": "CANLI",
"Seek to live, currently behind live": "Canlı yayım axtarışı, hal-hazırda canlı yayımdan geridədir",
"Seek to live, currently playing live": "Canlı yayım axtarışı, hal-hazırda canlı yayım göstərilir",
"Loaded": "Yükləndi",
"Progress": "Yüklənmə",
"Progress Bar": "Yüklənmə göstəricisi",
"progress bar timing: currentTime={1} duration={2}": "{1} / {2}",
"Fullscreen": "Tam ekran",
"Exit Fullscreen": "Tam ekrandan çıx",
"Mute": "Səssizi qoş",
"Unmute": "Səssizi söndür",
"Playback Rate": "Oynatma sürəti",
"Subtitles": "Alt yazılar",
"subtitles off": "Alt yazıları söndür",
"Captions": "Başlıqlar",
"captions off": "Başlıqları söndür",
"Chapters": "Fəsillər",
"Descriptions": "Təsvirlər",
"descriptions off": "Təsvirləri söndür",
"Audio Track": "Audio Trek",
"Volume Level": "Səs Səviyyəsi",
"You aborted the media playback": "Siz medianın oxudulmasını dayandırdınız",
"A network error caused the media download to fail part-way.": "Şəbəkə xətası səbəbindən medianın endirilməsi yarıda qaldı.",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "Yükləmə xətası.",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "Media faylının korlanması səbəbilə və ya media faylın brauzerinizin dəstəkləmədiyi funksiyalardan istifadə etdiyinə görə medianın oxudulması dayandırılıb.",
"No compatible source was found for this media.": "Bu media üçün uyğun mənbə tapılmadı.",
"The media is encrypted and we do not have the keys to decrypt it.": "Media faylı şifrələnib və onun şifrəsini açmaq üçün açarlar yoxdur.",
"Play Video": "Videonu oynat",
"Close": "Bağla",
"Close Modal Dialog": "Modal dialoqunu bağla",
"Modal Window": "Modal pəncərəsi",
"This is a modal window": "Bu modal pəncərəsidir",
"This modal can be closed by pressing the Escape key or activating the close button.": "Bu modal Escape düyməsini basmaqla və ya bağlama düyməsini sıxmaqla bağlana bilər.",
", opens captions settings dialog": ", başlıq parametrləri dialoqunu açır",
", opens subtitles settings dialog": ", altyazı parametrləri dialoqunu açır",
", opens descriptions settings dialog": ", təsvir parametrləri dialoqunu açır",
", selected": ", seçilmiş",
"captions settings": "başlıq parametrləri",
"subtitles settings": "altyazı parametrləri",
"descriptions settings": "təsvir parametrləri",
"Text": "Tekst",
"White": "Ağ",
"Black": "Qara",
"Red": "Qırmızı",
"Green": "Yaşıl",
"Blue": "Göy",
"Yellow": "Sarı",
"Magenta": "Bənövşəyi",
"Cyan": "Mavi",
"Background": "Fon",
"Window": "Pəncərə",
"Transparent": "Şəffaf",
"Semi-Transparent": "Yarım-Şəffaf",
"Opaque": "Qeyri-şəffaf",
"Font Size": "Şrift Ölçüsü",
"Text Edge Style": "Mətnin kənarlarının üslubu",
"None": "Heç biri",
"Raised": "Artırılmış",
"Depressed": "Azaldılmış",
"Uniform": "Ümumiləşdirilmiş",
"Drop shadow": "Arxa kölgə",
"Font Family": "Şrift Ailəsi",
"Proportional Sans-Serif": "Proporsional Sans-Serif",
"Monospace Sans-Serif": "Birenli Sans-Serif",
"Proportional Serif": "Proporsional Serif",
"Monospace Serif": "Birenli Serif",
"Casual": "Gündəlik",
"Script": "Skript",
"Small Caps": "Kiçik böyük hərflər",
"Reset": "Sıfırla",
"restore all settings to the default values": "bütün parametrləri susmaya görə bərpa edin",
"Done": "Bitdi",
"Caption Settings Dialog": "Başlıq Parametrləri Dialoqu",
"Beginning of dialog window. Escape will cancel and close the window.": "Dialoq pəncərəsinin başlanğıcı. Escape düyməsi ləğv edəcək və pəncərəni bağlayacaq.",
"End of dialog window.": "Dialoq pəncərəsinin sonu.",
"{1} is loading.": "{1} yüklənir.",
"Exit Picture-in-Picture": "Şəkil içində şəkil rejimindən çıxın",
"Picture-in-Picture": "Şəkil içində şəkil rejimi",
"No content": "Məzmun yoxdur",
"Color": "Rəng",
"Opacity": "Qeyri-şəffaflıq",
"Text Background": "Tekst Fonu",
"Caption Area Background": "Başlıq Sahəsinin Fonu",
"Playing in Picture-in-Picture": "Şəkil içində şəkil rejimində oynayır",
"Skip backward {1} seconds": "{1} saniyə geriyə keçin",
"Skip forward {1} seconds": "{1} saniyə qabağa keçin"
}
+26
View File
@@ -0,0 +1,26 @@
videojs.addLanguage('ba', {
"Play": "Pusti",
"Pause": "Pauza",
"Current Time": "Trenutno vrijeme",
"Duration": "Vrijeme trajanja",
"Remaining Time": "Preostalo vrijeme",
"Stream Type": "Način strimovanja",
"LIVE": "UŽIVO",
"Loaded": "Učitan",
"Progress": "Progres",
"Fullscreen": "Puni ekran",
"Exit Fullscreen": "Mali ekran",
"Mute": "Prigušen",
"Unmute": "Ne-prigušen",
"Playback Rate": "Stopa reprodukcije",
"Subtitles": "Podnaslov",
"subtitles off": "Podnaslov deaktiviran",
"Captions": "Titlovi",
"captions off": "Titlovi deaktivirani",
"Chapters": "Poglavlja",
"You aborted the media playback": "Isključili ste reprodukciju videa.",
"A network error caused the media download to fail part-way.": "Video se prestao preuzimati zbog greške na mreži.",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "Video se ne može reproducirati zbog servera, greške u mreži ili je format ne podržan.",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "Reprodukcija videa je zaustavljenja zbog greške u formatu ili zbog verzije vašeg pretraživača.",
"No compatible source was found for this media.": "Nije nađen nijedan kompatibilan izvor ovog videa."
});
+26
View File
@@ -0,0 +1,26 @@
{
"Play": "Pusti",
"Pause": "Pauza",
"Current Time": "Trenutno vrijeme",
"Duration": "Vrijeme trajanja",
"Remaining Time": "Preostalo vrijeme",
"Stream Type": "Način strimovanja",
"LIVE": "UŽIVO",
"Loaded": "Učitan",
"Progress": "Progres",
"Fullscreen": "Puni ekran",
"Exit Fullscreen": "Mali ekran",
"Mute": "Prigušen",
"Unmute": "Ne-prigušen",
"Playback Rate": "Stopa reprodukcije",
"Subtitles": "Podnaslov",
"subtitles off": "Podnaslov deaktiviran",
"Captions": "Titlovi",
"captions off": "Titlovi deaktivirani",
"Chapters": "Poglavlja",
"You aborted the media playback": "Isključili ste reprodukciju videa.",
"A network error caused the media download to fail part-way.": "Video se prestao preuzimati zbog greške na mreži.",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "Video se ne može reproducirati zbog servera, greške u mreži ili je format ne podržan.",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "Reprodukcija videa je zaustavljenja zbog greške u formatu ili zbog verzije vašeg pretraživača.",
"No compatible source was found for this media.": "Nije nađen nijedan kompatibilan izvor ovog videa."
}
+26
View File
@@ -0,0 +1,26 @@
videojs.addLanguage('bg', {
"Play": "Възпроизвеждане",
"Pause": "Пауза",
"Current Time": "Текущо време",
"Duration": "Продължителност",
"Remaining Time": "Оставащо време",
"Stream Type": "Тип на потока",
"LIVE": "НА ЖИВО",
"Loaded": "Заредено",
"Progress": "Прогрес",
"Fullscreen": "Цял екран",
"Exit Fullscreen": "Спиране на цял екран",
"Mute": "Без звук",
"Unmute": "Със звук",
"Playback Rate": "Скорост на възпроизвеждане",
"Subtitles": "Субтитри",
"subtitles off": "Спряни субтитри",
"Captions": "Аудио надписи",
"captions off": "Спряни аудио надписи",
"Chapters": "Глави",
"You aborted the media playback": "Спряхте възпроизвеждането на видеото",
"A network error caused the media download to fail part-way.": "Грешка в мрежата провали изтеглянето на видеото.",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "Видеото не може да бъде заредено заради проблем със сървъра или мрежата или защото този формат не е поддържан.",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "Възпроизвеждането на видеото беше прекъснато заради проблем с файла или защото видеото използва опции които браузърът Ви не поддържа.",
"No compatible source was found for this media.": "Не беше намерен съвместим източник за това видео."
});
+26
View File
@@ -0,0 +1,26 @@
{
"Play": "Възпроизвеждане",
"Pause": "Пауза",
"Current Time": "Текущо време",
"Duration": "Продължителност",
"Remaining Time": "Оставащо време",
"Stream Type": "Тип на потока",
"LIVE": "НА ЖИВО",
"Loaded": "Заредено",
"Progress": "Прогрес",
"Fullscreen": "Цял екран",
"Exit Fullscreen": "Спиране на цял екран",
"Mute": "Без звук",
"Unmute": "Със звук",
"Playback Rate": "Скорост на възпроизвеждане",
"Subtitles": "Субтитри",
"subtitles off": "Спряни субтитри",
"Captions": "Аудио надписи",
"captions off": "Спряни аудио надписи",
"Chapters": "Глави",
"You aborted the media playback": "Спряхте възпроизвеждането на видеото",
"A network error caused the media download to fail part-way.": "Грешка в мрежата провали изтеглянето на видеото.",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "Видеото не може да бъде заредено заради проблем със сървъра или мрежата или защото този формат не е поддържан.",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "Възпроизвеждането на видеото беше прекъснато заради проблем с файла или защото видеото използва опции които браузърът Ви не поддържа.",
"No compatible source was found for this media.": "Не беше намерен съвместим източник за това видео."
}
+90
View File
@@ -0,0 +1,90 @@
videojs.addLanguage('bn', {
"Audio Player": "অডিও প্লেয়ার",
"Video Player": "ভিডিও প্লেয়ার",
"Play": "প্লে করুন",
"Pause": "বিরাম",
"Replay": "রিপ্লে করুন",
"Current Time": "বর্তমান সময়",
"Duration": "ব্যাপ্তিকাল",
"Remaining Time": "অবশিষ্ট সময়",
"Stream Type": "স্ট্রিমের ধরন",
"LIVE": "লাইভ",
"Seek to live, currently behind live": "লাইভ দেখুন, বর্তমানে লাইভের পিছনে আছে",
"Seek to live, currently playing live": "লাইভ দেখুন, বর্তমানে লাইভে আছে",
"Loaded": "লোড হয়েছে",
"Progress": "প্রোগ্রেস",
"Progress Bar": "প্রোগ্রেস বার",
"progress bar timing: currentTime={1} duration={2}": "{2} এর {1}",
"Fullscreen": "পূর্ণ স্ক্রীন",
"Non-Fullscreen": "পূর্ণ স্ক্রীন থেকে প্রস্থান করুন",
"Mute": "মিউট",
"Unmute": "আনমিউট",
"Playback Rate": "প্লেব্যাক রেট",
"Subtitles": "সাবটাইটেল",
"subtitles off": "সাবটাইটেল বন্ধ করুন",
"Captions": "ক্যাপশন",
"captions off": "ক্যাপশন বন্ধ করুন",
"Chapters": "অধ্যায়",
"Descriptions": "বর্ণনা",
"descriptions off": "বর্ণনা বন্ধ করুন",
"Audio Track": "অডিও গান",
"Volume Level": "ভলিউম লেভেল",
"You aborted the media playback": "আপনি মিডিয়া প্লেব্যাক বাতিল করেছেন",
"A network error caused the media download to fail part-way.": "একটি নেটওয়ার্ক ত্রুটির কারণে মিডিয়া ডাউনলোড আংশিকভাবে ব্যর্থ হয়েছে৷",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "মিডিয়া লোড করা যায়নি, হয় সার্ভার বা নেটওয়ার্ক ব্যর্থ হওয়ার কারণে বা ফর্ম্যাটটি সমর্থিত নয়।",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "মিডিয়া প্লেব্যাক একটি সমস্যার কারণে বা মিডিয়া ব্যবহার করা বৈশিষ্ট্যগুলি আপনার ব্রাউজার সমর্থন করে না বলে বাতিল করা হয়েছে৷",
"No compatible source was found for this media.": "এই মিডিয়ার জন্য কোন সামঞ্জস্যপূর্ণ উৎস পাওয়া যায়নি.",
"The media is encrypted and we do not have the keys to decrypt it.": "মিডিয়া এনক্রিপ্ট করা হয়েছে এবং এটি ডিক্রিপ্ট করার সমাধান আমাদের কাছে নেই।",
"Play Video": "ভিডিও প্লে করুন",
"Close": "বন্ধ করুন",
"Close Modal Dialog": "মোডাল ডায়ালগ বন্ধ করুন",
"Modal Window": "মোডাল উইন্ডো",
"This is a modal window": "এটি একটি মোডাল উইন্ডো",
"This modal can be closed by pressing the Escape key or activating the close button.": "Esc কী চেপে বা ক্লোজ বাটনটি সক্রিয় করে এই মডেলটি বন্ধ করা যেতে পারে।",
", opens captions settings dialog": ", ক্যাপশন সেটিংস ডায়ালগ খোলে",
", opens subtitles settings dialog": ", সাবটাইটেল সেটিংস ডায়ালগ খোলে",
", opens descriptions settings dialog": ", বর্ণনা সেটিংস ডায়ালগ খোলে",
", selected": ", নির্বাচিত",
"captions settings": "ক্যাপশন সেটিংস",
"subtitles settings": "সাবটাইটেল সেটিংস ",
"descriptions settings": "বর্ণনা সেটিংস",
"Text": "টেক্সট",
"White": "সাদা",
"Black": "কালো",
"Red": "লাল",
"Green": "সবুজ",
"Blue": "নীল",
"Yellow": "হলুদ",
"Magenta": "ম্যাজেন্টা",
"Cyan": "নীল সবুজ",
"Background": "পটভূমি",
"Window": "উইন্ডো",
"Transparent": "স্বচ্ছ",
"Semi-Transparent": "আধা-স্বচ্ছ",
"Opaque": "অস্বচ্ছ",
"Font Size": "অক্ষরের আকার",
"Text Edge Style": "টেক্সট এজ স্টাইল",
"None": "কোনোটিই নয়",
"Raised": "বাড়ানো হয়েছে",
"Depressed": "নামানো হয়েছে",
"Uniform": "ইউনিফর্ম",
"Drop shadow": "ড্রপশ্যাডো",
"Font Family": "অক্ষরের পরিবার",
"Proportional Sans-Serif": "সমানুপাতিক সানস-সেরিফ",
"Monospace Sans-Serif": "মনোস্পেস সানস-সেরিফ",
"Proportional Serif": "সমানুপাতিক সেরিফ",
"Monospace Serif": "মনোস্পেস সেরিফ",
"Casual": "ক্যাজুয়াল",
"Script": "স্ক্রিপ্ট",
"Small Caps": "ছোট ক্যাপস",
"Reset": "রিসেট",
"restore all settings to the default values": "সমস্ত সেটিংস ডিফল্ট মানগুলিতে পুনরুদ্ধার করুন",
"Done": "সম্পন্ন",
"Caption Settings Dialog": "ক্যাপশন সেটিংস ডায়ালগ",
"Beginning of dialog window. Escape will cancel and close the window.": "ডায়লগ উইন্ডোর শুরু। Esc কী বাতিল করবে এবং উইন্ডো বন্ধ করবে।",
"End of dialog window.": "ডায়ালগ উইন্ডোর শেষ।",
"{1} is loading.": "{1} লোড হচ্ছে.",
"Exit Picture-in-Picture": "পিকচার-ইন-পিকচার থেকে প্রস্থান করুন",
"Picture-in-Picture": "পিকচার-ইন-পিকচার",
"No content": "কোন বিষয়বস্তু নেই"
});
+90
View File
@@ -0,0 +1,90 @@
{
"Audio Player": "অডিও প্লেয়ার",
"Video Player": "ভিডিও প্লেয়ার",
"Play": "প্লে করুন",
"Pause": "বিরাম",
"Replay": "রিপ্লে করুন",
"Current Time": "বর্তমান সময়",
"Duration": "ব্যাপ্তিকাল",
"Remaining Time": "অবশিষ্ট সময়",
"Stream Type": "স্ট্রিমের ধরন",
"LIVE": "লাইভ",
"Seek to live, currently behind live": "লাইভ দেখুন, বর্তমানে লাইভের পিছনে আছে",
"Seek to live, currently playing live": "লাইভ দেখুন, বর্তমানে লাইভে আছে",
"Loaded": "লোড হয়েছে",
"Progress": "প্রোগ্রেস",
"Progress Bar": "প্রোগ্রেস বার",
"progress bar timing: currentTime={1} duration={2}": "{2} এর {1}",
"Fullscreen": "পূর্ণ স্ক্রীন",
"Non-Fullscreen": "পূর্ণ স্ক্রীন থেকে প্রস্থান করুন",
"Mute": "মিউট",
"Unmute": "আনমিউট",
"Playback Rate": "প্লেব্যাক রেট",
"Subtitles": "সাবটাইটেল",
"subtitles off": "সাবটাইটেল বন্ধ করুন",
"Captions": "ক্যাপশন",
"captions off": "ক্যাপশন বন্ধ করুন",
"Chapters": "অধ্যায়",
"Descriptions": "বর্ণনা",
"descriptions off": "বর্ণনা বন্ধ করুন",
"Audio Track": "অডিও গান",
"Volume Level": "ভলিউম লেভেল",
"You aborted the media playback": "আপনি মিডিয়া প্লেব্যাক বাতিল করেছেন",
"A network error caused the media download to fail part-way.": "একটি নেটওয়ার্ক ত্রুটির কারণে মিডিয়া ডাউনলোড আংশিকভাবে ব্যর্থ হয়েছে৷",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "মিডিয়া লোড করা যায়নি, হয় সার্ভার বা নেটওয়ার্ক ব্যর্থ হওয়ার কারণে বা ফর্ম্যাটটি সমর্থিত নয়।",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "মিডিয়া প্লেব্যাক একটি সমস্যার কারণে বা মিডিয়া ব্যবহার করা বৈশিষ্ট্যগুলি আপনার ব্রাউজার সমর্থন করে না বলে বাতিল করা হয়েছে৷",
"No compatible source was found for this media.": "এই মিডিয়ার জন্য কোন সামঞ্জস্যপূর্ণ উৎস পাওয়া যায়নি.",
"The media is encrypted and we do not have the keys to decrypt it.": "মিডিয়া এনক্রিপ্ট করা হয়েছে এবং এটি ডিক্রিপ্ট করার সমাধান আমাদের কাছে নেই।",
"Play Video": "ভিডিও প্লে করুন",
"Close": "বন্ধ করুন",
"Close Modal Dialog": "মোডাল ডায়ালগ বন্ধ করুন",
"Modal Window": "মোডাল উইন্ডো",
"This is a modal window": "এটি একটি মোডাল উইন্ডো",
"This modal can be closed by pressing the Escape key or activating the close button.": "Esc কী চেপে বা ক্লোজ বাটনটি সক্রিয় করে এই মডেলটি বন্ধ করা যেতে পারে।",
", opens captions settings dialog": ", ক্যাপশন সেটিংস ডায়ালগ খোলে",
", opens subtitles settings dialog": ", সাবটাইটেল সেটিংস ডায়ালগ খোলে",
", opens descriptions settings dialog": ", বর্ণনা সেটিংস ডায়ালগ খোলে",
", selected": ", নির্বাচিত",
"captions settings": "ক্যাপশন সেটিংস",
"subtitles settings": "সাবটাইটেল সেটিংস ",
"descriptions settings": "বর্ণনা সেটিংস",
"Text": "টেক্সট",
"White": "সাদা",
"Black": "কালো",
"Red": "লাল",
"Green": "সবুজ",
"Blue": "নীল",
"Yellow": "হলুদ",
"Magenta": "ম্যাজেন্টা",
"Cyan": "নীল সবুজ",
"Background": "পটভূমি",
"Window": "উইন্ডো",
"Transparent": "স্বচ্ছ",
"Semi-Transparent": "আধা-স্বচ্ছ",
"Opaque": "অস্বচ্ছ",
"Font Size": "অক্ষরের আকার",
"Text Edge Style": "টেক্সট এজ স্টাইল",
"None": "কোনোটিই নয়",
"Raised": "বাড়ানো হয়েছে",
"Depressed": "নামানো হয়েছে",
"Uniform": "ইউনিফর্ম",
"Drop shadow": "ড্রপশ্যাডো",
"Font Family": "অক্ষরের পরিবার",
"Proportional Sans-Serif": "সমানুপাতিক সানস-সেরিফ",
"Monospace Sans-Serif": "মনোস্পেস সানস-সেরিফ",
"Proportional Serif": "সমানুপাতিক সেরিফ",
"Monospace Serif": "মনোস্পেস সেরিফ",
"Casual": "ক্যাজুয়াল",
"Script": "স্ক্রিপ্ট",
"Small Caps": "ছোট ক্যাপস",
"Reset": "রিসেট",
"restore all settings to the default values": "সমস্ত সেটিংস ডিফল্ট মানগুলিতে পুনরুদ্ধার করুন",
"Done": "সম্পন্ন",
"Caption Settings Dialog": "ক্যাপশন সেটিংস ডায়ালগ",
"Beginning of dialog window. Escape will cancel and close the window.": "ডায়লগ উইন্ডোর শুরু। Esc কী বাতিল করবে এবং উইন্ডো বন্ধ করবে।",
"End of dialog window.": "ডায়ালগ উইন্ডোর শেষ।",
"{1} is loading.": "{1} লোড হচ্ছে.",
"Exit Picture-in-Picture": "পিকচার-ইন-পিকচার থেকে প্রস্থান করুন",
"Picture-in-Picture": "পিকচার-ইন-পিকচার",
"No content": "কোন বিষয়বস্তু নেই"
}
+97
View File
@@ -0,0 +1,97 @@
videojs.addLanguage('ca', {
"Audio Player": "Reproductor d'àudio",
"Video Player": "Reproductor de vídeo",
"Play": "Reproduir",
"Pause": "Pausa",
"Replay": "Repetir",
"Current Time": "Temps actual",
"Duration": "Durada",
"Remaining Time": "Temps restant",
"Stream Type": "Tipus d'emissió",
"LIVE": "EN DIRECTE",
"Seek to live, currently behind live": "Anar en directe, actualment darrere de la retransmissió en directe",
"Seek to live, currently playing live": "Anar en directe, actualment en directe",
"Loaded": "Carregat",
"Progress": "Progrés",
"Progress Bar": "Barra de progrés",
"progress bar timing: currentTime={1} duration={2}": "{1} de {2}",
"Fullscreen": "Pantalla completa",
"Exit Fullscreen": "Sortir de pantalla completa",
"Mute": "Silenciar",
"Unmute": "Activar el so",
"Playback Rate": "Velocitat de reproducció",
"Subtitles": "Subtítols",
"subtitles off": "Desactivar subtítols",
"Captions": "Llegendes",
"captions off": "Desactivar llegendes",
"Chapters": "Capítols",
"Descriptions": "Descripcions",
"descriptions off": "Desactivar descripcions",
"Audio Track": "Pista d'àudio",
"Volume Level": "Nivell de volum",
"You aborted the media playback": "Has interromput la reproducció del contingut",
"A network error caused the media download to fail part-way.": "Un error de xarxa ha interromput la descàrrega del contingut.",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "No s'ha pogut carregar el contingut, ja sigui perquè el servidor o la xarxa han fallat o perquè el format no està suportat.",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "La reproducció del contingut s'ha interromput a causa d'un problema de corrupció o perquè el contingut fa servir funcions que el teu navegador no suporta.",
"No compatible source was found for this media.": "No s'ha trobat una font compatible per a aquest contingut.",
"The media is encrypted and we do not have the keys to decrypt it.": "El contingut està xifrat i no disposem de les claus per desxifrar-lo.",
"Play Video": "Reproduir vídeo",
"Close": "Tancar",
"Close Modal Dialog": "Tancar el diàleg modal",
"Modal Window": "Finestra modal",
"This is a modal window": "Aquesta és una finestra modal",
"This modal can be closed by pressing the Escape key or activating the close button.": "Aquesta finestra es pot tancar prement la tecla Escape o activant el botó de tancar.",
", opens captions settings dialog": ", obre el diàleg de configuració de subtítols",
", opens subtitles settings dialog": ", obre el diàleg de configuració de subtítols",
", opens descriptions settings dialog": ", obre el diàleg de configuració de descripcions",
", selected": ", seleccionat",
"captions settings": "configuració de subtítols",
"subtitles settings": "configuració de subtítols",
"descriptions settings": "configuració de descripcions",
"Text": "Text",
"White": "Blanc",
"Black": "Negre",
"Red": "Vermell",
"Green": "Verd",
"Blue": "Blau",
"Yellow": "Groc",
"Magenta": "Magenta",
"Cyan": "Cian",
"Background": "Fons",
"Window": "Finestra",
"Transparent": "Transparent",
"Semi-Transparent": "Semi-transparent",
"Opaque": "Opac",
"Font Size": "Mida de la lletra",
"Text Edge Style": "Estil de la vora del text",
"None": "Cap",
"Raised": "Rellevat",
"Depressed": "Premut",
"Uniform": "Uniforme",
"Drop shadow": "Ombra",
"Font Family": "Família tipogràfica",
"Proportional Sans-Serif": "Sense serif proporcional",
"Monospace Sans-Serif": "Monoespaiada sense serif",
"Proportional Serif": "Serif proporcional",
"Monospace Serif": "Monoespaiada amb serif",
"Casual": "Desenfadada",
"Script": "Script",
"Small Caps": "Minúscules",
"Reset": "Restablir",
"restore all settings to the default values": "restaurar totes les configuracions als valors predeterminats",
"Done": "Fet",
"Caption Settings Dialog": "Diàleg de configuració de subtítols",
"Beginning of dialog window. Escape will cancel and close the window.": "Inici del diàleg. L'Escape cancel·larà i tancarà la finestra.",
"End of dialog window.": "Fi del diàleg.",
"{1} is loading.": "S'està carregant {1}.",
"Exit Picture-in-Picture": "Sortir de la imatge en imatge",
"Picture-in-Picture": "Imatge en imatge",
"No content": "Sense contingut",
"Color": "Color",
"Opacity": "Opacitat",
"Text Background": "Fons del text",
"Caption Area Background": "Fons de l'àrea de subtítols",
"Playing in Picture-in-Picture": "Reproduint en imatge en imatge",
"Skip backward {1} seconds": "Salta enrere {1} segons",
"Skip forward {1} seconds": "Salta endavant {1} segons"
});
+97
View File
@@ -0,0 +1,97 @@
{
"Audio Player": "Reproductor d'àudio",
"Video Player": "Reproductor de vídeo",
"Play": "Reproduir",
"Pause": "Pausa",
"Replay": "Repetir",
"Current Time": "Temps actual",
"Duration": "Durada",
"Remaining Time": "Temps restant",
"Stream Type": "Tipus d'emissió",
"LIVE": "EN DIRECTE",
"Seek to live, currently behind live": "Anar en directe, actualment darrere de la retransmissió en directe",
"Seek to live, currently playing live": "Anar en directe, actualment en directe",
"Loaded": "Carregat",
"Progress": "Progrés",
"Progress Bar": "Barra de progrés",
"progress bar timing: currentTime={1} duration={2}": "{1} de {2}",
"Fullscreen": "Pantalla completa",
"Exit Fullscreen": "Sortir de pantalla completa",
"Mute": "Silenciar",
"Unmute": "Activar el so",
"Playback Rate": "Velocitat de reproducció",
"Subtitles": "Subtítols",
"subtitles off": "Desactivar subtítols",
"Captions": "Llegendes",
"captions off": "Desactivar llegendes",
"Chapters": "Capítols",
"Descriptions": "Descripcions",
"descriptions off": "Desactivar descripcions",
"Audio Track": "Pista d'àudio",
"Volume Level": "Nivell de volum",
"You aborted the media playback": "Has interromput la reproducció del contingut",
"A network error caused the media download to fail part-way.": "Un error de xarxa ha interromput la descàrrega del contingut.",
"The media could not be loaded, either because the server or network failed or because the format is not supported.": "No s'ha pogut carregar el contingut, ja sigui perquè el servidor o la xarxa han fallat o perquè el format no està suportat.",
"The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "La reproducció del contingut s'ha interromput a causa d'un problema de corrupció o perquè el contingut fa servir funcions que el teu navegador no suporta.",
"No compatible source was found for this media.": "No s'ha trobat una font compatible per a aquest contingut.",
"The media is encrypted and we do not have the keys to decrypt it.": "El contingut està xifrat i no disposem de les claus per desxifrar-lo.",
"Play Video": "Reproduir vídeo",
"Close": "Tancar",
"Close Modal Dialog": "Tancar el diàleg modal",
"Modal Window": "Finestra modal",
"This is a modal window": "Aquesta és una finestra modal",
"This modal can be closed by pressing the Escape key or activating the close button.": "Aquesta finestra es pot tancar prement la tecla Escape o activant el botó de tancar.",
", opens captions settings dialog": ", obre el diàleg de configuració de subtítols",
", opens subtitles settings dialog": ", obre el diàleg de configuració de subtítols",
", opens descriptions settings dialog": ", obre el diàleg de configuració de descripcions",
", selected": ", seleccionat",
"captions settings": "configuració de subtítols",
"subtitles settings": "configuració de subtítols",
"descriptions settings": "configuració de descripcions",
"Text": "Text",
"White": "Blanc",
"Black": "Negre",
"Red": "Vermell",
"Green": "Verd",
"Blue": "Blau",
"Yellow": "Groc",
"Magenta": "Magenta",
"Cyan": "Cian",
"Background": "Fons",
"Window": "Finestra",
"Transparent": "Transparent",
"Semi-Transparent": "Semi-transparent",
"Opaque": "Opac",
"Font Size": "Mida de la lletra",
"Text Edge Style": "Estil de la vora del text",
"None": "Cap",
"Raised": "Rellevat",
"Depressed": "Premut",
"Uniform": "Uniforme",
"Drop shadow": "Ombra",
"Font Family": "Família tipogràfica",
"Proportional Sans-Serif": "Sense serif proporcional",
"Monospace Sans-Serif": "Monoespaiada sense serif",
"Proportional Serif": "Serif proporcional",
"Monospace Serif": "Monoespaiada amb serif",
"Casual": "Desenfadada",
"Script": "Script",
"Small Caps": "Minúscules",
"Reset": "Restablir",
"restore all settings to the default values": "restaurar totes les configuracions als valors predeterminats",
"Done": "Fet",
"Caption Settings Dialog": "Diàleg de configuració de subtítols",
"Beginning of dialog window. Escape will cancel and close the window.": "Inici del diàleg. L'Escape cancel·larà i tancarà la finestra.",
"End of dialog window.": "Fi del diàleg.",
"{1} is loading.": "S'està carregant {1}.",
"Exit Picture-in-Picture": "Sortir de la imatge en imatge",
"Picture-in-Picture": "Imatge en imatge",
"No content": "Sense contingut",
"Color": "Color",
"Opacity": "Opacitat",
"Text Background": "Fons del text",
"Caption Area Background": "Fons de l'àrea de subtítols",
"Playing in Picture-in-Picture": "Reproduint en imatge en imatge",
"Skip backward {1} seconds": "Salta enrere {1} segons",
"Skip forward {1} seconds": "Salta endavant {1} segons"
}

Some files were not shown because too many files have changed in this diff Show More