video_player.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. <?php
  2. function ppvm_player($ppub, $path, $video) {
  3. $metadata = $ppub->metadata;
  4. $short_title = $metadata["title"];
  5. if(strlen($short_title) > 30) {
  6. $short_title = substr($short_title, 0, 30);
  7. $short_title .= "…";
  8. }
  9. ?>
  10. <!DOCTYPE html>
  11. <html lang="<?php echo($metadata["language"] ?? SITE_LANGUAGE);?>">
  12. <head>
  13. <meta charset="utf-8">
  14. <title><?php echo(htmlentities($metadata["title"]));?> - <?php echo(SITE_NAME);?></title>
  15. <meta name="description" content="<?php echo(htmlentities($metadata["description"]));?>">
  16. <meta name="author" content="<?php echo(htmlentities($metadata["author"]));?>">
  17. <link rel="alternate" type="application/x-ppub" title="<?php echo(htmlentities($metadata["title"]));?> (as PPUB)" href="?download=true" />
  18. <script type="text/javascript" src="<?php echo(SITE_URL);?>/ppvm_player.js"></script>
  19. <style type="text/css">
  20. body {
  21. margin: 0px;
  22. background-color: #000;
  23. }
  24. video {
  25. display: block;
  26. height: auto;
  27. width: 100vw;
  28. height: 100vh;
  29. }
  30. .additional-contols {
  31. background: rgba(45, 45, 45, 0.8);
  32. padding: 6px;
  33. color: #ffffff;
  34. height: 24px;
  35. position: absolute;
  36. top: -36px;
  37. left: 0;
  38. right: 0;
  39. opacity: 0;
  40. transition: 0.2s all;
  41. display: flex;
  42. align-items: center;
  43. justify-content: space-between;
  44. gap: 8px;
  45. }
  46. body:hover .additional-contols.javascript, .paused.javascript, .additional-contols.noscript {
  47. top: 0px;
  48. opacity: 1;
  49. }
  50. body, input {
  51. font: 1rem -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto, Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji", "Segoe UI Symbol";
  52. }
  53. dialog {
  54. background: rgba(45, 45, 45, 1);
  55. color: #ffffff;
  56. border: 1px solid aliceblue;
  57. max-width: 75%;
  58. }
  59. dialog p{
  60. margin-top: 2px;
  61. }
  62. dialog::backdrop {
  63. background: rgba(45, 45, 45, 0.8);
  64. }
  65. dialog .contents {
  66. margin: -15px;
  67. margin-bottom: 0px;
  68. padding: 15px;
  69. padding-bottom: 0px;
  70. max-height: calc(75vh - 55px);
  71. overflow-y: auto;
  72. }
  73. dialog .controls {
  74. border-top: 1px solid dimgrey;
  75. padding-top: 10px;
  76. }
  77. a {
  78. color: skyblue;
  79. }
  80. a:visited {
  81. color: aquamarine;
  82. }
  83. .additional-contols a {
  84. color: #ffffff;
  85. }
  86. .additional-control {
  87. display: inline-block;
  88. }
  89. .filler {
  90. flex: 1;
  91. }
  92. .site a {
  93. text-decoration: none;
  94. color: #ffffff;
  95. margin: 8px;
  96. height: 18px;
  97. line-height: 20px;
  98. }
  99. .site a:hover {
  100. color: skyblue;
  101. }
  102. .additional-control button, .additional-control select {
  103. background: rgba(45, 45, 45, 0);
  104. border: 1px solid rgba(45, 45, 45, 0);
  105. color: #ffffff;
  106. cursor: pointer;
  107. text-decoration: underline;
  108. text-align: right;
  109. margin-top: 0px;
  110. margin-bottom: 2px;
  111. margin-left: 2px;
  112. margin-right: 2px;
  113. padding-left: 6px;
  114. padding-right: 6px;
  115. padding-bottom: 3px;
  116. padding-top: 1px;
  117. height: 23px;
  118. -webkit-appearance: none;
  119. }
  120. .additional-control button:hover, .additional-control select:hover {
  121. color: skyblue;
  122. }
  123. .additional-control button:focus, .additional-control select:focus {
  124. color: skyblue;
  125. }
  126. .additional-control select option {
  127. color: #000000;
  128. }
  129. summary {
  130. cursor: pointer;
  131. }
  132. #share-modal textarea, pre {
  133. width: 500px;
  134. background: rgb(30, 30, 30);
  135. color: #fff;
  136. border: none;
  137. padding: 8px;
  138. margin-top: 8px;
  139. margin-bottom: 18px;
  140. border-radius: 4px;
  141. overflow: scroll;
  142. white-space: pre;
  143. }
  144. #download-modal li {
  145. margin-bottom: 8px;
  146. }
  147. </style>
  148. </head>
  149. <body>
  150. <video controls id="player" poster="<?php echo($video->metadata["poster"]);?>" preload="metadata" src="<?php echo($video->metadata["master"]);?>">
  151. </video>
  152. <div id="no-script" class="additional-contols noscript">
  153. <div class="additional-control site">
  154. <a href="<?php echo(SITE_URL);?>/<?php echo($_GET["ppub"]);?>/<?php echo($_GET["asset"]);?>" target="_blank" title="<?php echo(htmlentities($metadata["title"]));?>"><strong><?php echo(htmlentities($short_title));?></strong></a>
  155. </div>
  156. <div class="additional-control noscript">
  157. For the best experience, please enable JavaScript.
  158. </div>
  159. </div>
  160. <div id="controls" class="additional-contols paused">
  161. <div class="additional-control site">
  162. <a href="<?php echo(SITE_URL);?>/<?php echo($_GET["ppub"]);?>/<?php echo($_GET["asset"]);?>" target="_blank" title="<?php echo(htmlentities($metadata["title"]));?>"><strong><?php echo(htmlentities($short_title));?></strong></a>
  163. <button onclick="showInfo()">Info</button>
  164. <button onclick="shareVideo()">Share</button>
  165. <button onclick="downloadVideo()">Download</button>
  166. </div>
  167. <div class="additional-control quality">
  168. <select name="quality" id="quality-selector" onchange="qualitySelected()">
  169. </select>
  170. </div>
  171. </div>
  172. <dialog id="download-modal">
  173. <form method="dialog">
  174. <div class="contents">
  175. <p><strong>Download video</strong><br/>
  176. <a href="<?php echo($video->metadata["master"]); ?>" download>Download the full quality version of this video</a> or select a different version to suit your needs below.
  177. </p>
  178. <details>
  179. <summary>Other formats and versions</summary>
  180. <ul>
  181. <?php
  182. foreach ($video->entries as $entry) {
  183. $entry_asset = $ppub->asset_index[$entry->filename];
  184. echo(" <li><a href=\"" . $entry->filename . "\" download>" . htmlentities($entry->label) . "</a><br/>\n");
  185. echo(" <small>" . round(($entry_asset->end_location - $entry_asset->start_location) / 1000000, 2) . "MB, " . $entry_asset->mimetype . "</small></li>\n");
  186. }
  187. ?>
  188. </ul>
  189. </details>
  190. <p>
  191. <?php if ($ppub->metadata["copyright"] != null) { ?>
  192. <br/>
  193. <?php echo($ppub->metadata["copyright"]);?>
  194. <?php } if ($ppub->metadata["licence"] != null) { ?>
  195. <br/>
  196. <a href="<?php echo($ppub->metadata["licence"]);?>">See Licence</a>
  197. <?php } ?></p>
  198. </div>
  199. <div class="controls">
  200. <button value="cancel">Close</button>
  201. </div>
  202. </form>
  203. </dialog>
  204. <dialog id="info-modal">
  205. <form method="dialog">
  206. <div class="contents">
  207. <p><strong><?php echo(htmlentities($ppub->metadata["title"]));?></strong>
  208. <?php if($ppub->metadata["author"] != null) {
  209. preg_match("/^([^<]*(?= *<|$))<*([^>]*)>*/", $ppub->metadata["author"], $author);
  210. ?>
  211. <br/>By <?php
  212. if(isset($author[2]) && $author[2] != '') {
  213. echo("<a href=\"mailto:".$author[2]."\">");
  214. echo(htmlentities(trim($author[1])));
  215. echo("</a>");
  216. } else {
  217. echo(htmlentities($ppub->metadata["author"]));
  218. }
  219. ?>.
  220. <?php } if ($ppub->metadata["tags"] != null and USE_PPIX) { ?>
  221. <br/>Tagged with:
  222. <?php
  223. foreach(explode(" ", $ppub->metadata["tags"]) as $tag) {
  224. ?>
  225. <a href="<?php echo(SITE_URL);?>/?tag=<?php echo(urlencode($tag));?>" target="_blank"><?php echo(htmlentities($tag));?></a>
  226. <?php
  227. }
  228. ?>
  229. <?php } if ($ppub->metadata["date"] != null) { ?>
  230. <br/>Last updated on <?php echo(htmlentities((new DateTime($ppub->metadata["date"]))->format(DATE_FORMAT)));?>.
  231. <br/><?php } if ($ppub->metadata["copyright"] != null) { ?>
  232. <?php echo($ppub->metadata["copyright"]);?>
  233. <?php } if ($ppub->metadata["licence"] != null) { ?>
  234. <a href="<?php echo($ppub->metadata["licence"]);?>" target="_blank">See Licence</a>
  235. <?php } ?></p>
  236. <br/><small>Powered by <a href="https://github.com/Tilo15/php-ppub" target="_blank">php-ppub</a></small></p>
  237. </div>
  238. <div class="controls">
  239. <button value="cancel">Close</button>
  240. </div>
  241. </form>
  242. </dialog>
  243. <dialog id="share-modal">
  244. <form method="dialog">
  245. <div class="contents">
  246. <p><strong>Share this video</strong><br/>
  247. With your friends, colleagues, distant family, or strangers on the internet.
  248. </p>
  249. <div>
  250. <label>Link:</label>
  251. <pre><?php echo(SITE_URL);?>/<?php echo($_GET["ppub"]);?>/<?php echo($_GET["asset"]);?></pre>
  252. </div>
  253. <div>
  254. <label>Embed:</label><br/>
  255. <textarea readonly rows="3"><?php generate_embed($path, $video);?></textarea>
  256. </div>
  257. </div>
  258. <div class="controls">
  259. <button value="cancel" autofocus>Close</button>
  260. </div>
  261. </form>
  262. </dialog>
  263. <dialog id="unplayable-modal">
  264. <form method="dialog">
  265. <div class="contents">
  266. <p><strong>Unable to playback content</strong><br/>
  267. Your browser does not appear to support any of the available codecs.
  268. </p>
  269. </div>
  270. <div class="controls">
  271. <button value="cancel">Close</button>
  272. </div>
  273. </form>
  274. </dialog>
  275. <script type="text/javascript">
  276. setup_playback({
  277. entries: [
  278. <?php
  279. foreach ($video->entries as $entry) {
  280. $entry_asset = $ppub->asset_index[$entry->filename];
  281. echo(" { type: \"" . $entry->type . "\", mimetype: \"" . $entry_asset->mimetype . "\", path: \"" . $entry->filename . "\", label: \"" . $entry->label . "\", metadata: { ");
  282. foreach ($entry->metadata as $key => $val) {
  283. echo($key . ": \"" . $val . "\", ");
  284. }
  285. echo("}},\n");
  286. }
  287. ?>
  288. ]
  289. });
  290. </script>
  291. </body>
  292. </html>
  293. <?php
  294. }
  295. function generate_embed($path, $video) {
  296. $percent = 56.25;
  297. if(isset($video->metadata["ratio"])) {
  298. $ratio = explode(":", $video->metadata["ratio"]);
  299. $percent = (min($ratio[0], $ratio[1]) / max($ratio[0], $ratio[1])) * 100;
  300. }
  301. ?>
  302. <div class="ppvm-player" style="position: relative; height:0; background: #2d2d2d; padding-bottom: <?php echo($percent);?>%">
  303. <iframe src="<?php echo(SITE_URL);?>/<?php echo($_GET["ppub"]);?>/<?php echo($_GET["asset"]);?>?embed=true/" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe>
  304. </div><?php
  305. }
  306. ?>