+2021-04-15 Chris Gambrell <cgambrell@apple.com>
+
+ [LayoutTests] Convert http/tests/media convert PHP to Python
+ https://bugs.webkit.org/show_bug.cgi?id=224528
+ <rdar://problem/76627995>
+
+ Reviewed by Jonathan Bedard.
+
+ * http/tests/media/media-document-referer.html:
+ * http/tests/media/media-document.html:
+ * http/tests/media/media-play-stream-chunked-icy.html:
+ * http/tests/media/media-seeking-no-ranges-server.html:
+ * http/tests/media/modern-media-controls/macos-fullscreen-media-controls/macos-fullscreen-media-controls-live-broadcast.html:
+ * http/tests/media/modern-media-controls/pip-support/pip-support-live-broadcast.html:
+ * http/tests/media/modern-media-controls/skip-back-support/skip-back-support-button-click.html:
+ * http/tests/media/modern-media-controls/skip-back-support/skip-back-support-live-broadcast.html:
+ * http/tests/media/modern-media-controls/status-support/status-support-live-broadcast.html:
+ * http/tests/media/modern-media-controls/time-control/1-to-10-hours.html:
+ * http/tests/media/modern-media-controls/time-control/10-hours-or-more.html:
+ * http/tests/media/modern-media-controls/time-control/10-minutes-to-1-hour.html:
+ * http/tests/media/modern-media-controls/time-control/less-than-10-minutes.html:
+ * http/tests/media/resources/create-id3-db.php:
+ * http/tests/media/resources/hls/generate-vod.php: Removed.
+ * http/tests/media/resources/hls/generate-vod.py: Added.
+ * http/tests/media/resources/hls/playlist-with-cookie.m3u8:
+ * http/tests/media/resources/hls/sub-playlist-with-cookie.php: Removed.
+ * http/tests/media/resources/hls/sub-playlist-with-cookie.py: Added.
+ * http/tests/media/resources/hls/test-live.php: Removed.
+ * http/tests/media/resources/hls/test-live.py: Added.
+ * http/tests/media/resources/load-video.php: Removed.
+ * http/tests/media/resources/load-video.py: Added.
+ * http/tests/media/resources/serve-video.php: Removed.
+ * http/tests/media/resources/serve_video.py:
+ (answering):
+ * http/tests/media/resources/video-auth.php: Removed.
+ * http/tests/media/resources/video-auth.py: Added.
+ * http/tests/media/resources/video-check-useragent.php: Removed.
+ * http/tests/media/resources/video-check-useragent.py: Added.
+ * http/tests/media/resources/video-cookie-check-cookie.php: Removed.
+ * http/tests/media/resources/video-cookie-check-cookie.py: Added.
+ * http/tests/media/resources/video-referer-check-referer.php: Removed.
+ * http/tests/media/resources/video-referer-check-referer.py: Added.
+ * http/tests/media/video-auth-expected.txt:
+ * http/tests/media/video-auth-with-allowCrossOriginSubresourcesToAskForCredentials-expected.txt:
+ * http/tests/media/video-auth-with-allowCrossOriginSubresourcesToAskForCredentials.html:
+ * http/tests/media/video-auth.html:
+ * http/tests/media/video-cookie.html:
+ * http/tests/media/video-no-content-length-stall.html:
+ * http/tests/media/video-play-stall.html:
+ * http/tests/media/video-play-waiting.html:
+ * http/tests/media/video-query-url.html:
+ * http/tests/media/video-referer.html:
+ * http/tests/media/video-useragent.html:
+ * media/content/metadata.db: Removed.
+ * media/content/metadata.json: Added.
+
2021-04-15 Youenn Fablet <youenn@apple.com>
Make RTCEncodedVideoFrameMetadata.contributingSources undefined until properly supported
frame.width = "100%";
frame.height = "100%";
frame.onload = videoTest;
- frame.src = 'http://127.0.0.1:8000/media/resources/video-referer-check-referer.php?referer=media-document-referer.html&name=' + movie + '&type=' + type;
+ frame.src = 'http://127.0.0.1:8000/media/resources/video-referer-check-referer.py?referer=media-document-referer.html&name=' + movie + '&type=' + type;
document.body.appendChild(frame);
}
</script>
});
waitForEventAndFail('error');
waitForEventAndEnd('canplay');
- frame.src = 'resources/video-check-useragent.php?name=' + movie + '&type=' + type;
+ frame.src = 'resources/video-check-useragent.py?name=' + movie + '&type=' + type;
document.body.appendChild(frame);
}
</script>
var type = mimeTypeForExtension(media.split('.').pop());
var audio = document.querySelector("audio");
- audio.src = 'http://127.0.0.1:8000/media/resources/serve-video.php?name=' + media + '&type=' + type + '&content-length=no&icy-data=yes';
+ audio.src = 'http://127.0.0.1:8000/media/resources/serve_video.py?name=' + media + '&type=' + type + '&content-length=no&icy-data=yes';
waitForEventAndFail('error');
waitForEventAndEnd('ended');
function start()
{
audio = document.querySelector("audio");
- audio.src = 'http://127.0.0.1:8000/media/resources/load-video.php?name=' + media + '&type=' + type + '&ranges=no';
+ audio.src = 'http://127.0.0.1:8000/media/resources/load-video.py?name=' + media + '&type=' + type + '&ranges=no';
waitForEventAndFail('error');
waitForEventAndEnd('ended');
<script src="/media-resources/modern-media-controls/resources/media-controls-loader.js"></script>
<script src="/media-resources/modern-media-controls/resources/media-controls-utils.js"></script>
<body>
-<video src="../../resources/hls/test-live.php" style="width: 400px; height: 300px;" autoplay controls></video>
+<video src="../../resources/hls/test-live.py" style="width: 400px; height: 300px;" autoplay controls></video>
<div id="shadow"></div>
<script type="text/javascript">
<script src="../../../../../resources/js-test-pre.js"></script>
<script src="/media-resources/modern-media-controls/resources/media-controls-loader.js"></script>
<body>
-<video src="../../resources/hls/test-live.php" style="width: 800px;" autoplay controls></video>
+<video src="../../resources/hls/test-live.py" style="width: 800px;" autoplay controls></video>
<div id="shadow"></div>
<script type="text/javascript">
<script src="../../../../../resources/js-test-pre.js"></script>
<script src="/media-resources/modern-media-controls/resources/media-controls-loader.js"></script>
<body>
-<video src="../../resources/hls/generate-vod.php?duration=8000" style="width: 320px; height: 240px;" controls></video>
+<video src="../../resources/hls/generate-vod.py?duration=8000" style="width: 320px; height: 240px;" controls></video>
<div id="shadow"></div>
<script type="text/javascript">
<script src="../../../../../resources/js-test-pre.js"></script>
<script src="/media-resources/modern-media-controls/resources/media-controls-loader.js"></script>
<body>
-<video src="../../resources/hls/test-live.php" style="width: 800px;" autoplay controls></video>
+<video src="../../resources/hls/test-live.py" style="width: 800px;" autoplay controls></video>
<div id="shadow"></div>
<script type="text/javascript">
<script src="../../../../../resources/js-test-pre.js"></script>
<script src="/media-resources/modern-media-controls/resources/media-controls-loader.js"></script>
<body>
-<video src="../../resources/hls/test-live.php" style="width: 320px; height: 240px;" autoplay controls></video>
+<video src="../../resources/hls/test-live.py" style="width: 320px; height: 240px;" autoplay controls></video>
<div id="shadow"></div>
<script type="text/javascript">
<script src="../../../../../resources/js-test-pre.js"></script>
<script src="/media-resources/modern-media-controls/resources/media-controls-loader.js"></script>
<body>
-<video src="../../resources/hls/generate-vod.php?duration=8000" style="width: 320px; height: 240px;" controls autoplay></video>
+<video src="../../resources/hls/generate-vod.py?duration=8000" style="width: 320px; height: 240px;" controls autoplay></video>
<div id="shadow"></div>
<script type="text/javascript">
<script src="../../../../../resources/js-test-pre.js"></script>
<script src="/media-resources/modern-media-controls/resources/media-controls-loader.js"></script>
<body>
-<video src="../../resources/hls/generate-vod.php?duration=36001" style="width: 320px; height: 240px;" controls autoplay></video>
+<video src="../../resources/hls/generate-vod.py?duration=36001" style="width: 320px; height: 240px;" controls autoplay></video>
<div id="shadow"></div>
<script type="text/javascript">
<script src="../../../../../resources/js-test-pre.js"></script>
<script src="/media-resources/modern-media-controls/resources/media-controls-loader.js"></script>
<body>
-<video src="../../resources/hls/generate-vod.php?duration=800" style="width: 320px; height: 240px;" controls autoplay></video>
+<video src="../../resources/hls/generate-vod.py?duration=800" style="width: 320px; height: 240px;" controls autoplay></video>
<div id="shadow"></div>
<script type="text/javascript">
<script src="../../../../../resources/js-test-pre.js"></script>
<script src="/media-resources/modern-media-controls/resources/media-controls-loader.js"></script>
<body>
-<video src="../../resources/hls/generate-vod.php?duration=599" style="width: 320px; height: 240px;" controls autoplay></video>
+<video src="../../resources/hls/generate-vod.py?duration=599" style="width: 320px; height: 240px;" controls autoplay></video>
<div id="shadow"></div>
<script type="text/javascript">
// This script creates, overwriting if needed, the "metadata.db"
- // file used by scripts such as "serve-video.php".
+ // file used by scripts such as "serve-video.py".
//
// For creating or updating an existing file you have to run the
// http server used by the tests with:
+++ /dev/null
-<?php
-# See the HLS ITEF spec: <http://tools.ietf.org/id/draft-pantos-http-live-streaming-12.txt>
-header("Status: 200 OK");
-header("HTTP/1.1 200 OK");
-header("Connection: close");
-header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
-header("Pragma: no-cache");
-header("Etag: " . '"' . filesize(__FILE__) . "-" . filemtime(__FILE__) . '"');
-header("Content-Type: application/x-mpegurl");
-
-$chunkDuration = 6.0272;
-$chunkCount = 5;
-if (array_key_exists("duration", $_GET))
- $chunkCount = intval($_GET["duration"] / $chunkDuration);
-
-function println($string) { return print($string . PHP_EOL); }
-println("#EXTM3U");
-println("#EXT-X-TARGETDURATION:7");
-println("#EXT-X-VERSION:4");
-println("#EXT-X-MEDIA-SEQUENCE:0");
-println("#EXT-X-PLAYLIST-TYPE:VOD");
-
-for ($i = 0; $i < $chunkCount; ++$i) {
- println("#EXTINF:" . $chunkDuration . ",");
- println("test.ts");
-}
-
-println("#EXT-X-ENDLIST");
--- /dev/null
+#!/usr/bin/env python3
+
+# See the HLS ITEF spec: <http://tools.ietf.org/id/draft-pantos-http-live-streaming-12.txt>
+
+import os
+import sys
+from datetime import datetime
+from urllib.parse import parse_qs
+
+query = parse_qs(os.environ.get('QUERY_STRING', ''), keep_blank_values=True)
+last_modified = datetime.utcnow()
+
+sys.stdout.write(
+ 'status: 200\r\n'
+ 'Connection: close\r\n'
+ 'Last-Modified: {modified} GMT\r\n'
+ 'Pragma: no-cache\r\n'
+ 'Etag: "{size}-{mtime}"\r\n'
+ 'Content-Type: application/x-mpegurl\r\n\r\n'.format(modified=last_modified.strftime('%a, %d %b %Y %H:%M:%S'), size=os.path.getsize(__file__), mtime=os.stat(__file__).st_mtime)
+)
+
+chunk_duration = 6.0272
+chunk_count = 5
+if 'duration' in query.keys():
+ chunk_count = int(int(query.get('duration')[0]) / chunk_duration)
+
+sys.stdout.write(
+ '#EXTM3U\n'
+ '#EXT-X-TARGETDURATION:7\n'
+ '#EXT-X-VERSION:4\n'
+ '#EXT-X-MEDIA-SEQCE:0\n'
+ '#EXT-X-PLAYLIST-TYPE:VOD\n'
+)
+
+for _ in range(0, chunk_count):
+ sys.stdout.write(
+ '#EXTINF:{},\n'
+ 'test.ts\n'.format(chunk_duration)
+ )
+
+sys.stdout.write('#EXT-X-ENDLIST\n')
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=34000
-sub-playlist-with-cookie.php
+sub-playlist-with-cookie.py
+++ /dev/null
-<?php
-# See the HLS ITEF spec: <http://tools.ietf.org/id/draft-pantos-http-live-streaming-12.txt>
-header("Status: 200 OK");
-header("HTTP/1.1 200 OK");
-header("Connection: close");
-header('Cache-Control: no-store, no-cache="set-cookie"\n');
-header("Access-Control-Allow-Origin: *");
-header("Etag: " . '"' . filesize(__FILE__) . "-" . filemtime(__FILE__) . '"');
-header("Set-Cookie: TEST=test.ts; path=/media/resources/");
-header("Content-Type: application/x-mpegurl");
-header("Content-Length: " . filesize(__FILE__));
-
-$chunkDuration = 6.0272;
-$chunkCount = 4;
-
-function println($string) { return print($string . PHP_EOL); }
-
-println("#EXTM3U");
-println("#EXT-X-TARGETDURATION:7");
-println("#EXT-X-VERSION:4");
-println("#EXT-X-MEDIA-SEQUENCE:" . (time() / $chunkDuration % 100));
-
-$time = time();
-$time = $time - $time % $chunkDuration;
-
-for ($i = 0; $i < $chunkCount; ++$i) {
- $time += 6;
- println("#EXT-X-PROGRAM-DATE-TIME:" . gmdate("c", $time));
- println("#EXTINF:" . $chunkDuration . ",");
- println("../video-cookie-check-cookie.php");
-}
-?>
--- /dev/null
+#!/usr/bin/env python3
+
+# See the HLS ITEF spec: <http://tools.ietf.org/id/draft-pantos-http-live-streaming-12.txt>
+
+import os
+import sys
+from datetime import datetime
+
+sys.stdout.write(
+ 'status: 200\r\n'
+ 'Connection: close\r\n'
+ 'Cache-Control: no-store, no-cache="set-cookie"\\n\r\n'
+ 'Access-Control-Allow-Origin: *\r\n'
+ 'Pragma: no-cache\r\n'
+ 'Etag: "{size}-{mtime}"\r\n'
+ 'Set-Cookie: TEST=test.ts; path=/media/resources/\r\n'
+ 'Content-Type: application/x-mpegurl\r\n\r\n'.format(size=os.path.getsize(__file__), mtime=str(os.stat(__file__).st_mtime).split('.')[0])
+)
+
+chunk_duration = 6.0272
+chunk_count = 4
+
+sys.stdout.write(
+ '#EXTM3U\n'
+ '#EXT-X-TARGETDURATION:7\n'
+ '#EXT-X-VERSION:4\n'
+ '#EXT-X-MEDIA-SEQUENCE:{}\n'.format(int(datetime.utcnow().timestamp() / chunk_duration) % 100)
+)
+
+time = datetime.utcnow()
+time = time.timestamp() - time.timestamp() % chunk_duration
+
+for _ in range(0, chunk_count):
+ sys.stdout.write(
+ '#EXT-X-PROGRAM-DATE-TIME:{}T{}+00:00\n'
+ '#EXTINF:{},\n'
+ '../video-cookie-check-cookie.py\n'.format(datetime.fromtimestamp(time).strftime('%Y-%m-%d'), datetime.fromtimestamp(time).strftime('%H:%M:%S'), chunk_duration)
+ )
+++ /dev/null
-<?php
-# See the HLS ITEF spec: <http://tools.ietf.org/id/draft-pantos-http-live-streaming-12.txt>
-header("Status: 200 OK");
-header("HTTP/1.1 200 OK");
-header("Connection: close");
-header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
-header("Pragma: no-cache");
-header("Etag: " . '"' . filesize(__FILE__) . "-" . filemtime(__FILE__) . '"');
-header("Content-Type: application/x-mpegurl");
-header("Content-Length: " . filesize(__FILE__));
-
-$chunkDuration = 6.0272;
-if (array_key_exists("duration", $_GET))
- $chunkDuration = floatval($_GET["duration"]);
-
-$chunkCount = 4;
-if (array_key_exists("count", $_GET))
- $chunkCount = intval($_GET["count"]);
-
-$chunkURL = "test.ts";
-if (array_key_exists("url", $_GET))
- $chunkURL = $_GET["url"];
-
-function println($string) { return print($string . PHP_EOL); }
-println("#EXTM3U");
-println("#EXT-X-TARGETDURATION:7");
-println("#EXT-X-VERSION:4");
-println("#EXT-X-MEDIA-SEQUENCE:" . (time() / $chunkDuration % 100));
-
-$time = time();
-$time = $time - $time % $chunkDuration;
-
-for ($i = 0; $i < $chunkCount; ++$i) {
- $time += $chunkDuration;
- println("#EXT-X-PROGRAM-DATE-TIME:" . gmdate("c", $time));
- println("#EXTINF:" . $chunkDuration . ",");
- println($chunkURL);
-}
--- /dev/null
+#!/usr/bin/env python3
+
+# See the HLS ITEF spec: <http://tools.ietf.org/id/draft-pantos-http-live-streaming-12.txt>
+
+import os
+import sys
+from datetime import datetime
+from urllib.parse import parse_qs
+
+query = parse_qs(os.environ.get('QUERY_STRING', ''), keep_blank_values=True)
+last_modified = datetime.utcnow()
+
+sys.stdout.write(
+ 'status: 200\r\n'
+ 'Connection: close\r\n'
+ 'Last-Modified: {modified} GMT\r\n'
+ 'Pragma: no-cache\r\n'
+ 'Etag: "{size}-{mtime}"\r\n'
+ 'Content-Type: application/x-mpegurl\r\n\r\n'.format(modified=last_modified.strftime('%a, %d %b %Y %H:%M:%S'), size=os.path.getsize(__file__), mtime=str(os.stat(__file__).st_mtime).split('.')[0])
+)
+
+chunk_duration = 6.0272
+if 'duration' in query.keys():
+ chunk_duration = float(query.get('duration'))
+
+chunk_count = 4
+if 'count' in query.keys():
+ chunk_count = int(query.get('count'))
+
+chunk_url = 'test.ts'
+if 'url' in query.keys():
+ chunk_url = query.get('url')
+
+sys.stdout.write(
+ '#EXTM3U\n'
+ '#EXT-X-TARGETDURATION:7\n'
+ '#EXT-X-VERSION:4\n'
+ '#EXT-X-MEDIA-SEQUENCE:{}\n'.format(int(datetime.utcnow().timestamp() / chunk_duration) % 100)
+)
+
+time = datetime.utcnow()
+time = time.timestamp() - time.timestamp() % chunk_duration
+
+for _ in range(0, chunk_count):
+ time += chunk_duration
+ sys.stdout.write(
+ '#EXT-X-PROGRAM-DATE-TIME:{}T{}+00:00\n'
+ '#EXTINF:{},\n'
+ '{}\n'.format(datetime.fromtimestamp(time).strftime('%Y-%m-%d'), datetime.fromtimestamp(time).strftime('%H:%M:%S'), chunk_duration, chunk_url)
+ )
+++ /dev/null
-<?php
-
- $fileName = $_GET["name"];
- $type = $_GET["type"];
- if (array_key_exists("ranges", $_GET))
- $ranges = $_GET["ranges"];
-
- $_GET = array();
- $_GET['name'] = $fileName;
- $_GET['type'] = $type;
- if (isset($ranges))
- $_GET["ranges"] = $ranges;
- @include("./serve-video.php");
-
-?>
--- /dev/null
+#!/usr/bin/env python3
+
+import os
+import sys
+from urllib.parse import parse_qs, urlencode
+
+query = parse_qs(os.environ.get('QUERY_STRING', ''), keep_blank_values=True)
+filename = query.get('name', [''])[0]
+typ = query.get('type', [''])[0]
+ranges = query.get('ranges', [None])[0]
+
+query_obj = {'name': filename, 'type': typ}
+if ranges is not None:
+ query_obj.update({'ranges': ranges})
+
+os.environ['QUERY_STRING'] = urlencode(query_obj)
+
+from serve_video import serve_video
+++ /dev/null
-<?php
-
- // This script is based on the work done by gadgetguru
- // <david@vuistbijl.nl> at
- // https://github.com/gadgetguru/PHP-Streaming-Audio and released
- // under the Public Domain.
-
- // Set variables
- $settings = array(
- "chunkSize" => array_key_exists("chunkSize", $_GET) ? $_GET["chunkSize"] : 1024 * 256,
- "databaseFile" => "metadata.db",
- "httpStatus" => "500 Internal Server Error",
- "mediaDirectory" => array_key_exists("name", $_GET) ? dirname($_GET["name"]) : "",
- "mimeType" => array_key_exists("type", $_GET) ? $_GET["type"] : "",
- "radioGenre" => "Rock",
- "radioName" => "WebKit Test Radio",
- "radioUrl" => (array_key_exists("HTTPS", $_SERVER) ? "https" : "http") . "://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"],
- "setContentLength" => array_key_exists("content-length", $_GET) ? $_GET["content-length"] : "yes",
- "setIcyData" => array_key_exists("icy-data", $_GET) ? $_GET["icy-data"] : "no",
- "supportRanges" => array_key_exists("ranges", $_GET) ? $_GET["ranges"] : "yes",
- "stallOffset" => array_key_exists("stallOffset", $_GET) ? $_GET["stallOffset"] : 0,
- "stallDuration" => array_key_exists("stallDuration", $_GET) ? $_GET["stallDuration"] : 2,
- );
-
- // 500 on errors
- if (!array_key_exists("name", $_GET)) {
- trigger_error("You have not specified a 'name' parameter.", E_USER_WARNING);
- goto answering;
- }
-
- $fileName = $_GET["name"];
- if (!file_exists($fileName)) {
- trigger_error("The file '" . $fileName . "' doesn't exist.", E_USER_WARNING);
- goto answering;
- }
- $settings["databaseFile"] = $settings["mediaDirectory"] . "/" . $settings["databaseFile"];
-
- if ($settings["setIcyData"] != "yes" && $settings["mimeType"] == "") {
- trigger_error("You have not specified a 'type' parameter.", E_USER_WARNING);
- goto answering;
- }
-
- if ($settings["setIcyData"] == "yes") {
- if (!file_exists($settings["databaseFile"])) {
-
- // If the metadata database file doesn't exist it has to
- // be create previously.
- //
- // Check the instructions about how to create it from the
- // create-id3-db.php script file in this same directory.
-
- trigger_error("The metadata database doesn't exist. To create one, check the script 'create-id3-db.php'.", E_USER_WARNING);
- goto answering;
- }
-
- $playFiles = unserialize(file_get_contents($settings["databaseFile"]));
- foreach ($playFiles as $i=>$playFile) {
- if (basename($fileName) == $playFile["fileName"]) {
- $fileInDB = true;
- break;
- }
- }
-
- if (!isset($fileInDB)) {
- trigger_error("The requested file is not in the database.", E_USER_WARNING);
- goto answering;
- }
- }
-
- // There is everything needed to send the media file
- $fileSize = filesize($fileName);
- if ($settings["stallOffset"] && ($settings["stallOffset"] > $fileSize)) {
- trigger_error("The 'stallOffset' offset parameter is greater than file size (" . $fileSize . ").", E_USER_WARNING);
- goto answering;
- }
-
- $start = 0;
- $end = $fileSize - 1;
- if ($settings["supportRanges"] != "no" && array_key_exists("HTTP_RANGE", $_SERVER))
- $contentRange = $_SERVER["HTTP_RANGE"];
- if (isset($contentRange)) {
- $range = explode("-", substr($contentRange, strlen("bytes=")));
- $start = intval($range[0]);
- if (!empty($range[1]))
- $end = intval($range[1]);
- $settings["httpStatus"] = "206 Partial Content";
- } else
- $settings["httpStatus"] = "200 OK";
-
-
-answering:
-
- header("Status: " . $settings["httpStatus"]);
- header("HTTP/1.1 " . $settings["httpStatus"]);
- header("Connection: close");
-
- if ($settings["httpStatus"] == "500 Internal Server Error") {
- header("Content-Type: text/html");
- $errorMessage = sprintf("<html><body><h1>%s</h1><p/>",
- $settings["httpStatus"]);
- if (function_exists("error_get_last")) {
- $errorArray = error_get_last();
- if ($errorArray) {
- $errorMessage = sprintf("%sError type: %d<p/>Error message: %s<p/>".
- "Error file: %s<p/>Error line: %d<p/>",
- $errorMessage, $errorArray["type"], $errorArray["message"],
- $errorArray["file"], $errorArray["line"]);
- }
- }
- $errorMessage = $errorMessage . "</body><html>";
- print($errorMessage);
- flush();
- exit;
- }
-
- header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
- header("Cache-Control: no-cache");
- header("Etag: " . '"' . $fileSize . "-" . filemtime($fileName) . '"');
- if ($settings["setIcyData"] == "yes") {
- $bitRate = ceil($playFiles[$i]["bitRate"] / 1000);
- if ($settings["mimeType"] == "")
- $settings["mimeType"] = $playFiles[$i]["mimeType"];
- header("icy-notice1: <BR>This stream requires a shoutcast/icecast compatible player.<BR>");
- header("icy-notice2: WebKit Stream Test<BR>");
- header("icy-name: " . $settings["radioName"]);
- header("icy-genre: " . $settings["radioGenre"]);
- header("icy-url: " . $settings["radioUrl"]);
- header("icy-pub: 1");
- header("icy-br: " . $bitRate);
- }
- header("Content-Type: " . $settings["mimeType"]);
- if ($settings["supportRanges"] != "no")
- header("Accept-Ranges: bytes");
- if ($settings["setContentLength"] != "no")
- header("Content-Length: " . ($end - $start + 1));
- if (isset($contentRange))
- header("Content-Range: bytes " . $start . "-" . $end . "/" . $fileSize);
-
- $offset = $start;
-
- $fn = fopen($fileName, "rb");
- fseek($fn, $offset, 0);
-
- if ($settings["stallDuration"])
- set_time_limit(0);
-
- $stalledOnce = false;
- while (!feof($fn) && $offset <= $end && connection_status() == 0) {
- $readSize = min($settings["chunkSize"], ($end - $offset) + 1);
- $stallNow = false;
- if (!$stalledOnce && $settings["stallOffset"] && $settings["stallOffset"] >= $offset && $settings["stallOffset"] < $offset + $readSize) {
- $readSize = min($settings["chunkSize"], $settings["stallOffset"] - $offset);
- $stallNow = true;
- }
-
- $buffer = fread($fn, $readSize);
- $readLength = strlen($buffer);
-
- print($buffer);
- flush();
- $offset += $readLength;
-
- if ($stallNow) {
- sleep($settings["stallDuration"]);
- $stalledOnce = true;
- }
- }
- fclose($fn);
-
- exit;
-?>
radio_url = ''
if https is None:
- radio_url += 'https://'
-else:
radio_url += 'http://'
+else:
+ radio_url += 'https://'
radio_url += '{}{}'.format(os.environ.get('HTTP_HOST', ''), os.environ.get('REQUEST_URI', ''))
query = parse_qs(os.environ.get('QUERY_STRING', ''), keep_blank_values=True)
if name != '':
media_directory = os.path.abspath(os.path.dirname(name))
file_name = name
+file_size = os.path.getsize(file_name)
+
+file_in_db = False
+file_index_in_db = -1
+
+start = 0
+end = file_size - 1
# Set Variables
settings = {
'chunkSize': int(query.get('chunkSize', [1024 * 256])[0]),
- 'databaseFile': 'metadata.db',
+ 'databaseFile': 'metadata.json',
'httpStatus': '500 Internal Server Error',
'mediaDirectory': media_directory,
'mimeType': query.get('type', [''])[0],
sys.stdout.flush()
sys.exit(0)
- file_size = os.path.getsize(file_name)
last_modified = datetime.utcnow()
sys.stdout.write(
'Last-Modified: {} GMT\r\n'
)
if settings['setIcyData'] == 'yes':
- bit_rate = math.ceil(play_files[len(play_files) - 1]['mimeType'] / 1000)
+ bit_rate = math.ceil(play_files[file_index_in_db]['bitRate'] / 1000)
if settings['mimeType'] == '':
- settings['mimeType'] = play_files[len(play_files) - 1]['mimeType']
+ settings['mimeType'] = play_files[file_index_in_db]['mimeType']
sys.stdout.write(
'icy-notice1: <BR>This stream requires a shoutcast/icecast compatible player.<BR>\r\n'
if settings['supportRanges'] != 'no':
sys.stdout.write('Accept-Ranges: bytes\r\n')
- if settings['setContentLength'] != 'no':
- sys.stdout.write('Content-Length: {}\r\n'.format(end - start + 1))
if content_range is not None:
sys.stdout.write('Content-Range: bytes {}-{}/{}\r\n'.format(start, end, file_size))
sys.stdout.write('\r\n')
read_size = min(settings['chunkSize'], settings['stallOffset'] - offset)
stall_now = True
- buff = content[offset:read_size]
+ buff = content[offset:offset + read_size]
read_length = len(buff)
+ sys.stdout.flush()
sys.stdout.buffer.write(buff)
sys.stdout.flush()
offset += read_length
play_files = {}
with open(settings['databaseFile'], 'r') as file:
- play_files = json.loads(file.read())
- sys.stderr.write('\n{}\n'.format(play_files))
+ json_content = file.read()
+ play_files = json.loads(json_content)
- file_in_db = False
for play_file in play_files:
+ file_index_in_db += 1
if file_name.split('/')[-1] == play_file['fileName']:
file_in_db = True
break
answering()
# We have everything that's needed to send the media file
-file_size = os.path.getsize(file_name)
if settings['stallOffset'] > file_size:
sys.stderr.write('The \'stallOffset\' offset parameter is greater than file size ({}).\n'.format(file_size))
answering()
-start = 0
-end = file_size - 1
content_range = None
-if settings['supportRanges'] != 'no' and os.environ.get('HTTP_RANGE', None) is not None:
+if settings['supportRanges'] != 'no' and 'HTTP_RANGE' in os.environ.keys():
content_range = os.environ.get('HTTP_RANGE')
if content_range is not None:
rng = content_range[len('bytes='):].split('-')
+++ /dev/null
-<?php
-
- $ua = $_SERVER["HTTP_USER_AGENT"];
-
- header("Cache-Control: no-store");
- header("Connection: close");
- if (!isset($_SERVER['PHP_AUTH_USER'])) {
- header("WWW-authenticate: Basic realm=\"" . $_SERVER['REQUEST_URI'] . "\"");
- header('HTTP/1.0 401 Unauthorized');
- exit;
- }
-
- $fileName = $_GET["name"];
- $type = $_GET["type"];
-
- $_GET = array();
- $_GET['name'] = $fileName;
- $_GET['type'] = $type;
- @include("./serve-video.php");
-?>
--- /dev/null
+#!/usr/bin/env python3
+
+import base64
+import os
+import sys
+from urllib.parse import parse_qs, urlencode
+
+username = base64.b64decode(os.environ.get('HTTP_AUTHORIZATION', ' Og==').split(' ')[1]).decode().split(':')[0]
+query = parse_qs(os.environ.get('QUERY_STRING', ''), keep_blank_values=True)
+
+sys.stdout.write(
+ 'Cache-Control: no-store\r\n'
+ 'Connection: close\r\n'
+)
+
+if not username:
+ sys.stdout.write(
+ 'WWW-authenticate: Basic realm="{}"\r\n'
+ 'status: 401\r\n\r\n'.format(os.environ.get('REQUEST_URI', ''))
+ )
+ sys.exit(0)
+
+filename = query.get('name', ['404.txt'])[0]
+typ = query.get('type', [''])[0]
+
+os.environ['QUERY_STRING'] = urlencode({'name': filename, 'type': typ})
+
+from serve_video import serve_video
+++ /dev/null
-<?php
-
- $ua = $_SERVER["HTTP_USER_AGENT"];
-
- if (!isset($ua) || stripos($ua, "WebKit/") === false || stripos($ua, "(KHTML, like Gecko)") === false)
- die;
-
- $fileName = $_GET["name"];
- $type = $_GET["type"];
-
- $_GET = array();
- $_GET['name'] = $fileName;
- $_GET['type'] = $type;
- @include("./serve-video.php");
-
-?>
--- /dev/null
+#!/usr/bin/env python3
+
+import os
+import sys
+from urllib.parse import parse_qs, urlencode
+
+user_agent = os.environ.get('HTTP_USER_AGENT', None)
+query = parse_qs(os.environ.get('QUERY_STRING', ''), keep_blank_values=True)
+
+if user_agent is None or 'WebKit/' not in user_agent or '(KHTML, like Gecko)' not in user_agent:
+ sys.stdout.write('Content-Type: text/html\r\n\r\n')
+ sys.exit(0)
+
+filename = query.get('name', [''])[0]
+typ = query.get('type', [''])[0]
+
+os.environ['QUERY_STRING'] = urlencode({'name': filename, 'type': typ})
+
+from serve_video import serve_video
+++ /dev/null
-<?php
- if($_COOKIE["TEST"])
- {
- $extension = pathinfo($_COOKIE["TEST"], PATHINFO_EXTENSION);
- if ($extension == 'mp4') {
- header("Content-Type: video/mp4");
- $fileName = "test.mp4";
- } else if ($extension == 'ogv') {
- header("Content-Type: video/ogg");
- $fileName = "test.ogv";
- } else if ($extension == 'ts') {
- header("Content-Type: video/mpegts");
- $fileName = "hls/test.ts";
- } else
- die;
-
- header("Cache-Control: no-store");
- header("Connection: close");
- header("Content-Length: " . filesize($fileName));
-
- $fn = fopen($fileName, "r");
- fpassthru($fn);
- fclose($fn);
- exit;
- }
-?>
--- /dev/null
+#!/usr/bin/env python3
+
+import os
+import sys
+
+file = __file__.split(':/cygwin')[-1]
+http_root = os.path.dirname(os.path.dirname(os.path.abspath(os.path.dirname(file))))
+sys.path.insert(0, http_root)
+
+from resources.portabilityLayer import get_cookies
+
+cookies = get_cookies()
+test = cookies.get('TEST', None)
+
+filename = 'test.'
+if test is not None:
+ extension = test.split('.')[-1]
+
+ if extension == 'mp4':
+ sys.stdout.write('Content-Type: video/mp4\r\n')
+ filename += extension
+ elif extension == 'ogv':
+ sys.stdout.write('Content-Type: video/ogg\r\n')
+ filename += extension
+ elif extension == 'ts':
+ sys.stdout.write('Content-Type: video/mpegts\r\n')
+ filename = 'hls/test.ts'
+ else:
+ sys.stdout.write('Content-Type: text/html\r\n\r\n')
+ sys.exit(0)
+
+sys.stdout.write(
+ 'Cache-Control: no-store\r\n'
+ 'Connection: close\r\n'
+)
+
+if os.path.isfile(filename):
+ sys.stdout.write('Content-Length: {}\r\n\r\n'.format(os.path.getsize(filename)))
+
+ sys.stdout.flush()
+ with open(os.path.join(os.path.dirname(__file__), filename), 'rb') as file:
+ sys.stdout.buffer.write(file.read())
+
+else:
+ sys.stdout.write('\r\n')
+ sys.stderr.write('Could not find file {}\n'.format(filename))
+++ /dev/null
-<?php
-
- $requiredReferer = $_GET["referer"];
- $referHeader = $_SERVER["HTTP_REFERER"];
- if (!isset($referHeader) || stripos($referHeader, $requiredReferer) === false)
- die;
-
- $fileName = $_GET["name"];
- $type = $_GET["type"];
-
- $_GET = array();
- $_GET['name'] = $fileName;
- $_GET['type'] = $type;
- @include("./serve-video.php");
-
-?>
--- /dev/null
+#!/usr/bin/env python3
+
+import os
+import sys
+from urllib.parse import parse_qs, urlencode
+
+query = parse_qs(os.environ.get('QUERY_STRING', ''), keep_blank_values=True)
+required_referer = query.get('referer', [''])[0]
+refer_header = os.environ.get('HTTP_REFERER', None)
+
+if refer_header is None or required_referer not in refer_header:
+ sys.stdout.write('Content-Type: text/html\r\n\r\n')
+ sys.exit(0)
+
+filename = query.get('name', [''])[0]
+typ = query.get('type', [''])[0]
+os.environ['QUERY_STRING'] = urlencode({'name': filename, 'type': typ})
+
+from serve_video import serve_video
-http://127.0.0.1:8000/media/resources/video-auth.php?name=test.mp4&type=video/mp4 - didReceiveAuthenticationChallenge - Responding with username:password
+http://127.0.0.1:8000/media/resources/video-auth.py?name=test.mp4&type=video/mp4 - didReceiveAuthenticationChallenge - Responding with username:password
Tests that the media player sends authorization credentials when requesting a media file.
Testing same domain (127.0.0.1)
-http://127.0.0.1:8000/media/resources/video-auth.php?name=test.mp4&type=video/mp4 - didReceiveAuthenticationChallenge - Responding with username:password
-http://localhost:8000/media/resources/video-auth.php?name=test.mp4&type=video/mp4 - didReceiveAuthenticationChallenge - Responding with username:password
+http://127.0.0.1:8000/media/resources/video-auth.py?name=test.mp4&type=video/mp4 - didReceiveAuthenticationChallenge - Responding with username:password
+http://localhost:8000/media/resources/video-auth.py?name=test.mp4&type=video/mp4 - didReceiveAuthenticationChallenge - Responding with username:password
Tests that the media player sends authorization credentials when requesting a media file.
Testing same domain (127.0.0.1)
function testSameDomain()
{
consoleWrite('Testing same domain (127.0.0.1)');
- video.src = 'http://127.0.0.1:8000/media/resources/video-auth.php?name=' + media + '&type=' + type;
+ video.src = 'http://127.0.0.1:8000/media/resources/video-auth.py?name=' + media + '&type=' + type;
video.load();
}
function testCrossDomain()
{
consoleWrite('Testing cross domain (localhost)');
- video.src = 'http://localhost:8000/media/resources/video-auth.php?name=' + media + '&type=' + type;
+ video.src = 'http://localhost:8000/media/resources/video-auth.py?name=' + media + '&type=' + type;
video.load();
}
</script>
function testSameDomain()
{
consoleWrite('Testing same domain (127.0.0.1)');
- video.src = 'http://127.0.0.1:8000/media/resources/video-auth.php?name=' + media + '&type=' + type;
+ video.src = 'http://127.0.0.1:8000/media/resources/video-auth.py?name=' + media + '&type=' + type;
video.load();
}
</script>
frame.addEventListener('load', function () {
video = document.getElementById('video');
- video.src="http://127.0.0.1:8000/media/resources/video-cookie-check-cookie.php";
+ video.src="http://127.0.0.1:8000/media/resources/video-cookie-check-cookie.py";
video.play();
});
function prepareAudio() {
// Global variables used from video-test.js.
video = document.getElementById('audio');
- video.src="http://127.0.0.1:8000/media/resources/serve-video.php?content-length=no"
+ video.src="http://127.0.0.1:8000/media/resources/serve_video.py?content-length=no"
+ "&name=hls/english/description.aac&type=audio/aac&stallOffset=512&stallDuration=2";
mediaElement = video;
video.play();
var mediaFile = findMediaFile("video", "../../../../media/content/long-test");
var mimeType = mimeTypeForFile(mediaFile);
- video.src = "http://127.0.0.1:8000/media/resources/serve-video.php?name=" + mediaFile + "&type=" + mimeType + "&stallOffset=1000000&stallDuration=60&chunkSize=1024";
+ video.src = "http://127.0.0.1:8000/media/resources/serve_video.py?name=" + mediaFile + "&type=" + mimeType + "&stallOffset=1000000&stallDuration=60&chunkSize=1024";
}
</script>
var mediaFile = findMediaFile("video", "../../../../media/content/long-test");
var mimeType = mimeTypeForFile(mediaFile);
- video.src = "http://127.0.0.1:8000/media/resources/serve-video.php?name=" + mediaFile + "&type=" + mimeType + "&stallOffset=100000&stallDuration=60&chunkSize=1024";
+ video.src = "http://127.0.0.1:8000/media/resources/serve_video.py?name=" + mediaFile + "&type=" + mimeType + "&stallOffset=100000&stallDuration=60&chunkSize=1024";
</script>
frame.width = 0;
frame.height = 0;
frame.addEventListener('load', function () {
- video.src = 'http://127.0.0.1:8000/media/resources/load-video.php?name=' + movie + '&type=' + type;
+ video.src = 'http://127.0.0.1:8000/media/resources/load-video.py?name=' + movie + '&type=' + type;
waitForEventAndFail('error');
waitForEventAndEnd('canplay');
frame.height = 0;
frame.addEventListener('load', function () {
source = document.getElementById('source');
- source.src = 'http://127.0.0.1:8000/media/resources/video-referer-check-referer.php?referer=video-referer.html&name=' + movie + '&type=' + type;
+ source.src = 'http://127.0.0.1:8000/media/resources/video-referer-check-referer.py?referer=video-referer.html&name=' + movie + '&type=' + type;
source.type = type;
waitForEventAndFail('error');
frame.height = 0;
frame.addEventListener('load', function () {
source = document.getElementById('source');
- source.src = 'http://127.0.0.1:8000/media/resources/video-check-useragent.php?name=' + movie + '&type=' + type;
+ source.src = 'http://127.0.0.1:8000/media/resources/video-check-useragent.py?name=' + movie + '&type=' + type;
source.type = type;
waitForEventAndFail('error');
+++ /dev/null
-a:37:{i:0;a:11:{s:8:"fileName";s:23:"720x576i-anamorphic.mov";s:8:"fileSize";i:226625;s:8:"playTime";i:5;s:10:"audioStart";i:3463;s:8:"audioEnd";i:226625;s:11:"audioLength";i:223162;s:6:"artist";s:19:"720x576i-anamorphic";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:15:"video/quicktime";s:10:"fileFormat";s:9:"quicktime";}i:1;a:11:{s:8:"fileName";s:16:"CC+Subtitles.mov";s:8:"fileSize";i:545959;s:8:"playTime";i:30;s:10:"audioStart";i:32206;s:8:"audioEnd";i:545959;s:11:"audioLength";i:513753;s:6:"artist";s:12:"CC+Subtitles";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:15:"video/quicktime";s:10:"fileFormat";s:3:"mp4";}i:2;a:11:{s:8:"fileName";s:7:"abe.png";s:8:"fileSize";i:12242;s:8:"playTime";N;s:10:"audioStart";i:0;s:8:"audioEnd";i:12242;s:11:"audioLength";i:12242;s:6:"artist";s:3:"abe";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:9:"image/png";s:10:"fileFormat";s:3:"png";}i:3;a:11:{s:8:"fileName";s:22:"counting-captioned.mov";s:8:"fileSize";i:314055;s:8:"playTime";d:9.8283333333333331;s:10:"audioStart";i:5885;s:8:"audioEnd";i:314055;s:11:"audioLength";i:308170;s:6:"artist";s:18:"counting-captioned";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:15:"video/quicktime";s:10:"fileFormat";s:3:"mp4";}i:4;a:11:{s:8:"fileName";s:27:"counting-subtitled-kate.ogv";s:8:"fileSize";i:154649;s:8:"playTime";N;s:10:"audioStart";i:0;s:8:"audioEnd";i:154581;s:11:"audioLength";i:154581;s:6:"artist";s:23:"counting-subtitled-kate";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:15:"application/ogg";s:10:"fileFormat";s:3:"ogg";}i:5;a:11:{s:8:"fileName";s:26:"counting-subtitled-srt.mkv";s:8:"fileSize";i:318669;s:8:"playTime";d:10.800000000000001;s:10:"audioStart";i:0;s:8:"audioEnd";i:318669;s:11:"audioLength";i:318669;s:6:"artist";s:22:"counting-subtitled-srt";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:16:"video/x-matroska";s:10:"fileFormat";s:8:"matroska";}i:6;a:11:{s:8:"fileName";s:22:"counting-subtitled.m4v";s:8:"fileSize";i:317064;s:8:"playTime";d:10.800000000000001;s:10:"audioStart";i:311344;s:8:"audioEnd";i:317064;s:11:"audioLength";i:5720;s:6:"artist";s:18:"counting-subtitled";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:15:"video/quicktime";s:10:"fileFormat";s:3:"mp4";}i:7;a:11:{s:8:"fileName";s:12:"counting.jpg";s:8:"fileSize";i:6629;s:8:"playTime";N;s:10:"audioStart";N;s:8:"audioEnd";N;s:11:"audioLength";i:0;s:6:"artist";s:8:"counting";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:10:"image/jpeg";s:10:"fileFormat";N;}i:8;a:11:{s:8:"fileName";s:12:"counting.mp4";s:8:"fileSize";i:311336;s:8:"playTime";d:9.8283333333333331;s:10:"audioStart";i:3590;s:8:"audioEnd";i:311336;s:11:"audioLength";i:307746;s:6:"artist";s:8:"counting";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:15:"video/quicktime";s:10:"fileFormat";s:3:"mp4";}i:9;a:11:{s:8:"fileName";s:12:"counting.ogv";s:8:"fileSize";i:187773;s:8:"playTime";N;s:10:"audioStart";i:0;s:8:"audioEnd";i:187773;s:11:"audioLength";i:187773;s:6:"artist";s:8:"counting";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";N;s:10:"fileFormat";s:3:"ogg";}i:10;a:11:{s:8:"fileName";s:9:"empty.oga";s:8:"fileSize";i:0;s:8:"playTime";N;s:10:"audioStart";N;s:8:"audioEnd";N;s:11:"audioLength";i:0;s:6:"artist";s:5:"empty";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";N;s:10:"fileFormat";N;}i:11;a:11:{s:8:"fileName";s:9:"empty.wav";s:8:"fileSize";i:0;s:8:"playTime";N;s:10:"audioStart";N;s:8:"audioEnd";N;s:11:"audioLength";i:0;s:6:"artist";s:5:"empty";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";N;s:10:"fileFormat";N;}i:12;a:11:{s:8:"fileName";s:11:"garbage.mp4";s:8:"fileSize";i:22;s:8:"playTime";N;s:10:"audioStart";N;s:8:"audioEnd";N;s:11:"audioLength";i:0;s:6:"artist";s:7:"garbage";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";N;s:10:"fileFormat";N;}i:13;a:11:{s:8:"fileName";s:11:"garbage.ogv";s:8:"fileSize";i:22;s:8:"playTime";N;s:10:"audioStart";N;s:8:"audioEnd";N;s:11:"audioLength";i:0;s:6:"artist";s:7:"garbage";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";N;s:10:"fileFormat";N;}i:14;a:11:{s:8:"fileName";s:12:"greenbox.png";s:8:"fileSize";i:95;s:8:"playTime";N;s:10:"audioStart";i:0;s:8:"audioEnd";i:95;s:11:"audioLength";i:95;s:6:"artist";s:8:"greenbox";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:9:"image/png";s:10:"fileFormat";s:3:"png";}i:15;a:11:{s:8:"fileName";s:17:"scaled-matrix.mov";s:8:"fileSize";i:203856;s:8:"playTime";d:9.8283333333333331;s:10:"audioStart";i:1671;s:8:"audioEnd";i:203856;s:11:"audioLength";i:202185;s:6:"artist";s:13:"scaled-matrix";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:15:"video/quicktime";s:10:"fileFormat";s:9:"quicktime";}i:16;a:11:{s:8:"fileName";s:9:"short.wav";s:8:"fileSize";i:4920;s:8:"playTime";d:0.027641723356009069;s:10:"audioStart";i:44;s:8:"audioEnd";i:4920;s:11:"audioLength";i:4876;s:6:"artist";s:5:"short";s:5:"title";N;s:7:"bitRate";i:1411200;s:8:"mimeType";s:12:"audio/x-wave";s:10:"fileFormat";s:4:"riff";}i:17;a:11:{s:8:"fileName";s:16:"silence-loop.mov";s:8:"fileSize";i:36443;s:8:"playTime";d:1.3844777777777777;s:10:"audioStart";i:1622;s:8:"audioEnd";i:36443;s:11:"audioLength";i:34821;s:6:"artist";s:12:"silence-loop";s:5:"title";N;s:7:"bitRate";d:201207.99659719269;s:8:"mimeType";s:15:"video/quicktime";s:10:"fileFormat";s:9:"quicktime";}i:18;a:11:{s:8:"fileName";s:11:"silence.m4a";s:8:"fileSize";i:20447;s:8:"playTime";d:1.3699773242630386;s:10:"audioStart";i:4096;s:8:"audioEnd";i:20447;s:11:"audioLength";i:16351;s:6:"artist";s:7:"silence";s:5:"title";N;s:7:"bitRate";d:95481.87235169491;s:8:"mimeType";s:9:"audio/mp4";s:10:"fileFormat";s:3:"mp4";}i:19;a:11:{s:8:"fileName";s:11:"silence.mp3";s:8:"fileSize";i:17961;s:8:"playTime";d:1.4105833333333333;s:10:"audioStart";i:1034;s:8:"audioEnd";i:17961;s:11:"audioLength";i:16927;s:6:"artist";s:7:"silence";s:5:"title";N;s:7:"bitRate";i:96000;s:8:"mimeType";s:10:"audio/mpeg";s:10:"fileFormat";s:3:"mp3";}i:20;a:11:{s:8:"fileName";s:11:"silence.mpg";s:8:"fileSize";i:33227;s:8:"playTime";d:1.3844583333333333;s:10:"audioStart";i:0;s:8:"audioEnd";i:33227;s:11:"audioLength";i:33227;s:6:"artist";s:7:"silence";s:5:"title";N;s:7:"bitRate";i:192000;s:8:"mimeType";s:10:"audio/mpeg";s:10:"fileFormat";s:3:"mp2";}i:21;a:11:{s:8:"fileName";s:11:"silence.oga";s:8:"fileSize";i:12983;s:8:"playTime";d:1.3844897959183673;s:10:"audioStart";i:172;s:8:"audioEnd";i:10460;s:11:"audioLength";i:10288;s:6:"artist";s:7:"silence";s:5:"title";N;s:7:"bitRate";d:59447.16981132076;s:8:"mimeType";s:15:"application/ogg";s:10:"fileFormat";s:3:"ogg";}i:22;a:11:{s:8:"fileName";s:11:"silence.wav";s:8:"fileSize";i:120876;s:8:"playTime";d:1.3699773242630386;s:10:"audioStart";i:44;s:8:"audioEnd";i:120876;s:11:"audioLength";i:120832;s:6:"artist";s:7:"silence";s:5:"title";N;s:7:"bitRate";i:705600;s:8:"mimeType";s:12:"audio/x-wave";s:10:"fileFormat";s:4:"riff";}i:23;a:11:{s:8:"fileName";s:14:"test-25fps.mp4";s:8:"fileSize";i:167758;s:8:"playTime";i:10;s:10:"audioStart";i:7621;s:8:"audioEnd";i:167758;s:11:"audioLength";i:160137;s:6:"artist";s:10:"test-25fps";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:15:"video/quicktime";s:10:"fileFormat";s:3:"mp4";}i:24;a:11:{s:8:"fileName";s:14:"test-25fps.ogv";s:8:"fileSize";i:191863;s:8:"playTime";N;s:10:"audioStart";i:0;s:8:"audioEnd";i:191863;s:11:"audioLength";i:191863;s:6:"artist";s:10:"test-25fps";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";N;s:10:"fileFormat";s:3:"ogg";}i:25;a:11:{s:8:"fileName";s:17:"test-par-16-9.mp4";s:8:"fileSize";i:193661;s:8:"playTime";d:6.0430000000000001;s:10:"audioStart";i:48;s:8:"audioEnd";i:193661;s:11:"audioLength";i:193613;s:6:"artist";s:13:"test-par-16-9";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:15:"video/quicktime";s:10:"fileFormat";s:3:"mp4";}i:26;a:11:{s:8:"fileName";s:17:"test-par-16-9.ogv";s:8:"fileSize";i:99394;s:8:"playTime";N;s:10:"audioStart";i:11528;s:8:"audioEnd";i:98473;s:11:"audioLength";i:86945;s:6:"artist";s:13:"test-par-16-9";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:15:"application/ogg";s:10:"fileFormat";s:3:"ogg";}i:27;a:11:{s:8:"fileName";s:8:"test.mp4";s:8:"fileSize";i:192844;s:8:"playTime";d:6.0271999999999997;s:10:"audioStart";i:4345;s:8:"audioEnd";i:192844;s:11:"audioLength";i:188499;s:6:"artist";s:4:"test";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:15:"video/quicktime";s:10:"fileFormat";s:3:"mp4";}i:28;a:11:{s:8:"fileName";s:8:"test.oga";s:8:"fileSize";i:20787;s:8:"playTime";d:7.5683749999999996;s:10:"audioStart";i:170;s:8:"audioEnd";i:19650;s:11:"audioLength";i:19480;s:6:"artist";s:4:"test";s:5:"title";N;s:7:"bitRate";d:20590.945876756901;s:8:"mimeType";s:15:"application/ogg";s:10:"fileFormat";s:3:"ogg";}i:29;a:11:{s:8:"fileName";s:8:"test.ogv";s:8:"fileSize";i:157839;s:8:"playTime";N;s:10:"audioStart";i:0;s:8:"audioEnd";i:157839;s:11:"audioLength";i:157839;s:6:"artist";s:4:"test";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";N;s:10:"fileFormat";s:3:"ogg";}i:30;a:11:{s:8:"fileName";s:8:"test.wav";s:8:"fileSize";i:121138;s:8:"playTime";d:7.5683749999999996;s:10:"audioStart";i:44;s:8:"audioEnd";i:121138;s:11:"audioLength";i:121094;s:6:"artist";s:4:"test";s:5:"title";N;s:7:"bitRate";i:128000;s:8:"mimeType";s:12:"audio/x-wave";s:10:"fileFormat";s:4:"riff";}i:31;a:11:{s:8:"fileName";s:15:"test_yuv420.mp4";s:8:"fileSize";i:65537;s:8:"playTime";d:6.048;s:10:"audioStart";i:48;s:8:"audioEnd";i:65537;s:11:"audioLength";i:65489;s:6:"artist";s:11:"test_yuv420";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:15:"video/quicktime";s:10:"fileFormat";s:3:"mp4";}i:32;a:11:{s:8:"fileName";s:15:"test_yuv420.ogv";s:8:"fileSize";i:98780;s:8:"playTime";N;s:10:"audioStart";i:0;s:8:"audioEnd";i:98780;s:11:"audioLength";i:98780;s:6:"artist";s:11:"test_yuv420";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";N;s:10:"fileFormat";s:3:"ogg";}i:33;a:11:{s:8:"fileName";s:15:"test_yuv422.mp4";s:8:"fileSize";i:83353;s:8:"playTime";d:6.0510000000000002;s:10:"audioStart";i:48;s:8:"audioEnd";i:83353;s:11:"audioLength";i:83305;s:6:"artist";s:11:"test_yuv422";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";s:15:"video/quicktime";s:10:"fileFormat";s:3:"mp4";}i:34;a:11:{s:8:"fileName";s:15:"test_yuv422.ogv";s:8:"fileSize";i:164158;s:8:"playTime";N;s:10:"audioStart";i:0;s:8:"audioEnd";i:164158;s:11:"audioLength";i:164158;s:6:"artist";s:11:"test_yuv422";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";N;s:10:"fileFormat";s:3:"ogg";}i:35;a:11:{s:8:"fileName";s:30:"two-audio-and-video-tracks.mkv";s:8:"fileSize";i:968566;s:8:"playTime";d:8.918000000000001;s:10:"audioStart";i:0;s:8:"audioEnd";i:968566;s:11:"audioLength";i:968566;s:6:"artist";s:26:"two-audio-and-video-tracks";s:5:"title";N;s:7:"bitRate";i:80000;s:8:"mimeType";s:16:"video/x-matroska";s:10:"fileFormat";s:8:"matroska";}i:36;a:11:{s:8:"fileName";s:21:"unsupported_track.mov";s:8:"fileSize";i:180;s:8:"playTime";N;s:10:"audioStart";N;s:8:"audioEnd";N;s:11:"audioLength";i:0;s:6:"artist";s:17:"unsupported_track";s:5:"title";N;s:7:"bitRate";N;s:8:"mimeType";N;s:10:"fileFormat";N;}}
\ No newline at end of file
--- /dev/null
+[
+ {
+ "fileName": "720x576i-anamorphic.mov",
+ "fileSize": 226625,
+ "playTime": 5,
+ "audioStart": 3463,
+ "audioEnd": 226625,
+ "audioLength": 223162,
+ "artist": "720x576i-anamorphic",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "video/quicktime",
+ "fileFormat": "quicktime"
+ }, {
+ "fileName": "CC+Subtitles.mov",
+ "fileSize": 545959,
+ "playTime": 30,
+ "audioStart": 32206,
+ "audioEnd": 545959,
+ "audioLength": 513753,
+ "artist": "CC+Subtitles",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "video/quicktime",
+ "fileFormat": "mp4"
+ }, {
+ "fileName": "abe.png",
+ "fileSize": 12242,
+ "playTime": null,
+ "audioStart": 0,
+ "audioEnd": 12242,
+ "audioLength": 12242,
+ "artist": "abe",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "image/png",
+ "fileFormat": "png"
+ }, {
+ "fileName": "counting-captioned.mov",
+ "fileSize": 314055,
+ "playTime": 9.8283333333333,
+ "audioStart": 5885,
+ "audioEnd": 314055,
+ "audioLength": 308170,
+ "artist": "counting-captioned",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "video/quicktime",
+ "fileFormat": "mp4"
+ }, {
+ "fileName": "counting-subtitled-kate.ogv",
+ "fileSize": 154649,
+ "playTime": null,
+ "audioStart": 0,
+ "audioEnd": 154581,
+ "audioLength": 154581,
+ "artist": "counting-subtitled-kate",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "application/ogg",
+ "fileFormat": "ogg"
+ }, {
+ "fileName": "counting-subtitled-srt.mkv",
+ "fileSize": 318669,
+ "playTime": 10.8,
+ "audioStart": 0,
+ "audioEnd": 318669,
+ "audioLength": 318669,
+ "artist": "counting-subtitled-srt",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "video/x-matroska",
+ "fileFormat": "matroska"
+ }, {
+ "fileName": "counting-subtitled.m4v",
+ "fileSize": 317064,
+ "playTime": 10.8,
+ "audioStart": 311344,
+ "audioEnd": 317064,
+ "audioLength": 5720,
+ "artist": "counting-subtitled",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "video/quicktime",
+ "fileFormat": "mp4"
+ }, {
+ "fileName": "counting.jpg",
+ "fileSize": 6629,
+ "playTime": null,
+ "audioStart": null,
+ "audioEnd": null,
+ "audioLength": 0,
+ "artist": "counting",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "image/jpeg",
+ "fileFormat": ""
+ }, {
+ "fileName": "counting.mp4",
+ "fileSize": 311336,
+ "playTime": 9.8283333333333,
+ "audioStart": 3590,
+ "audioEnd": 311336,
+ "audioLength": 307746,
+ "artist": "counting",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "video/quicktime",
+ "fileFormat": "mp4"
+ }, {
+ "fileName": "counting.ogv",
+ "fileSize": 187773,
+ "playTime": null,
+ "audioStart": 0,
+ "audioEnd": 187773,
+ "audioLength": 187773,
+ "artist": "counting",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "",
+ "fileFormat": "ogg"
+ }, {
+ "fileName": "empty.oga",
+ "fileSize": 0,
+ "playTime": null,
+ "audioStart": null,
+ "audioEnd": null,
+ "audioLength": 0,
+ "artist": "empty",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "",
+ "fileFormat": ""
+ }, {
+ "fileName": "empty.wav",
+ "fileSize": 0,
+ "playTime": null,
+ "audioStart": null,
+ "audioEnd": null,
+ "audioLength": 0,
+ "artist": "empty",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "",
+ "fileFormat": ""
+ }, {
+ "fileName": "garbage.mp4",
+ "fileSize": 22,
+ "playTime": null,
+ "audioStart": null,
+ "audioEnd": null,
+ "audioLength": 0,
+ "artist": "garbage",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "",
+ "fileFormat": ""
+ }, {
+ "fileName": "garbage.ogv",
+ "fileSize": 22,
+ "playTime": null,
+ "audioStart": null,
+ "audioEnd": null,
+ "audioLength": 0,
+ "artist": "garbage",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "",
+ "fileFormat": ""
+ }, {
+ "fileName": "greenbox.png",
+ "fileSize": 95,
+ "playTime": null,
+ "audioStart": 0,
+ "audioEnd": 95,
+ "audioLength": 95,
+ "artist": "greenbox",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "image/png",
+ "fileFormat": "png"
+ }, {
+ "fileName": "scaled-matrix.mov",
+ "fileSize": 203856,
+ "playTime": 9.8283333333333,
+ "audioStart": 1671,
+ "audioEnd": 203856,
+ "audioLength": 202185,
+ "artist": "scaled-matrix",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "video/quicktime",
+ "fileFormat": "quicktime"
+ }, {
+ "fileName": "short.wav",
+ "fileSize": 4920,
+ "playTime": 0.027641723356009,
+ "audioStart": 44,
+ "audioEnd": 4920,
+ "audioLength": 4876,
+ "artist": "short",
+ "title": "",
+ "bitRate": 1411200,
+ "mimeType": "audio/x-wave",
+ "fileFormat": "riff"
+ }, {
+ "fileName": "silence-loop.mov",
+ "fileSize": 36443,
+ "playTime": 1.3844777777778,
+ "audioStart": 1622,
+ "audioEnd": 36443,
+ "audioLength": 34821,
+ "artist": "silence-loop",
+ "title": "",
+ "bitRate": 201207.99659719,
+ "mimeType": "video/quicktime",
+ "fileFormat": "quicktime"
+ }, {
+ "fileName": "silence.m4a",
+ "fileSize": 20447,
+ "playTime": 1.369977324263,
+ "audioStart": 4096,
+ "audioEnd": 20447,
+ "audioLength": 16351,
+ "artist": "silence",
+ "title": "",
+ "bitRate": 95481.872351695,
+ "mimeType": "audio/mp4",
+ "fileFormat": "mp4"
+ }, {
+ "fileName": "silence.mp3",
+ "fileSize": 17961,
+ "playTime": 1.4105833333333,
+ "audioStart": 1034,
+ "audioEnd": 17961,
+ "audioLength": 16927,
+ "artist": "silence",
+ "title": "",
+ "bitRate": 96000,
+ "mimeType": "audio/mpeg",
+ "fileFormat": "mp3"
+ }, {
+ "fileName": "silence.mpg",
+ "fileSize": 33227,
+ "playTime": 1.3844583333333,
+ "audioStart": 0,
+ "audioEnd": 33227,
+ "audioLength": 33227,
+ "artist": "silence",
+ "title": "",
+ "bitRate": 192000,
+ "mimeType": "audio/mpeg",
+ "fileFormat": "mp2"
+ }, {
+ "fileName": "silence.oga",
+ "fileSize": 12983,
+ "playTime": 1.3844897959184,
+ "audioStart": 172,
+ "audioEnd": 10460,
+ "audioLength": 10288,
+ "artist": "silence",
+ "title": "",
+ "bitRate": 59447.169811321,
+ "mimeType": "application/ogg",
+ "fileFormat": "ogg"
+ }, {
+ "fileName": "silence.wav",
+ "fileSize": 120876,
+ "playTime": 1.369977324263,
+ "audioStart": 44,
+ "audioEnd": 120876,
+ "audioLength": 120832,
+ "artist": "silence",
+ "title": "",
+ "bitRate": 705600,
+ "mimeType": "audio/x-wave",
+ "fileFormat": "riff"
+ }, {
+ "fileName": "test-25fps.mp4",
+ "fileSize": 167758,
+ "playTime": 10,
+ "audioStart": 7621,
+ "audioEnd": 167758,
+ "audioLength": 160137,
+ "artist": "test-25fps",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "video/quicktime",
+ "fileFormat": "mp4"
+ }, {
+ "fileName": "test-25fps.ogv",
+ "fileSize": 191863,
+ "playTime": null,
+ "audioStart": 0,
+ "audioEnd": 191863,
+ "audioLength": 191863,
+ "artist": "test-25fps",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "",
+ "fileFormat": "ogg"
+ }, {
+ "fileName": "test-par-16-9.mp4",
+ "fileSize": 193661,
+ "playTime": 6.043,
+ "audioStart": 48,
+ "audioEnd": 193661,
+ "audioLength": 193613,
+ "artist": "test-par-16-9",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "video/quicktime",
+ "fileFormat": "mp4"
+ }, {
+ "fileName": "test-par-16-9.ogv",
+ "fileSize": 99394,
+ "playTime": null,
+ "audioStart": 11528,
+ "audioEnd": 98473,
+ "audioLength": 86945,
+ "artist": "test-par-16-9",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "application/ogg",
+ "fileFormat": "ogg"
+ }, {
+ "fileName": "test.mp4",
+ "fileSize": 192844,
+ "playTime": 6.0272,
+ "audioStart": 4345,
+ "audioEnd": 192844,
+ "audioLength": 188499,
+ "artist": "test",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "video/quicktime",
+ "fileFormat": "mp4"
+ }, {
+ "fileName": "test.oga",
+ "fileSize": 20787,
+ "playTime": 7.568375,
+ "audioStart": 170,
+ "audioEnd": 19650,
+ "audioLength": 19480,
+ "artist": "test",
+ "title": "",
+ "bitRate": 20590.945876757,
+ "mimeType": "application/ogg",
+ "fileFormat": "ogg"
+ }, {
+ "fileName": "test.ogv",
+ "fileSize": 157839,
+ "playTime": null,
+ "audioStart": 0,
+ "audioEnd": 157839,
+ "audioLength": 157839,
+ "artist": "test",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "",
+ "fileFormat": "ogg"
+ }, {
+ "fileName": "test.wav",
+ "fileSize": 121138,
+ "playTime": 7.568375,
+ "audioStart": 44,
+ "audioEnd": 121138,
+ "audioLength": 121094,
+ "artist": "test",
+ "title": "",
+ "bitRate": 128000,
+ "mimeType": "audio/x-wave",
+ "fileFormat": "riff"
+ }, {
+ "fileName": "test_yuv420.mp4",
+ "fileSize": 65537,
+ "playTime": 6.048,
+ "audioStart": 48,
+ "audioEnd": 65537,
+ "audioLength": 65489,
+ "artist": "test_yuv420",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "video/quicktime",
+ "fileFormat": "mp4"
+ }, {
+ "fileName": "test_yuv420.ogv",
+ "fileSize": 98780,
+ "playTime": null,
+ "audioStart": 0,
+ "audioEnd": 98780,
+ "audioLength": 98780,
+ "artist": "test_yuv420",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "",
+ "fileFormat": "ogg"
+ }, {
+ "fileName": "test_yuv422.mp4",
+ "fileSize": 83353,
+ "playTime": 6.051,
+ "audioStart": 48,
+ "audioEnd": 83353,
+ "audioLength": 83305,
+ "artist": "test_yuv422",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "video/quicktime",
+ "fileFormat": "mp4"
+ }, {
+ "fileName": "test_yuv422.ogv",
+ "fileSize": 164158,
+ "playTime": null,
+ "audioStart": 0,
+ "audioEnd": 164158,
+ "audioLength": 164158,
+ "artist": "test_yuv422",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "",
+ "fileFormat": "ogg"
+ }, {
+ "fileName": "two-audio-and-video-tracks.mkv",
+ "fileSize": 968566,
+ "playTime": 8.918,
+ "audioStart": 0,
+ "audioEnd": 968566,
+ "audioLength": 968566,
+ "artist": "two-audio-and-video-tracks",
+ "title": "",
+ "bitRate": 80000,
+ "mimeType": "video/x-matroska",
+ "fileFormat": "matroska"
+ }, {
+ "fileName": "unsupported_track.mov",
+ "fileSize": 180,
+ "playTime": null,
+ "audioStart": null,
+ "audioEnd": null,
+ "audioLength": 0,
+ "artist": "unsupported_track",
+ "title": "",
+ "bitRate": null,
+ "mimeType": "",
+ "fileFormat": ""
+ }
+]
\ No newline at end of file