From a5fcb75d444bba7c729c33af1790f77fb2105b9d Mon Sep 17 00:00:00 2001 From: Ivan Borzenkov Date: Wed, 11 Aug 2021 11:58:06 +0300 Subject: [PATCH 01/12] update videojs --- package.json | 4 +- yarn.lock | 236 ++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 200 insertions(+), 40 deletions(-) diff --git a/package.json b/package.json index b59ccfe89e..0774631615 100644 --- a/package.json +++ b/package.json @@ -95,8 +95,8 @@ "trakt.tv-ondeck": "7.x.x", "underscore": "^1.13.6", "urijs": "^1.19.11", - "video.js": "4.11.4", - "videojs-youtube": "1.2.10", + "video.js": "^7.14.3", + "videojs-youtube": "^2.6.1", "webtorrent": "^1.9.7", "webtorrent-health": "1.x.x" }, diff --git a/yarn.lock b/yarn.lock index 9764d06ef5..389542c196 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,13 @@ resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.3.2.tgz#a6abc715fb6884851fca9dad37fc34739a04fd11" integrity sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw== +"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b" + integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA== + dependencies: + regenerator-runtime "^0.13.4" + "@fortawesome/fontawesome-free@^6.4": version "6.4.0" resolved "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.4.0.tgz" @@ -249,9 +256,9 @@ "@types/node" "*" "@types/semver@^7.3.8": - version "7.5.0" - resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz" - integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== + version "7.3.9" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.9.tgz#152c6c20a7688c30b967ec1841d31ace569863fc" + integrity sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ== "@types/vinyl@^2.0.9": version "2.0.11" @@ -268,6 +275,38 @@ dependencies: "@types/node" "*" +"@videojs/http-streaming@2.9.2": + version "2.9.2" + resolved "https://registry.yarnpkg.com/@videojs/http-streaming/-/http-streaming-2.9.2.tgz#47d33bb02bd9c1287200398b1e85d213dee814d0" + integrity sha512-2ZsxJn4/nZZ6k6jIhic2l9ynGmKwprtuI5b3+M6JgqOSLvQQ/ah+heVs/0g2Ze7qJxodqR+aSY948JwJIz1gCw== + dependencies: + "@babel/runtime" "^7.12.5" + "@videojs/vhs-utils" "^3.0.2" + aes-decrypter "3.1.2" + global "^4.4.0" + m3u8-parser "4.7.0" + mpd-parser "0.17.0" + mux.js "5.12.2" + video.js "^6 || ^7" + +"@videojs/vhs-utils@^3.0.0", "@videojs/vhs-utils@^3.0.2": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@videojs/vhs-utils/-/vhs-utils-3.0.3.tgz#708bc50742e9481712039695299b32da6582ef92" + integrity sha512-bU7daxDHhzcTDbmty1cXjzsTYvx2cBGbA8hG5H2Gvpuk4sdfuvkZtMCwtCqL59p6dsleMPspyaNS+7tWXx2Y0A== + dependencies: + "@babel/runtime" "^7.12.5" + global "^4.4.0" + url-toolkit "^2.2.1" + +"@videojs/xhr@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@videojs/xhr/-/xhr-2.5.1.tgz#26bc5a79dbb3b03bfb13742c6ce559f89e90719e" + integrity sha512-wV9nGESHseSK+S9ePEru2+OJZ1jq/ZbbzniGQ4weAmTIepuBMSYPx5zrxxQA0E786T5ykpO8ts+LayV+3/oI2w== + dependencies: + "@babel/runtime" "^7.5.5" + global "~4.4.0" + is-function "^1.0.1" + "@webtorrent/http-node@^1.3.0": version "1.3.0" resolved "https://registry.npmjs.org/@webtorrent/http-node/-/http-node-1.3.0.tgz" @@ -315,6 +354,16 @@ adm-zip@0.4.16: resolved "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz" integrity sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg== +aes-decrypter@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/aes-decrypter/-/aes-decrypter-3.1.2.tgz#3545546f8e9f6b878640339a242efe221ba7a7cb" + integrity sha512-42nRwfQuPRj9R1zqZBdoxnaAmnIFyDi0MNyTVhjdFOd8fifXKKRfwIHIZ6AMn1or4x5WONzjwRTbTWcsIQ0O4A== + dependencies: + "@babel/runtime" "^7.12.5" + "@videojs/vhs-utils" "^3.0.0" + global "^4.4.0" + pkcs7 "^1.0.4" + agent-base@^6.0.2: version "6.0.2" resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" @@ -2099,6 +2148,11 @@ dom-serializer@^2.0.0: domhandler "^5.0.2" entities "^4.2.0" +dom-walk@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" + integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== + domelementtype@1: version "1.3.1" resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz" @@ -3086,6 +3140,14 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" +global@^4.3.1, global@^4.4.0, global@~4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" + integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== + dependencies: + min-document "^2.19.0" + process "^0.11.10" + globby@^11.0.1: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -3694,6 +3756,11 @@ indexof@0.0.1: resolved "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz" integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= +individual@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/individual/-/individual-2.0.0.tgz#833b097dad23294e76117a98fb38e0d9ad61bb97" + integrity sha1-gzsJfa0jKU52EXqY+zjg2a1hu5c= + indx@^0.2.3: version "0.2.3" resolved "https://registry.npmjs.org/indx/-/indx-0.2.3.tgz" @@ -3949,6 +4016,11 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-function@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" + integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz" @@ -4401,6 +4473,11 @@ k-rpc@^5.1.0: k-rpc-socket "^1.7.2" randombytes "^2.0.5" +keycode@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.2.0.tgz#3d0af56dc7b8b8e5cba8d0a97f107204eec22b04" + integrity sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ= + keypress@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/keypress/-/keypress-0.2.1.tgz" @@ -4708,6 +4785,15 @@ lt_donthave@^1.0.1: debug "^4.2.0" unordered-array-remove "^1.0.2" +m3u8-parser@4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/m3u8-parser/-/m3u8-parser-4.7.0.tgz#e01e8ce136098ade1b14ee691ea20fc4dc60abf6" + integrity sha512-48l/OwRyjBm+QhNNigEEcRcgbRvnUjL7rxs597HmW9QSNbyNvt+RcZ9T/d9vxi9A9z7EZrB1POtZYhdRlwYQkQ== + dependencies: + "@babel/runtime" "^7.12.5" + "@videojs/vhs-utils" "^3.0.0" + global "^4.4.0" + magnet-uri@^6.2.0: version "6.2.0" resolved "https://registry.npmjs.org/magnet-uri/-/magnet-uri-6.2.0.tgz" @@ -4918,10 +5004,17 @@ mimic-response@^3.1.0: resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== -"minimatch@2 || 3", minimatch@^3.0.3, minimatch@^3.1.1: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= + dependencies: + dom-walk "^0.1.0" + +"minimatch@2 || 3", minimatch@^3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" @@ -4932,6 +5025,13 @@ minimatch@9.0.1: dependencies: brace-expansion "^2.0.1" +minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + minimatch@^5.0.1, minimatch@^5.1.0: version "5.1.6" resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz" @@ -5040,6 +5140,16 @@ mp4-stream@^3.0.0: queue-microtask "^1.2.2" readable-stream "^3.0.6" +mpd-parser@0.17.0: + version "0.17.0" + resolved "https://registry.yarnpkg.com/mpd-parser/-/mpd-parser-0.17.0.tgz#d7f3002edcb706f98993ef75846a713d056d3332" + integrity sha512-oKS5G0jCcHHJ3sHYlcLeM9Xcbuixl08eAx7QW0Th7ChlZiI0YvLtGaHE/L0aKUBJFNvtkeksIr8XgJgSBBsS4g== + dependencies: + "@babel/runtime" "^7.12.5" + "@videojs/vhs-utils" "^3.0.2" + global "^4.4.0" + xmldom "^0.5.0" + ms@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" @@ -5086,6 +5196,13 @@ mute-stdout@^1.0.0: resolved "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz" integrity sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg== +mux.js@5.12.2: + version "5.12.2" + resolved "https://registry.yarnpkg.com/mux.js/-/mux.js-5.12.2.tgz#cd823312f4bb69adb8b9c5f45635b4451066d6e6" + integrity sha512-9OY1lrFIo7FxMeIC6aLUftiNv97AztufDfi30N7qDll1Pcy7bCxlHztyHp1Ce0KQwy2XqchGeENPS4v1NJngHQ== + dependencies: + "@babel/runtime" "^7.11.2" + mv@2.x.x: version "2.1.1" resolved "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz" @@ -5726,6 +5843,13 @@ pinkie@^2.0.0: resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= +pkcs7@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/pkcs7/-/pkcs7-1.0.4.tgz#6090b9e71160dabf69209d719cbafa538b00a1cb" + integrity sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ== + dependencies: + "@babel/runtime" "^7.5.5" + plist@3.0.5: version "3.0.5" resolved "https://registry.npmjs.org/plist/-/plist-3.0.5.tgz" @@ -5819,6 +5943,11 @@ process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + progress@2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" @@ -6170,6 +6299,11 @@ redent@^1.0.0: indent-string "^2.1.0" strip-indent "^1.0.1" +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + regex-cache@^0.4.2: version "0.4.4" resolved "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz" @@ -6460,6 +6594,13 @@ rusha@^0.8.13: resolved "https://registry.npmjs.org/rusha/-/rusha-0.8.14.tgz" integrity sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA== +rust-result@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rust-result/-/rust-result-1.0.0.tgz#34c75b2e6dc39fe5875e5bdec85b5e0f91536f72" + integrity sha1-NMdbLm3Dn+WHXlveyFteD5FTb3I= + dependencies: + individual "^2.0.0" + safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" @@ -6475,6 +6616,13 @@ safe-identifier@^0.4.1: resolved "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz" integrity sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w== +safe-json-parse@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-4.0.0.tgz#7c0f578cfccd12d33a71c0e05413e2eca171eaac" + integrity sha1-fA9XjPzNEtM6ccDgVBPi7KFx6qw= + dependencies: + rust-result "^1.0.0" + safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz" @@ -7759,6 +7907,11 @@ url-to-options@^1.0.1: resolved "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz" integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= +url-toolkit@^2.2.1: + version "2.2.3" + resolved "https://registry.yarnpkg.com/url-toolkit/-/url-toolkit-2.2.3.tgz#78fa901215abbac34182066932220279b804522b" + integrity sha512-Da75SQoxsZ+2wXS56CZBrj2nukQ4nlGUZUP/dqUBG5E1su5GKThgT94Q00x81eVII7AyS1Pn+CtTTZ4Z0pLUtQ== + use@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/use/-/use-3.1.1.tgz" @@ -7850,37 +8003,43 @@ video-name-parser@^1.4.6: resolved "https://registry.npmjs.org/video-name-parser/-/video-name-parser-1.4.6.tgz" integrity sha512-ZdeYjh8X4ms1EzjY/UoiTZ6JWbi8SYyOPGY0jESSLq2BAmdc5sZHi+F8J19Qz0y7H1WSpaltojsCkO1p2dH4YA== -video.js@4.11.4: - version "4.11.4" - resolved "https://registry.npmjs.org/video.js/-/video.js-4.11.4.tgz" - integrity sha1-t4NIVKrLSGEzF74K/hKPDe2Z9cY= - dependencies: - videojs-swf "4.5.3" +"video.js@^5.6.0 || ^6.2.8 || ^7.0.2", "video.js@^6 || ^7", video.js@^7.14.3: + version "7.14.3" + resolved "https://registry.yarnpkg.com/video.js/-/video.js-7.14.3.tgz#0b612c09a0a81ef9bce65c710e73291cb06dc32c" + integrity sha512-6avCdSIfn5ss5NOgoQfY/xEfPNcz9DXSw+ZN80NwPguCdRd4VL4y40b/d7osYJwyCdF+YkvhqAW7dw4s0vBigg== + dependencies: + "@babel/runtime" "^7.12.5" + "@videojs/http-streaming" "2.9.2" + "@videojs/vhs-utils" "^3.0.2" + "@videojs/xhr" "2.5.1" + aes-decrypter "3.1.2" + global "^4.4.0" + keycode "^2.2.0" + m3u8-parser "4.7.0" + mpd-parser "0.17.0" + mux.js "5.12.2" + safe-json-parse "4.0.0" + videojs-font "3.2.0" + videojs-vtt.js "^0.15.3" + +videojs-font@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/videojs-font/-/videojs-font-3.2.0.tgz#212c9d3f4e4ec3fa7345167d64316add35e92232" + integrity sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA== -video.js@^4.12.5: - version "4.12.15" - resolved "https://registry.npmjs.org/video.js/-/video.js-4.12.15.tgz" - integrity sha1-KQ7+MPmdyaSs6Mdz3sJU3+5DTec= +videojs-vtt.js@^0.15.3: + version "0.15.3" + resolved "https://registry.yarnpkg.com/videojs-vtt.js/-/videojs-vtt.js-0.15.3.tgz#84260393b79487fcf195d9372f812d7fab83a993" + integrity sha512-5FvVsICuMRx6Hd7H/Y9s9GDeEtYcXQWzGMS+sl4UX3t/zoHp3y+isSfIPRochnTH7h+Bh1ILyC639xy9Z6kPag== dependencies: - videojs-swf "4.7.5" - vtt.js "git+https://github.com/gkatsev/vtt.js.git#vjs-v0.12.1" - -videojs-swf@4.5.3: - version "4.5.3" - resolved "https://registry.npmjs.org/videojs-swf/-/videojs-swf-4.5.3.tgz" - integrity sha1-l4seBrH1sjw81cpQRT//sA0tioI= - -videojs-swf@4.7.5: - version "4.7.5" - resolved "https://registry.npmjs.org/videojs-swf/-/videojs-swf-4.7.5.tgz" - integrity sha1-UPn2R9xZB+bRFUxVn3KGzNi0tsg= + global "^4.3.1" -videojs-youtube@1.2.10: - version "1.2.10" - resolved "https://registry.npmjs.org/videojs-youtube/-/videojs-youtube-1.2.10.tgz" - integrity sha1-Bv69RquPuyp40AwnC4vZThMFS/U= +videojs-youtube@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/videojs-youtube/-/videojs-youtube-2.6.1.tgz#3f7cce15229509ea6d54582e28793df530254860" + integrity sha512-qvwrkgXixbX8xzdkBa7o5r9KUITRISAy4bbyrpBgub3m0mhwz6WLXDIwJZ6/w4Z/JijWjLQqlg8W1jYhCEgHZw== dependencies: - video.js "^4.12.5" + video.js "^5.6.0 || ^6.2.8 || ^7.0.2" videostream@^3.2.2: version "3.2.2" @@ -7992,10 +8151,6 @@ vinyl@^3.0.0: replace-ext "^2.0.0" teex "^1.0.1" -"vtt.js@git+https://github.com/gkatsev/vtt.js.git#vjs-v0.12.1": - version "0.12.1" - resolved "git+ssh://git@github.com/gkatsev/vtt.js.git#8ea664e257ec7b5c092f58ac989e3134ff536a7a" - w-json@^1.3.10: version "1.3.10" resolved "https://registry.npmjs.org/w-json/-/w-json-1.3.10.tgz" @@ -8229,6 +8384,11 @@ xmldom@0.1.x: resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz" integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ== +xmldom@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.5.0.tgz#193cb96b84aa3486127ea6272c4596354cb4962e" + integrity sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA== + xmlrpc@^1.3.2: version "1.3.2" resolved "https://registry.npmjs.org/xmlrpc/-/xmlrpc-1.3.2.tgz" From c47cc415fa28ca1d9846071e20df20192ce39604 Mon Sep 17 00:00:00 2001 From: Ivan Borzenkov Date: Wed, 11 Aug 2021 17:28:28 +0300 Subject: [PATCH 02/12] first fixes --- src/app/global.js | 3 +++ src/app/lib/views/player/player.js | 40 ++++++++++++++++-------------- src/app/styl/views/player.styl | 1 + 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/app/global.js b/src/app/global.js index 2ea77f5782..b61237e9bd 100644 --- a/src/app/global.js +++ b/src/app/global.js @@ -36,6 +36,7 @@ var _ = require('underscore'), // Torrent engines WebTorrent = require('webtorrent'), torrentCollection = require('torrentcollection6'), + videojs = require('video.js'), // NodeJS child = require('child_process'), // package.json @@ -45,5 +46,7 @@ var _ = require('underscore'), // setting default filters status curSetDefaultFilters = false; +require('videojs-youtube'); + dayjs.extend(require('dayjs/plugin/relativeTime')); dayjs.extend(require('dayjs/plugin/localizedFormat')); diff --git a/src/app/lib/views/player/player.js b/src/app/lib/views/player/player.js index 29a1055aec..a6a84c71e6 100644 --- a/src/app/lib/views/player/player.js +++ b/src/app/lib/views/player/player.js @@ -211,6 +211,8 @@ if (type === 'episode') { type = 'show'; } + console.log('===='); + console.log(this.video); if (this.video.currentTime() / this.video.duration() >= 0.8 && type !== undefined && this.model.get('metadataCheckRequired') !== false) { App.vent.trigger(type + ':watched', this.model.attributes, 'database'); } @@ -469,12 +471,13 @@ // start videojs engine if (this.model.get('type') === 'video/youtube') { - this.video = videojs('video_player', { + this.video = videojs($('#video_player').get(0), { techOrder: ['youtube'], forceSSL: true, - ytcontrols: false, - quality: '720p' - }).ready(function () { + ytcontrols: true, + quality: '720p', + }); + this.video.ready(function () { that.player && that.player.cache_ && that.player.cache_.volume ? that.player.volume(Settings.playerVolume) : null; this.addClass('vjs-has-started'); }); @@ -509,12 +512,13 @@ customSubtitles: {}, progressTips: {} } - }).ready(function () { + }); + this.video.ready(function () { that.playerWasReady = Date.now(); }); $('head > title').text(this.model.get('title') + ' - Popcorn-Time' ); } - this.player = this.video.player(); + this.player = this.video;//.player(); App.PlayerView = this; /* The following is a hack to make VideoJS listen to @@ -522,18 +526,18 @@ * video element. Stops video pausing/playing when * dragged. TODO: #fixit! */ - this.player.tech.off('mousedown'); - this.player.tech.on('mouseup', function (event) { - if (event.target.origEvent) { - if (!event.target.origEvent.originalEvent.defaultPrevented) { - that.player.tech.onClick(event); - } - // clean up after ourselves - delete event.target.origEvent; - } else { - that.player.tech.onClick(event); - } - }); + // this.player.tech.off('mousedown'); + // this.player.tech.on('mouseup', function (event) { + // if (event.target.origEvent) { + // if (!event.target.origEvent.originalEvent.defaultPrevented) { + // that.player.tech.onClick(event); + // } + // // clean up after ourselves + // delete event.target.origEvent; + // } else { + // that.player.tech.onClick(event); + // } + // }); // Force custom controls this.player.usingNativeControls(false); diff --git a/src/app/styl/views/player.styl b/src/app/styl/views/player.styl index 5e1b05b6d8..a8cc14e9b2 100644 --- a/src/app/styl/views/player.styl +++ b/src/app/styl/views/player.styl @@ -15,6 +15,7 @@ position: absolute overflow: hidden background-color: #000 + font-size: 10px; video { width: 100% height: 100% From 98574c546e7de7964bc93533fdfdaef367e8ca1f Mon Sep 17 00:00:00 2001 From: Ivan Borzenkov Date: Sat, 14 Aug 2021 16:32:09 +0300 Subject: [PATCH 03/12] it's run --- src/app/lib/views/player/player.js | 15 +- src/app/vendor/videojshooks.js | 1036 ++++++++++++++-------------- src/app/vendor/videojsplugins.js | 318 ++++----- 3 files changed, 684 insertions(+), 685 deletions(-) diff --git a/src/app/lib/views/player/player.js b/src/app/lib/views/player/player.js index a6a84c71e6..c242e6d476 100644 --- a/src/app/lib/views/player/player.js +++ b/src/app/lib/views/player/player.js @@ -211,8 +211,6 @@ if (type === 'episode') { type = 'show'; } - console.log('===='); - console.log(this.video); if (this.video.currentTime() / this.video.duration() >= 0.8 && type !== undefined && this.model.get('metadataCheckRequired') !== false) { App.vent.trigger(type + ':watched', this.model.attributes, 'database'); } @@ -474,7 +472,7 @@ this.video = videojs($('#video_player').get(0), { techOrder: ['youtube'], forceSSL: true, - ytcontrols: true, + ytcontrols: false, quality: '720p', }); this.video.ready(function () { @@ -503,13 +501,14 @@ }); } else { - this.video = videojs('video_player', { + this.video = videojs($('#video_player').get(0), { nativeControlsForTouch: false, trackTimeOffset: 0, + //inactivityTimeout: 2000, plugins: { - biggerSubtitle: {}, - smallerSubtitle: {}, - customSubtitles: {}, + //biggerSubtitle: {}, + //smallerSubtitle: {}, + //customSubtitles: {}, progressTips: {} } }); @@ -518,7 +517,7 @@ }); $('head > title').text(this.model.get('title') + ' - Popcorn-Time' ); } - this.player = this.video;//.player(); + this.player = this.video; App.PlayerView = this; /* The following is a hack to make VideoJS listen to diff --git a/src/app/vendor/videojshooks.js b/src/app/vendor/videojshooks.js index 1be009ca7a..70a5d77356 100644 --- a/src/app/vendor/videojshooks.js +++ b/src/app/vendor/videojshooks.js @@ -1,518 +1,518 @@ -vjs.options['children'] = { - 'mediaLoader': {}, - 'posterImage': {}, - 'textTrackDisplay': {}, - 'loadingSpinner': {}, - //'bigPlayButton': {}, - 'controlBar': {}, - 'errorDisplay': {} -}; - -vjs.Player.prototype.debugMouse_ = false; -vjs.Player.prototype.reportUserActivity = function (event) { - /** DEBUG MOUSE CTRL+D **/ - if (this.debugMouse_) { - console.log('Event fired at: ' + vjs.formatTime(this.player_.currentTime(), this.player_.duration())); - console.log(event); - } - if (event !== undefined && event.type === 'mousemove') { - if (event.webkitMovementX === 0 && event.webkitMovementY === 0) { - return; - } - } - this.userActivity_ = true; -}; - -vjs.Player.prototype.listenForUserActivity = function () { - var onActivity, onMouseDown, mouseInProgress, onMouseUp, - activityCheck, inactivityTimeout; - - onActivity = vjs.bind(this, this.reportUserActivity); - - onMouseDown = function (e) { - onActivity(e); - clearInterval(mouseInProgress); - mouseInProgress = setInterval(onActivity, 250); - }; - - onMouseUp = function (e) { - onActivity(e); - clearInterval(mouseInProgress); - }; - - this.on('mousedown', onMouseDown); - this.on('mousemove', onActivity); - this.on('mouseup', onMouseUp); - this.on('keydown', onActivity); - this.on('keyup', onActivity); - - activityCheck = setInterval(vjs.bind(this, function () { - if (this.userActivity_) { - this.userActivity_ = false; - this.userActive(true); - clearTimeout(inactivityTimeout); - inactivityTimeout = setTimeout(vjs.bind(this, function () { - if (!this.userActivity_) { - this.userActive(false); - } - }), 2000); - } - }), 250); - - this.on('dispose', function () { - clearInterval(activityCheck); - clearTimeout(inactivityTimeout); - }); -}; - -vjs.Player.prototype.onFullscreenChange = function (e) { - e.stopPropagation(); - if (this.isFullscreen()) { - this.addClass('vjs-fullscreen'); - $('.vjs-text-track').css('font-size', '140%'); - $('.state-info-player').css('font-size', '65px'); - } else { - this.removeClass('vjs-fullscreen'); - $('.vjs-text-track').css('font-size', ''); - $('.state-info-player').css('font-size', '50px'); - } -}; - -// This is a custom way of loading subtitles, since we can't use src (CORS blocks it and we can't disable it) -// We fetch them when requested, process them and finally throw a parseCues their way -vjs.TextTrack.prototype.load = function () { - // Only load if not loaded yet. - if (this.readyState_ === 0) { - var this_ = this; - this.readyState_ = 1; - - var subsParams = function () { - var subtitles = $('.vjs-subtitles'), - vjsTextTrack = $('.vjs-text-track'), - vjsTextTrackDsp = $('.vjs-text-track-display'); - - vjsTextTrack.css('display', 'inline-block').drags(); - vjsTextTrackDsp.css('font-size', Settings.subtitle_size); - if (win.isFullscreen) { - vjsTextTrack.css('font-size', '140%'); - } - subtitles.css('color', Settings.subtitle_color); - subtitles.css('font-family', Settings.subtitle_font); - if (Settings.subtitle_decoration === 'None') { - vjsTextTrack.css('text-shadow', 'none'); - } else if (Settings.subtitle_decoration === 'Opaque Background') { - vjsTextTrack.css('background', '#000'); - } else if (Settings.subtitle_decoration === 'See-through Background') { - vjsTextTrack.css('background', 'rgba(0,0,0,.5)'); - } - if (Settings.subtitles_bold) { - vjsTextTrack.css('font-weight', 'bold'); - } - vjsTextTrack.css('z-index', 'auto').css('position', 'relative').css('top', AdvSettings.get('playerSubPosition')); - }; - - // Fetches a raw subtitle, locally or remotely - var get_subtitle = function (subtitle_url, callback) { - - // Fetches Locally - if (fs.existsSync(path.join(subtitle_url))) { - fs.readFile(subtitle_url, function (error, data) { - if (!error) { - callback(data); - } else { - console.warn('Failed to read subtitle!', error); - } - }); - // Fetches Remotely - } else { - request({ - url: subtitle_url, - encoding: null - }, function (error, response, data) { - if (!error && response.statusCode === 200) { - callback(data); - } else { - console.warn('Failed to download subtitle!', error, response); - } - }); - } - }; - - //transcode .ass, .ssa, .txt to SRT - var convert2srt = function (file, ext, callback) { - var readline = require('readline'), - counter = null, - lastBeginTime, - - //input - orig = /([^\\]+)$/.exec(file)[1], - origPath = file.substr(0, file.indexOf(orig)), - - //output - srt = orig.replace(ext, '.srt'), - srtPath = Settings.tmpLocation, - - //elements - dialog, begin_time, end_time; - - fs.writeFileSync(path.join(srtPath, srt), ''); //create or delete content; - console.log('SUB format can be converted:', orig); - - var rl = readline.createInterface({ - input: fs.createReadStream(path.join(origPath, orig)), - output: process.stdout, - terminal: false - }); - rl.on('line', function (line) { - - //detect encoding - var charset = charsetDetect.detect(line); - var encoding = charset.encoding; - var line_, parsedBeginTime, parsedEndTime, parsedDialog; - - //parse SSA - if (ext === '.ssa' || ext === '.ass') { - encoding = 'utf-8'; - if (line.indexOf('Format:') !== -1) { - var ssaFormat = line.split(','); - - for (var i = 0; i < ssaFormat.length; i++) { - switch (ssaFormat[i]) { - case 'Text': - case ' Text': - dialog = i; - break; - case 'Start': - case ' Start': - begin_time = i; - break; - case 'End': - case ' End': - end_time = i; - break; - default: - } - } - - if (dialog && begin_time && end_time) { - console.log('SUB formatted in \'ssa\''); - } - return; //we have the elms spots, move on to the next line - } - - if (line.indexOf('Dialogue:') === -1) { //not a dialog line - return; - } - - line_ = line.split(','); - - parsedBeginTime = line_[begin_time]; - parsedEndTime = line_[end_time]; - parsedDialog = line_[dialog]; - parsedDialog = parsedDialog.replace('{\\i1}', '').replace('{\\i0}', ''); //italics - parsedDialog = parsedDialog.replace('{\\b1}', '').replace('{\\b0}', ''); //bold - parsedDialog = parsedDialog.replace('\\N', '\n'); //return to line - parsedDialog = parsedDialog.replace(/{.*?}/g, ''); //remove leftovers brackets - } - - //parse TXT - if (ext === '.txt') { - line_ = line.split('}'); - - var formatSeconds = function (seconds) { - var date = new Date(1970, 0, 1); - date.setSeconds(seconds); - return date.toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, '$1'); - }; - - parsedBeginTime = formatSeconds(line_[0].replace('{', '') / 25); - parsedEndTime = formatSeconds(line_[1].replace('{', '') / 25); - parsedDialog = line_[2].replace('|', '\n'); - } - - //SRT needs a number for each subtitle - counter += 1; - - //keep only the last lang - if (parsedBeginTime < lastBeginTime) { - counter = 1; - fs.writeFileSync(path.join(srtPath, srt), ''); - console.log('SUB contains multiple tracks, keeping only the last'); - } - - //SRT formatting - var parsedLine = - counter + '\n' + - parsedBeginTime + ' --> ' + parsedEndTime + '\n' + - parsedDialog; - - fs.appendFileSync(path.join(srtPath, srt), '\n\n' + parsedLine, encoding); - lastBeginTime = parsedBeginTime; - }); - - setTimeout(function () { - fs.readFile(path.join(srtPath, srt), function (err, dataBuff) { - if (!err) { - console.log('SUB transcoded to SRT:', srt); - callback(dataBuff); - } else { - console.warn('SUB transcoding failed', err); - } - }); - }, 2000); - }; - - // Decompress zip - var decompress = function (dataBuff, callback) { - try { - var zip = new AdmZip(dataBuff); - var zipEntries = zip.getEntries(); - // TODO: Shouldn't we look for only 1 file ??? - zipEntries.forEach(function (zipEntry, key) { - if (zipEntry.entryName.indexOf('.srt') !== -1) { - var decompressedData = zip.readFile(zipEntry); - callback(decompressedData); - } - }); - } catch (error) { - console.warn('Failed to decompress subtitle!', error); - } - }; - - // Handles charset encoding - var decode = function (dataBuff, language, callback) { - if(language && language.indexOf('|')!==-1){ - language = language.substr(0,language.indexOf('|')); - } - - var targetEncodingCharset = 'utf8'; - - var parse = function (strings) { - strings = strings - .replace(/\{.*\}/g, '') // {/pos(x,y)} - .replace(/(- |==|sync).*[\s\S].*[\s\S].*[\s\S].*[\s\S].*\.(com|org|net|edu)/ig, '') // various teams - .replace(/[^0-9][\s\S][^0-9\W].*[\s\S].*[\s\S].*opensubtitles.*/ig, ''); // opensubs "contact us" ads - - // clean two following subtitle indexes for one timing, example: - // 3 - // 2 - // 00:00:59,142 --> 00:01:01,144 - // N'Y COMPTE PAS - // - strings = strings.replace(/^(\d{1,5}\r*\n)(\d{1,5}\r*\n)((\d\d:){2}\d\d,\d{3}\s-->\s(\d\d:){2}\d\d,\d{3}\r*\n)/gm, '$1$3'); - - strings = Common.sanitize(strings); // xss-style attacks - strings = strings.replace(/--\>\;/g, '-->'); // restore srt format - callback(strings); - }; - - var charset = charsetDetect.detect(dataBuff); - var detectedEncoding = charset.encoding; - console.log('SUB charset detected: ' + detectedEncoding); - // Do we need decoding? - if (detectedEncoding && detectedEncoding.toLowerCase().replace('-', '') === targetEncodingCharset) { - parse(dataBuff.toString('utf-8')); - // We do - } else { - if (!language && Settings.subtitle_language !== 'none') { - language = Settings.subtitle_language; - console.log('SUB charset: using subtitles_language setting (' + language + ') as default'); - } - var langInfo = App.Localization.langcodes[language] || {}; - console.log('SUB charset expected:', langInfo.encoding); - if (langInfo.encoding !== undefined && langInfo.encoding.indexOf(detectedEncoding) < 0) { - // The detected encoding was unexepected to the language, so we'll use the most common - // encoding for that language instead. - detectedEncoding = langInfo.encoding[0]; - dataBuff = iconv.encode(iconv.decode(dataBuff, detectedEncoding), targetEncodingCharset); - } else { - // fallback to utf8 - console.log('SUB charset: fallback to utf-8'); - dataBuff = iconv.decode(dataBuff, detectedEncoding); - detectedEncoding = 'UTF-8'; - } - console.log('SUB charset used:', detectedEncoding); - parse(dataBuff.toString('utf-8')); - } - }; - - var vjsBind = function (data) { - try { - this_.parseCues(data); - } catch (e) { - console.error('Error reading subtitles timing, file seems corrupted', e); - subsParams(); - App.vent.trigger('notification:show', new App.Model.Notification({ - title: i18n.__('Error reading subtitle timings, file seems corrupted'), - body: i18n.__('Try another subtitle or drop one in the player'), - showRestart: false, - type: 'error', - autoclose: true - })); - } - }; - - this.on('loaded', function () { - console.log('Subtitles loaded!'); - subsParams(); - }); - - // Get it, Unzip it, Decode it, Send it - get_subtitle(this.src_, function (dataBuf) { - if (path.extname(this_.src_) === '.zip') { - decompress(dataBuf, function (dataBuf) { - decode(dataBuf, this_.language(), vjsBind); - }); - } else if (path.extname(this_.src_) === '.ass' || path.extname(this_.src_) === '.ssa' || path.extname(this_.src_) === '.txt') { - convert2srt(this_.src_, path.extname(this_.src_), function (dataBuf) { - decode(dataBuf, this_.language(), vjsBind); - }); - } else { - decode(dataBuf, this_.language(), vjsBind); - } - }); - - } - -}; - -/** - * The specific menu item type for selecting a language within a text track kind - * - * @constructor - */ -vjs.TextTrackMenuItem = vjs.MenuItem.extend({ - /** @constructor */ - init: function (player, options) { - var track = this.track = options['track']; - - // Modify options for parent MenuItem class's init. - options['label'] = track.label(); - options['selected'] = track.dflt(); - vjs.MenuItem.call(this, player, options); - - this.player_.on(track.kind() + 'trackchange', vjs.bind(this, this.update)); - - // Popcorn Time Fix - // Allowing us to send a default language - if (track.dflt()) { - this.player_.showTextTrack(this.track.id_, this.track.kind()); - } - } -}); - -vjs.TextTrackMenuItem.prototype.onClick = function () { - vjs.MenuItem.prototype.onClick.call(this); - this.player_.showTextTrack(this.track.id_, this.track.kind()); - $('.vjs-text-track').css('display', 'inline-block'); -}; - -vjs.TextTrackMenuItem.prototype.update = function () { - this.selected(this.track.mode() === 2); -}; - -vjs.Player.prototype.onLoadStart = function () { - if (this.error()) { - this.error(null); - } - - vjs.addClass(this.el_, 'vjs-has-started'); - this.trigger('volumechange'); -}; - -/** - * The custom progressbar we create. Updated in player.js - * - * @constructor - */ -vjs.LoadProgressBar = vjs.Component.extend({ - init: function (player, options) { - vjs.Component.call(this, player, options); - this.on(player, 'progress', this.update); - } -}); -vjs.LoadProgressBar.prototype.createEl = function () { - return vjs.Component.prototype.createEl.call(this, 'div', { - className: 'vjs-load-progress', - innerHTML: '' + this.localize('Loaded') + ': 0%' - }); -}; -vjs.LoadProgressBar.prototype.update = function () { - return; -}; - -vjs.Player.prototype.volume = function (percentAsDecimal) { - var vol; - - if (percentAsDecimal !== undefined) { - vol = Math.max(0, Math.min(1, parseFloat(percentAsDecimal))); // Force value to between 0 and 1 - this.cache_.volume = vol; - this.techCall('setVolume', vol); - vjs.setLocalStorage('volume', vol); - - //let's save this bad boy - AdvSettings.set('playerVolume', vol.toFixed(2)); - App.PlayerView.displayOverlayMsg(i18n.__('Volume') + ': ' + (vol.toFixed(2) * 100).toFixed(0) + '%'); - - return this; - } - - // Default to 1 when returning current volume. - vol = parseFloat(this.techGet('volume')); - - if ($('.vjs-overlay')) { - $('.vjs-overlay').css('opacity', '1'); - } - - return (isNaN(vol)) ? 1 : vol; -}; - -//Display our own error -var suggestedExternal = function () { - var link = 'VLC'; - try { - App.Device.Collection.models.forEach(function (player) { - link = (player.id === 'VLC') ? player.id : link; - }); - } catch (e) {} - return link; -}; - -vjs.ErrorDisplay.prototype.update = function () { - if (this.player().error()) { - if (this.player().error().message === 'The video playback was aborted due to a corruption problem or because the video used features your browser did not support.') { - this.contentEl_.innerHTML = i18n.__('The video playback encountered an issue. Please try an external player like %s to view this content.', suggestedExternal()); - } else { - this.contentEl_.innerHTML = this.player().error().message; - } - } -}; - -// Remove videojs key listeners -vjs.Button.prototype.onKeyPress = function (event) { - return; -}; - -// Dispose needs to clear currentTimeInterval to avoid vdata error (https://github.com/videojs/video.js/issues/1484#issuecomment-55245716) -vjs.MediaTechController.prototype.dispose = function () { - // Turn off any manual progress or timeupdate tracking - if (this.manualProgress) { - this.manualProgressOff(); - } - - if (this.manualTimeUpdates) { - this.manualTimeUpdatesOff(); - } - - clearInterval(this.currentTimeInterval); - - vjs.Component.prototype.dispose.call(this); -}; -// Custom hasData function to not error if el==null (vdata error) -vjs.prototype.hasData = function (el) { - if (!el) { - return; - } - var id = el[vjs.expando]; - return !(!id || vjs.isEmpty(vjs.cache[id])); -}; +// videojs.options['children'] = { +// 'mediaLoader': {}, +// 'posterImage': {}, +// 'textTrackDisplay': {}, +// 'loadingSpinner': {}, +// //'bigPlayButton': {}, +// 'controlBar': {}, +// 'errorDisplay': {} +// }; +// +// vjs.Player.prototype.debugMouse_ = false; +// vjs.Player.prototype.reportUserActivity = function (event) { +// /** DEBUG MOUSE CTRL+D **/ +// if (this.debugMouse_) { +// console.log('Event fired at: ' + vjs.formatTime(this.player_.currentTime(), this.player_.duration())); +// console.log(event); +// } +// if (event !== undefined && event.type === 'mousemove') { +// if (event.webkitMovementX === 0 && event.webkitMovementY === 0) { +// return; +// } +// } +// this.userActivity_ = true; +// }; +// +// vjs.Player.prototype.listenForUserActivity = function () { +// var onActivity, onMouseDown, mouseInProgress, onMouseUp, +// activityCheck, inactivityTimeout; +// +// onActivity = vjs.bind(this, this.reportUserActivity); +// +// onMouseDown = function (e) { +// onActivity(e); +// clearInterval(mouseInProgress); +// mouseInProgress = setInterval(onActivity, 250); +// }; +// +// onMouseUp = function (e) { +// onActivity(e); +// clearInterval(mouseInProgress); +// }; +// +// this.on('mousedown', onMouseDown); +// this.on('mousemove', onActivity); +// this.on('mouseup', onMouseUp); +// this.on('keydown', onActivity); +// this.on('keyup', onActivity); +// +// activityCheck = setInterval(vjs.bind(this, function () { +// if (this.userActivity_) { +// this.userActivity_ = false; +// this.userActive(true); +// clearTimeout(inactivityTimeout); +// inactivityTimeout = setTimeout(vjs.bind(this, function () { +// if (!this.userActivity_) { +// this.userActive(false); +// } +// }), 2000); +// } +// }), 250); +// +// this.on('dispose', function () { +// clearInterval(activityCheck); +// clearTimeout(inactivityTimeout); +// }); +// }; +// +// vjs.Player.prototype.onFullscreenChange = function (e) { +// e.stopPropagation(); +// if (this.isFullscreen()) { +// this.addClass('vjs-fullscreen'); +// $('.vjs-text-track').css('font-size', '140%'); +// $('.state-info-player').css('font-size', '65px'); +// } else { +// this.removeClass('vjs-fullscreen'); +// $('.vjs-text-track').css('font-size', ''); +// $('.state-info-player').css('font-size', '50px'); +// } +// }; +// +// // This is a custom way of loading subtitles, since we can't use src (CORS blocks it and we can't disable it) +// // We fetch them when requested, process them and finally throw a parseCues their way +// vjs.TextTrack.prototype.load = function () { +// // Only load if not loaded yet. +// if (this.readyState_ === 0) { +// var this_ = this; +// this.readyState_ = 1; +// +// var subsParams = function () { +// var subtitles = $('.vjs-subtitles'), +// vjsTextTrack = $('.vjs-text-track'), +// vjsTextTrackDsp = $('.vjs-text-track-display'); +// +// vjsTextTrack.css('display', 'inline-block').drags(); +// vjsTextTrackDsp.css('font-size', Settings.subtitle_size); +// if (win.isFullscreen) { +// vjsTextTrack.css('font-size', '140%'); +// } +// subtitles.css('color', Settings.subtitle_color); +// subtitles.css('font-family', Settings.subtitle_font); +// if (Settings.subtitle_decoration === 'None') { +// vjsTextTrack.css('text-shadow', 'none'); +// } else if (Settings.subtitle_decoration === 'Opaque Background') { +// vjsTextTrack.css('background', '#000'); +// } else if (Settings.subtitle_decoration === 'See-through Background') { +// vjsTextTrack.css('background', 'rgba(0,0,0,.5)'); +// } +// if (Settings.subtitles_bold) { +// vjsTextTrack.css('font-weight', 'bold'); +// } +// vjsTextTrack.css('z-index', 'auto').css('position', 'relative').css('top', AdvSettings.get('playerSubPosition')); +// }; +// +// // Fetches a raw subtitle, locally or remotely +// var get_subtitle = function (subtitle_url, callback) { +// +// // Fetches Locally +// if (fs.existsSync(path.join(subtitle_url))) { +// fs.readFile(subtitle_url, function (error, data) { +// if (!error) { +// callback(data); +// } else { +// console.warn('Failed to read subtitle!', error); +// } +// }); +// // Fetches Remotely +// } else { +// request({ +// url: subtitle_url, +// encoding: null +// }, function (error, response, data) { +// if (!error && response.statusCode === 200) { +// callback(data); +// } else { +// console.warn('Failed to download subtitle!', error, response); +// } +// }); +// } +// }; +// +// //transcode .ass, .ssa, .txt to SRT +// var convert2srt = function (file, ext, callback) { +// var readline = require('readline'), +// counter = null, +// lastBeginTime, +// +// //input +// orig = /([^\\]+)$/.exec(file)[1], +// origPath = file.substr(0, file.indexOf(orig)), +// +// //output +// srt = orig.replace(ext, '.srt'), +// srtPath = Settings.tmpLocation, +// +// //elements +// dialog, begin_time, end_time; +// +// fs.writeFileSync(path.join(srtPath, srt), ''); //create or delete content; +// console.log('SUB format can be converted:', orig); +// +// var rl = readline.createInterface({ +// input: fs.createReadStream(path.join(origPath, orig)), +// output: process.stdout, +// terminal: false +// }); +// rl.on('line', function (line) { +// +// //detect encoding +// var charset = charsetDetect.detect(line); +// var encoding = charset.encoding; +// var line_, parsedBeginTime, parsedEndTime, parsedDialog; +// +// //parse SSA +// if (ext === '.ssa' || ext === '.ass') { +// encoding = 'utf-8'; +// if (line.indexOf('Format:') !== -1) { +// var ssaFormat = line.split(','); +// +// for (var i = 0; i < ssaFormat.length; i++) { +// switch (ssaFormat[i]) { +// case 'Text': +// case ' Text': +// dialog = i; +// break; +// case 'Start': +// case ' Start': +// begin_time = i; +// break; +// case 'End': +// case ' End': +// end_time = i; +// break; +// default: +// } +// } +// +// if (dialog && begin_time && end_time) { +// console.log('SUB formatted in \'ssa\''); +// } +// return; //we have the elms spots, move on to the next line +// } +// +// if (line.indexOf('Dialogue:') === -1) { //not a dialog line +// return; +// } +// +// line_ = line.split(','); +// +// parsedBeginTime = line_[begin_time]; +// parsedEndTime = line_[end_time]; +// parsedDialog = line_[dialog]; +// parsedDialog = parsedDialog.replace('{\\i1}', '').replace('{\\i0}', ''); //italics +// parsedDialog = parsedDialog.replace('{\\b1}', '').replace('{\\b0}', ''); //bold +// parsedDialog = parsedDialog.replace('\\N', '\n'); //return to line +// parsedDialog = parsedDialog.replace(/{.*?}/g, ''); //remove leftovers brackets +// } +// +// //parse TXT +// if (ext === '.txt') { +// line_ = line.split('}'); +// +// var formatSeconds = function (seconds) { +// var date = new Date(1970, 0, 1); +// date.setSeconds(seconds); +// return date.toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, '$1'); +// }; +// +// parsedBeginTime = formatSeconds(line_[0].replace('{', '') / 25); +// parsedEndTime = formatSeconds(line_[1].replace('{', '') / 25); +// parsedDialog = line_[2].replace('|', '\n'); +// } +// +// //SRT needs a number for each subtitle +// counter += 1; +// +// //keep only the last lang +// if (parsedBeginTime < lastBeginTime) { +// counter = 1; +// fs.writeFileSync(path.join(srtPath, srt), ''); +// console.log('SUB contains multiple tracks, keeping only the last'); +// } +// +// //SRT formatting +// var parsedLine = +// counter + '\n' + +// parsedBeginTime + ' --> ' + parsedEndTime + '\n' + +// parsedDialog; +// +// fs.appendFileSync(path.join(srtPath, srt), '\n\n' + parsedLine, encoding); +// lastBeginTime = parsedBeginTime; +// }); +// +// setTimeout(function () { +// fs.readFile(path.join(srtPath, srt), function (err, dataBuff) { +// if (!err) { +// console.log('SUB transcoded to SRT:', srt); +// callback(dataBuff); +// } else { +// console.warn('SUB transcoding failed', err); +// } +// }); +// }, 2000); +// }; +// +// // Decompress zip +// var decompress = function (dataBuff, callback) { +// try { +// var zip = new AdmZip(dataBuff); +// var zipEntries = zip.getEntries(); +// // TODO: Shouldn't we look for only 1 file ??? +// zipEntries.forEach(function (zipEntry, key) { +// if (zipEntry.entryName.indexOf('.srt') !== -1) { +// var decompressedData = zip.readFile(zipEntry); +// callback(decompressedData); +// } +// }); +// } catch (error) { +// console.warn('Failed to decompress subtitle!', error); +// } +// }; +// +// // Handles charset encoding +// var decode = function (dataBuff, language, callback) { +// if(language && language.indexOf('|')!==-1){ +// language = language.substr(0,language.indexOf('|')); +// } +// +// var targetEncodingCharset = 'utf8'; +// +// var parse = function (strings) { +// strings = strings +// .replace(/\{.*\}/g, '') // {/pos(x,y)} +// .replace(/(- |==|sync).*[\s\S].*[\s\S].*[\s\S].*[\s\S].*\.(com|org|net|edu)/ig, '') // various teams +// .replace(/[^0-9][\s\S][^0-9\W].*[\s\S].*[\s\S].*opensubtitles.*/ig, ''); // opensubs "contact us" ads +// +// // clean two following subtitle indexes for one timing, example: +// // 3 +// // 2 +// // 00:00:59,142 --> 00:01:01,144 +// // N'Y COMPTE PAS +// // +// strings = strings.replace(/^(\d{1,5}\r*\n)(\d{1,5}\r*\n)((\d\d:){2}\d\d,\d{3}\s-->\s(\d\d:){2}\d\d,\d{3}\r*\n)/gm, '$1$3'); +// +// strings = Common.sanitize(strings); // xss-style attacks +// strings = strings.replace(/--\>\;/g, '-->'); // restore srt format +// callback(strings); +// }; +// +// var charset = charsetDetect.detect(dataBuff); +// var detectedEncoding = charset.encoding; +// console.log('SUB charset detected: ' + detectedEncoding); +// // Do we need decoding? +// if (detectedEncoding && detectedEncoding.toLowerCase().replace('-', '') === targetEncodingCharset) { +// parse(dataBuff.toString('utf-8')); +// // We do +// } else { +// if (!language && Settings.subtitle_language !== 'none') { +// language = Settings.subtitle_language; +// console.log('SUB charset: using subtitles_language setting (' + language + ') as default'); +// } +// var langInfo = App.Localization.langcodes[language] || {}; +// console.log('SUB charset expected:', langInfo.encoding); +// if (langInfo.encoding !== undefined && langInfo.encoding.indexOf(detectedEncoding) < 0) { +// // The detected encoding was unexepected to the language, so we'll use the most common +// // encoding for that language instead. +// detectedEncoding = langInfo.encoding[0]; +// dataBuff = iconv.encode(iconv.decode(dataBuff, detectedEncoding), targetEncodingCharset); +// } else { +// // fallback to utf8 +// console.log('SUB charset: fallback to utf-8'); +// dataBuff = iconv.decode(dataBuff, detectedEncoding); +// detectedEncoding = 'UTF-8'; +// } +// console.log('SUB charset used:', detectedEncoding); +// parse(dataBuff.toString('utf-8')); +// } +// }; +// +// var vjsBind = function (data) { +// try { +// this_.parseCues(data); +// } catch (e) { +// console.error('Error reading subtitles timing, file seems corrupted', e); +// subsParams(); +// App.vent.trigger('notification:show', new App.Model.Notification({ +// title: i18n.__('Error reading subtitle timings, file seems corrupted'), +// body: i18n.__('Try another subtitle or drop one in the player'), +// showRestart: false, +// type: 'error', +// autoclose: true +// })); +// } +// }; +// +// this.on('loaded', function () { +// console.log('Subtitles loaded!'); +// subsParams(); +// }); +// +// // Get it, Unzip it, Decode it, Send it +// get_subtitle(this.src_, function (dataBuf) { +// if (path.extname(this_.src_) === '.zip') { +// decompress(dataBuf, function (dataBuf) { +// decode(dataBuf, this_.language(), vjsBind); +// }); +// } else if (path.extname(this_.src_) === '.ass' || path.extname(this_.src_) === '.ssa' || path.extname(this_.src_) === '.txt') { +// convert2srt(this_.src_, path.extname(this_.src_), function (dataBuf) { +// decode(dataBuf, this_.language(), vjsBind); +// }); +// } else { +// decode(dataBuf, this_.language(), vjsBind); +// } +// }); +// +// } +// +// }; +// +// /** +// * The specific menu item type for selecting a language within a text track kind +// * +// * @constructor +// */ +// vjs.TextTrackMenuItem = vjs.MenuItem.extend({ +// /** @constructor */ +// init: function (player, options) { +// var track = this.track = options['track']; +// +// // Modify options for parent MenuItem class's init. +// options['label'] = track.label(); +// options['selected'] = track.dflt(); +// vjs.MenuItem.call(this, player, options); +// +// this.player_.on(track.kind() + 'trackchange', vjs.bind(this, this.update)); +// +// // Popcorn Time Fix +// // Allowing us to send a default language +// if (track.dflt()) { +// this.player_.showTextTrack(this.track.id_, this.track.kind()); +// } +// } +// }); +// +// vjs.TextTrackMenuItem.prototype.onClick = function () { +// vjs.MenuItem.prototype.onClick.call(this); +// this.player_.showTextTrack(this.track.id_, this.track.kind()); +// $('.vjs-text-track').css('display', 'inline-block'); +// }; +// +// vjs.TextTrackMenuItem.prototype.update = function () { +// this.selected(this.track.mode() === 2); +// }; +// +// vjs.Player.prototype.onLoadStart = function () { +// if (this.error()) { +// this.error(null); +// } +// +// vjs.addClass(this.el_, 'vjs-has-started'); +// this.trigger('volumechange'); +// }; +// +// /** +// * The custom progressbar we create. Updated in player.js +// * +// * @constructor +// */ +// vjs.LoadProgressBar = vjs.Component.extend({ +// init: function (player, options) { +// vjs.Component.call(this, player, options); +// this.on(player, 'progress', this.update); +// } +// }); +// vjs.LoadProgressBar.prototype.createEl = function () { +// return vjs.Component.prototype.createEl.call(this, 'div', { +// className: 'vjs-load-progress', +// innerHTML: '' + this.localize('Loaded') + ': 0%' +// }); +// }; +// vjs.LoadProgressBar.prototype.update = function () { +// return; +// }; +// +// vjs.Player.prototype.volume = function (percentAsDecimal) { +// var vol; +// +// if (percentAsDecimal !== undefined) { +// vol = Math.max(0, Math.min(1, parseFloat(percentAsDecimal))); // Force value to between 0 and 1 +// this.cache_.volume = vol; +// this.techCall('setVolume', vol); +// vjs.setLocalStorage('volume', vol); +// +// //let's save this bad boy +// AdvSettings.set('playerVolume', vol.toFixed(2)); +// App.PlayerView.displayOverlayMsg(i18n.__('Volume') + ': ' + (vol.toFixed(2) * 100).toFixed(0) + '%'); +// +// return this; +// } +// +// // Default to 1 when returning current volume. +// vol = parseFloat(this.techGet('volume')); +// +// if ($('.vjs-overlay')) { +// $('.vjs-overlay').css('opacity', '1'); +// } +// +// return (isNaN(vol)) ? 1 : vol; +// }; +// +// //Display our own error +// var suggestedExternal = function () { +// var link = 'VLC'; +// try { +// App.Device.Collection.models.forEach(function (player) { +// link = (player.id === 'VLC') ? player.id : link; +// }); +// } catch (e) {} +// return link; +// }; +// +// vjs.ErrorDisplay.prototype.update = function () { +// if (this.player().error()) { +// if (this.player().error().message === 'The video playback was aborted due to a corruption problem or because the video used features your browser did not support.') { +// this.contentEl_.innerHTML = i18n.__('The video playback encountered an issue. Please try an external player like %s to view this content.', suggestedExternal()); +// } else { +// this.contentEl_.innerHTML = this.player().error().message; +// } +// } +// }; +// +// // Remove videojs key listeners +// vjs.Button.prototype.onKeyPress = function (event) { +// return; +// }; +// +// // Dispose needs to clear currentTimeInterval to avoid vdata error (https://github.com/videojs/video.js/issues/1484#issuecomment-55245716) +// vjs.MediaTechController.prototype.dispose = function () { +// // Turn off any manual progress or timeupdate tracking +// if (this.manualProgress) { +// this.manualProgressOff(); +// } +// +// if (this.manualTimeUpdates) { +// this.manualTimeUpdatesOff(); +// } +// +// clearInterval(this.currentTimeInterval); +// +// vjs.Component.prototype.dispose.call(this); +// }; +// // Custom hasData function to not error if el==null (vdata error) +// vjs.prototype.hasData = function (el) { +// if (!el) { +// return; +// } +// var id = el[vjs.expando]; +// return !(!id || vjs.isEmpty(vjs.cache[id])); +// }; diff --git a/src/app/vendor/videojsplugins.js b/src/app/vendor/videojsplugins.js index 97d5c29f72..4bf4cec031 100644 --- a/src/app/vendor/videojsplugins.js +++ b/src/app/vendor/videojsplugins.js @@ -1,162 +1,162 @@ -// VideoJS Plugins - -videojs.BiggerSubtitleButton = videojs.Button.extend({ - /** @constructor */ - init: function (player, options) { - videojs.Button.call(this, player, options); - this.on('click', this.onClick); - } -}); - -videojs.BiggerSubtitleButton.prototype.onClick = function () { - var $subs = $('#video_player.video-js .vjs-text-track-display'); - var font_size = parseInt($subs.css('font-size')); - font_size = font_size + 2; - $subs.css('font-size', font_size + 'px'); -}; - -var createBiggerSubtitleButton = function () { - var props = { - className: 'vjs_biggersub_button vjs-control', - innerHTML: '
A+
', - role: 'button', - 'aria-live': 'polite', // let the screen reader user know that the text of the button may change - tabIndex: 0 - }; - return videojs.Component.prototype.createEl(null, props); -}; - -var biggerSubtitle; -videojs.plugin('biggerSubtitle', function () { - var options = { - 'el': createBiggerSubtitleButton() - }; - biggerSubtitle = new videojs.BiggerSubtitleButton(this, options); - this.controlBar.el().appendChild(biggerSubtitle.el()); -}); - -videojs.SmallerSubtitleButton = videojs.Button.extend({ - /** @constructor */ - init: function (player, options) { - videojs.Button.call(this, player, options); - this.on('click', this.onClick); - } -}); - -videojs.SmallerSubtitleButton.prototype.onClick = function () { - var $subs = $('#video_player.video-js .vjs-text-track-display'); - var font_size = parseInt($subs.css('font-size')); - font_size = font_size - 2; - $subs.css('font-size', font_size + 'px'); -}; - -var createSmallerSubtitleButton = function () { - var props = { - className: 'vjs_smallersub_button vjs-control', - innerHTML: '
A-
', - role: 'button', - 'aria-live': 'polite', // let the screen reader user know that the text of the button may change - tabIndex: 0 - }; - return videojs.Component.prototype.createEl(null, props); -}; - -var smallerSubtitle; -videojs.plugin('smallerSubtitle', function () { - var options = { - 'el': createSmallerSubtitleButton() - }; - smallerSubtitle = new videojs.SmallerSubtitleButton(this, options); - this.controlBar.el().appendChild(smallerSubtitle.el()); -}); - - -// Custom Subtitles Button/Menu -videojs.plugin('customSubtitles', function () { - - // Find subtitlesButton - var subtitlesButton; - this.controlBar.children().forEach(function (el) { - if (el.name() === 'subtitlesButton') { - subtitlesButton = el; - } - }); - - var CustomTrackMenuItem = vjs.TextTrackMenuItem.extend({ - - /*@ Constructor */ - init: function (player, options) { - options = options || {}; - // fake 'empty' track - options['track'] = { - kind: function () { - return 'subtitles'; - }, - player: player, - label: function () { - return i18n.__('Custom...'); - }, - dflt: function () { - return false; - }, - mode: function () { - return false; - } - }; - - this.fileInput_ = $(''); - $(this.el()).append(this.fileInput_); - - var that = this; - - App.vent.on('videojs:drop_sub', function () { - var subname = Settings.droppedSub; - var subpath = path.join(App.settings.tmpLocation, subname); - win.info('Subtitles dropped:', subname); - that.loadSubtitle(subpath); - }); - - this.fileInput_.on('change', function () { - that.player_.play(); - if (this.value === '') { - return; - } - that.loadSubtitle(this.value); - this.value = null; //reset - }); - - vjs.TextTrackMenuItem.call(this, player, options); - } - }); - - CustomTrackMenuItem.prototype.onClick = function () { - this.player_.pause(); - this.fileInput_.trigger('click'); // redirect to fileInput click - }; - - CustomTrackMenuItem.prototype.loadSubtitle = function (filePath) { - - //clean tracks - var tracks = this.player_.textTracks() || []; - for (var i = 0; i < tracks.length; ++i) { - if (tracks[i].id_.indexOf('vjs_subtitles_00') !== -1) { - $(tracks[i].el()).remove(); - tracks.splice(i, 1); - break; - } - } - - this.track = this.player_.addTextTrack('subtitles', i18n.__('Custom...'), '00', { - src: filePath - }); - App.vent.trigger('customSubtitles:added', filePath); - vjs.TextTrackMenuItem.prototype.onClick.call(this); // redirect to TextTrackMenuItem.onClick - }; - - subtitlesButton.menu.addItem(new CustomTrackMenuItem(this)); - subtitlesButton.show(); // Always show subtitles button - -}); +// // VideoJS Plugins +// +// var Button = videojs.getComponent('Button'); +// var BiggerSubtitleButton = videojs.extend(Button, { +// /** @constructor */ +// constructor: function() { +// Button.apply(this, arguments); +// }, +// handleClick: function() { +// var $subs = $('#video_player.video-js .vjs-text-track-display'); +// var font_size = parseInt($subs.css('font-size')); +// font_size = font_size + 2; +// $subs.css('font-size', font_size + 'px'); +// } +// }); +// videojs.registerComponent('BiggerSubtitleButton', BiggerSubtitleButton); +// +// var createBiggerSubtitleButton = function () { +// var props = { +// className: 'vjs_biggersub_button vjs-control', +// innerHTML: '
A+
', +// role: 'button', +// 'aria-live': 'polite', // let the screen reader user know that the text of the button may change +// tabIndex: 0 +// }; +// return videojs.Component.prototype.createEl(null, props); +// }; +// +// var biggerSubtitle; +// videojs.plugin('biggerSubtitle', function () { +// var options = { +// 'el': createBiggerSubtitleButton() +// }; +// biggerSubtitle = new BiggerSubtitleButton(this, options); +// this.controlBar.el().appendChild(biggerSubtitle.el()); +// }); + +// videojs.SmallerSubtitleButton = videojs.Button.extend({ +// /** @constructor */ +// init: function (player, options) { +// videojs.Button.call(this, player, options); +// this.on('click', this.onClick); +// } +// }); +// +// videojs.SmallerSubtitleButton.prototype.onClick = function () { +// var $subs = $('#video_player.video-js .vjs-text-track-display'); +// var font_size = parseInt($subs.css('font-size')); +// font_size = font_size - 2; +// $subs.css('font-size', font_size + 'px'); +// }; +// +// var createSmallerSubtitleButton = function () { +// var props = { +// className: 'vjs_smallersub_button vjs-control', +// innerHTML: '
A-
', +// role: 'button', +// 'aria-live': 'polite', // let the screen reader user know that the text of the button may change +// tabIndex: 0 +// }; +// return videojs.Component.prototype.createEl(null, props); +// }; +// +// var smallerSubtitle; +// videojs.plugin('smallerSubtitle', function () { +// var options = { +// 'el': createSmallerSubtitleButton() +// }; +// smallerSubtitle = new videojs.SmallerSubtitleButton(this, options); +// this.controlBar.el().appendChild(smallerSubtitle.el()); +// }); +// + +// // Custom Subtitles Button/Menu +// videojs.plugin('customSubtitles', function () { +// +// // Find subtitlesButton +// var subtitlesButton; +// this.controlBar.children().forEach(function (el) { +// if (el.name() === 'subtitlesButton') { +// subtitlesButton = el; +// } +// }); +// +// var CustomTrackMenuItem = vjs.TextTrackMenuItem.extend({ +// +// /*@ Constructor */ +// init: function (player, options) { +// options = options || {}; +// // fake 'empty' track +// options['track'] = { +// kind: function () { +// return 'subtitles'; +// }, +// player: player, +// label: function () { +// return i18n.__('Custom...'); +// }, +// dflt: function () { +// return false; +// }, +// mode: function () { +// return false; +// } +// }; +// +// this.fileInput_ = $(''); +// $(this.el()).append(this.fileInput_); +// +// var that = this; +// +// App.vent.on('videojs:drop_sub', function () { +// var subname = Settings.droppedSub; +// var subpath = path.join(App.settings.tmpLocation, subname); +// win.info('Subtitles dropped:', subname); +// that.loadSubtitle(subpath); +// }); +// +// this.fileInput_.on('change', function () { +// that.player_.play(); +// if (this.value === '') { +// return; +// } +// that.loadSubtitle(this.value); +// this.value = null; //reset +// }); +// +// vjs.TextTrackMenuItem.call(this, player, options); +// } +// }); +// +// CustomTrackMenuItem.prototype.onClick = function () { +// this.player_.pause(); +// this.fileInput_.trigger('click'); // redirect to fileInput click +// }; +// +// CustomTrackMenuItem.prototype.loadSubtitle = function (filePath) { +// +// //clean tracks +// var tracks = this.player_.textTracks() || []; +// for (var i = 0; i < tracks.length; ++i) { +// if (tracks[i].id_.indexOf('vjs_subtitles_00') !== -1) { +// $(tracks[i].el()).remove(); +// tracks.splice(i, 1); +// break; +// } +// } +// +// this.track = this.player_.addTextTrack('subtitles', i18n.__('Custom...'), '00', { +// src: filePath +// }); +// App.vent.trigger('customSubtitles:added', filePath); +// vjs.TextTrackMenuItem.prototype.onClick.call(this); // redirect to TextTrackMenuItem.onClick +// }; +// +// subtitlesButton.menu.addItem(new CustomTrackMenuItem(this)); +// subtitlesButton.show(); // Always show subtitles button +// +// }); /*! videojs-progressTips - v0.1.0 - 2013-09-16 * https://github.com/mickey/videojs-progressTips From 7da508ce562ef644a633d8aad827d4934ac765f2 Mon Sep 17 00:00:00 2001 From: Ivan Borzenkov Date: Sun, 15 Aug 2021 10:34:17 +0300 Subject: [PATCH 04/12] control bar --- src/app/vendor/videojshooks.js | 24 +++++++++++++++--------- src/app/vendor/videojsplugins.js | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/app/vendor/videojshooks.js b/src/app/vendor/videojshooks.js index 70a5d77356..8f8bafe7b5 100644 --- a/src/app/vendor/videojshooks.js +++ b/src/app/vendor/videojshooks.js @@ -1,12 +1,18 @@ -// videojs.options['children'] = { -// 'mediaLoader': {}, -// 'posterImage': {}, -// 'textTrackDisplay': {}, -// 'loadingSpinner': {}, -// //'bigPlayButton': {}, -// 'controlBar': {}, -// 'errorDisplay': {} -// }; +videojs.options['children'] = { + 'mediaLoader': {}, + 'posterImage': {}, + 'textTrackDisplay': {}, + 'loadingSpinner': {}, + //'bigPlayButton': {}, + 'controlBar': { + currentTimeDisplay : true, + durationDisplay : true, + liveDisplay: false, + seekToLive: false, + }, + 'errorDisplay': {} +}; + // // vjs.Player.prototype.debugMouse_ = false; // vjs.Player.prototype.reportUserActivity = function (event) { diff --git a/src/app/vendor/videojsplugins.js b/src/app/vendor/videojsplugins.js index 4bf4cec031..8c98b9fd27 100644 --- a/src/app/vendor/videojsplugins.js +++ b/src/app/vendor/videojsplugins.js @@ -162,7 +162,7 @@ * https://github.com/mickey/videojs-progressTips * Copyright (c) 2013 Michael Bensoussan; Licensed MIT */ -videojs.plugin('progressTips', function (options) { +videojs.registerPlugin('progressTips', function (options) { var init; init = function () { var player; From 6ae4113666aeeb33e6a3c19b551d0acefa9af73e Mon Sep 17 00:00:00 2001 From: Ivan Borzenkov Date: Sun, 15 Aug 2021 13:28:26 +0300 Subject: [PATCH 05/12] fix load --- src/app/global.js | 2 -- src/app/index.html | 6 +++--- src/app/lib/views/player/player.js | 4 ++-- src/app/styl/views/player.styl | 1 - src/app/styl/views/videojs.styl | 4 ++-- src/app/vendor/videojshooks.js | 26 -------------------------- 6 files changed, 7 insertions(+), 36 deletions(-) diff --git a/src/app/global.js b/src/app/global.js index b61237e9bd..8749831bb2 100644 --- a/src/app/global.js +++ b/src/app/global.js @@ -46,7 +46,5 @@ var _ = require('underscore'), // setting default filters status curSetDefaultFilters = false; -require('videojs-youtube'); - dayjs.extend(require('dayjs/plugin/relativeTime')); dayjs.extend(require('dayjs/plugin/localizedFormat')); diff --git a/src/app/index.html b/src/app/index.html index 8e8aa98713..e7c476ab35 100644 --- a/src/app/index.html +++ b/src/app/index.html @@ -6,7 +6,7 @@ - + @@ -57,13 +57,13 @@ - + - + diff --git a/src/app/lib/views/player/player.js b/src/app/lib/views/player/player.js index c242e6d476..d8495e2325 100644 --- a/src/app/lib/views/player/player.js +++ b/src/app/lib/views/player/player.js @@ -469,7 +469,7 @@ // start videojs engine if (this.model.get('type') === 'video/youtube') { - this.video = videojs($('#video_player').get(0), { + this.video = videojs('video_player', { techOrder: ['youtube'], forceSSL: true, ytcontrols: false, @@ -501,7 +501,7 @@ }); } else { - this.video = videojs($('#video_player').get(0), { + this.video = videojs('video_player', { nativeControlsForTouch: false, trackTimeOffset: 0, //inactivityTimeout: 2000, diff --git a/src/app/styl/views/player.styl b/src/app/styl/views/player.styl index a8cc14e9b2..5e1b05b6d8 100644 --- a/src/app/styl/views/player.styl +++ b/src/app/styl/views/player.styl @@ -15,7 +15,6 @@ position: absolute overflow: hidden background-color: #000 - font-size: 10px; video { width: 100% height: 100% diff --git a/src/app/styl/views/videojs.styl b/src/app/styl/views/videojs.styl index 0d51dc9cb8..925a51cd78 100644 --- a/src/app/styl/views/videojs.styl +++ b/src/app/styl/views/videojs.styl @@ -293,7 +293,8 @@ padding-top: 0.1em; } } - .vjs-time-controls { + .vjs-time-control { + display: block; position: relative; color: #fff; font-family: "Open Sans", sans-serif; @@ -311,7 +312,6 @@ } .vjs-remaining-time { display: none; - float: left; } .vjs-fullscreen-control { position: relative; diff --git a/src/app/vendor/videojshooks.js b/src/app/vendor/videojshooks.js index 8f8bafe7b5..f11de80c72 100644 --- a/src/app/vendor/videojshooks.js +++ b/src/app/vendor/videojshooks.js @@ -7,8 +7,6 @@ videojs.options['children'] = { 'controlBar': { currentTimeDisplay : true, durationDisplay : true, - liveDisplay: false, - seekToLive: false, }, 'errorDisplay': {} }; @@ -498,27 +496,3 @@ videojs.options['children'] = { // vjs.Button.prototype.onKeyPress = function (event) { // return; // }; -// -// // Dispose needs to clear currentTimeInterval to avoid vdata error (https://github.com/videojs/video.js/issues/1484#issuecomment-55245716) -// vjs.MediaTechController.prototype.dispose = function () { -// // Turn off any manual progress or timeupdate tracking -// if (this.manualProgress) { -// this.manualProgressOff(); -// } -// -// if (this.manualTimeUpdates) { -// this.manualTimeUpdatesOff(); -// } -// -// clearInterval(this.currentTimeInterval); -// -// vjs.Component.prototype.dispose.call(this); -// }; -// // Custom hasData function to not error if el==null (vdata error) -// vjs.prototype.hasData = function (el) { -// if (!el) { -// return; -// } -// var id = el[vjs.expando]; -// return !(!id || vjs.isEmpty(vjs.cache[id])); -// }; From bf15d74f7953d532d34b0df5e361273dc103234e Mon Sep 17 00:00:00 2001 From: Ivan Borzenkov Date: Sun, 15 Aug 2021 16:05:42 +0300 Subject: [PATCH 06/12] interface --- src/app/lib/views/player/player.js | 2 +- src/app/styl/views/videojs.styl | 1750 ++++++++++++++-------------- src/app/vendor/videojshooks.js | 11 +- src/app/vendor/videojsplugins.js | 92 +- 4 files changed, 941 insertions(+), 914 deletions(-) diff --git a/src/app/lib/views/player/player.js b/src/app/lib/views/player/player.js index d8495e2325..caa6cf3ca9 100644 --- a/src/app/lib/views/player/player.js +++ b/src/app/lib/views/player/player.js @@ -509,7 +509,7 @@ //biggerSubtitle: {}, //smallerSubtitle: {}, //customSubtitles: {}, - progressTips: {} + //progressTips: {} } }); this.video.ready(function () { diff --git a/src/app/styl/views/videojs.styl b/src/app/styl/views/videojs.styl index 925a51cd78..c9cf4d736e 100644 --- a/src/app/styl/views/videojs.styl +++ b/src/app/styl/views/videojs.styl @@ -1,871 +1,891 @@ .vjs-popcorn-skin { - color: #1c1c1c; - .vjs-slider { - position: relative; - cursor: pointer; - background-color: rgba(255,255,255,0.2); - &:hover { - & > .vjs-slider-handle:before { - color: $PlayerColor; - } - } - } - .vjs-slider-handle { - position: absolute; - top: -6px; - width: 14px; - height: 14px; - margin-left: -8px; - &:before { - color: rgba(255,255,255,0); - content: '\25CF'; - font-size: 46px; - line-height: 14px; - transition: all .1s !important; - } - } - - .vjs-control-bar, .vjs-control-window { - display: none; - position: absolute; - bottom: 0; - left: 0; - background: linear-gradient(transparent, rgba(0,0,0,0.7)); - } - - .vjs-control-bar { - right: 0; - height: 60px; - width: 100%; - } - - &.vjs-user-active { - .player-header-background { - display: block; - } - } - .vjs-live-controls { - display: none; - } - &.vjs-has-started { - &.vjs-user-inactive { - &.vjs-playing { - .vjs-control-bar, .vjs-control-window { - display: block; - visibility: hidden; - opacity: 0; - transition: visibility 1s, opacity 1s; - transition: visibility 1s, opacity 1s; - } - } - } - .vjs-big-play-button { - display: none; - } - } - &.vjs-controls-disabled { - .vjs-control-bar, .vjs-control-window { - display: none; - } - .vjs-big-play-button { - display: none; - } - } - &.vjs-using-native-controls { - .vjs-control-bar, .vjs-control-window { - display: none; - } - .vjs-big-play-button { - display: none; - } - } - &.vjs-error { - .vjs-control-bar, .vjs-control-window { - display: none; - } - .player-header-background { - &.vjs-control-bar, .vjs-control-window { - visibility: visible!important; - opacity: 1!important; - display: block!important; - } - } - } - .vjs-control { - outline: none; - position: relative; - float: left; - text-align: center; - margin: 0; - &:focus { - } - } - .vjs-control-text { - border: 0; - clip: rect(0 0 0 0); - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; - width: 1px; - } - .vjs-play-control { - top: 24px; - cursor: pointer; - width: 14px; - height: 16px; - margin-left: 20px; - &:hover { - transition: all .5s; - -webkit-filter: brightness(0.70); - &:before { - text-shadow: none !important; - } - } - &:before { - position: relative; - text-shadow: none !important; - content: "\f04b"; - color: white; - font-family: "Font Awesome 6 Free"; - font-size: 14px; - line-height: 17px; - font-weight: 900; - } - } - &.vjs-playing { - .vjs-play-control { - &:before { - content: "\f04c"; - } - } - } - .vjs-playback-rate { - .vjs-playback-rate-value { - font-size: 1.5em; - line-height: 2; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - text-align: center; - text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5); - } - &.vjs-menu-button { - .vjs-menu { - .vjs-menu-content { - width: 4em; - left: -2em; - list-style: none; - } - } - } - } - .vjs-mute-control { - &:hover { - transition: all .5s; - -webkit-filter: brightness(0.70); - } + //color: #1c1c1c; + //.vjs-slider { + // position: relative; + // cursor: pointer; + // background-color: rgba(255,255,255,0.2); + // &:hover { + // & > .vjs-slider-handle:before { + // color: $PlayerColor; + // } + // } + //} + //.vjs-slider-handle { + // position: absolute; + // top: -6px; + // width: 14px; + // height: 14px; + // margin-left: -8px; + // &:before { + // color: rgba(255,255,255,0); + // content: '\25CF'; + // font-size: 46px; + // line-height: 14px; + // transition: all .1s !important; + // } + //} + // + //.vjs-control-bar, .vjs-control-window { + // display: none; + // position: absolute; + // bottom: 0; + // left: 0; + // background: linear-gradient(transparent, rgba(0,0,0,0.7)); + //} + // + //.vjs-control-bar { + // right: 0; + // height: 60px; + // width: 100%; + //} + // + //&.vjs-user-active { + // .player-header-background { + // display: block; + // } + //} + //.vjs-live-controls { + // display: none; + //} + //&.vjs-has-started { + // &.vjs-user-inactive { + // &.vjs-playing { + // .vjs-control-bar, .vjs-control-window { + // display: block; + // visibility: hidden; + // opacity: 0; + // transition: visibility 1s, opacity 1s; + // transition: visibility 1s, opacity 1s; + // } + // } + // } + // .vjs-big-play-button { + // display: none; + // } + //} + //&.vjs-controls-disabled { + // .vjs-control-bar, .vjs-control-window { + // display: none; + // } + // .vjs-big-play-button { + // display: none; + // } + //} + //&.vjs-using-native-controls { + // .vjs-control-bar, .vjs-control-window { + // display: none; + // } + // .vjs-big-play-button { + // display: none; + // } + //} + //&.vjs-error { + // .vjs-control-bar, .vjs-control-window { + // display: none; + // } + // .player-header-background { + // &.vjs-control-bar, .vjs-control-window { + // visibility: visible!important; + // opacity: 1!important; + // display: block!important; + // } + // } + //} + //.vjs-control { + // outline: none; + // position: relative; + // float: left; + // text-align: center; + // margin: 0; + // &:focus { + // } + //} + //.vjs-control-text { + // border: 0; + // clip: rect(0 0 0 0); + // height: 1px; + // margin: -1px; + // overflow: hidden; + // padding: 0; + // position: absolute; + // width: 1px; + //} + //.vjs-play-control { + // top: 24px; + // cursor: pointer; + // width: 14px; + // height: 16px; + // margin-left: 20px; + // &:hover { + // transition: all .5s; + // -webkit-filter: brightness(0.70); + // &:before { + // text-shadow: none !important; + // } + // } + // &:before { + // position: relative; + // text-shadow: none !important; + // content: "\f04b"; + // color: white; + // font-family: "Font Awesome 5 Free"; + // font-size: 14px; + // line-height: 17px; + // font-weight: 900; + // } + //} + //&.vjs-playing { + // .vjs-play-control { + // &:before { + // content: "\f04c"; + // } + // } + //} + //.vjs-playback-rate { + // .vjs-playback-rate-value { + // font-size: 1.5em; + // line-height: 2; + // position: absolute; + // top: 0; + // left: 0; + // width: 100%; + // height: 100%; + // text-align: center; + // text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5); + // } + // &.vjs-menu-button { + // .vjs-menu { + // .vjs-menu-content { + // width: 4em; + // left: -2em; + // list-style: none; + // } + // } + // } + //} + //.vjs-mute-control { + // &:hover { + // transition: all .5s; + // -webkit-filter: brightness(0.70); + // } + //} + //.vjs-volume-control { + // top: 29px; + // width: 54px; + // float: right; + // margin-right: 0px; + // overflow: hidden; + // height: 6px; + // border-radius: 3px/2px; + // &:hover { + // top: 28px; + // height: 8px; + // & > .vjs-volume-bar { + // height: 8px; + // } + // } + //} + //.vjs-volume-bar { + // top: 0px; + // left: -7px; + // height: 6px; + // width: 69px; + // margin-right: 0px; + // border-radius: 3px / 2px; + // &:hover { + // & > .vjs-volume-level { + // height: 8px; + // } + // & > .vjs-volume-handle:before { + // font-size: 14px; + // color: rgba(0, 0, 0, 0); + // } + // } + //} + //.vjs-volume-menu-button { + // .vjs-menu-content { + // height: 2.9em; + // } + //} + //.vjs-volume-level { + // position: absolute; + // top: 0; + // left: 0; + // height: 6px; + // background-color: $PlayerColor; + // border-radius: 3px / 2px; + // border-radius: 3px / 2px; + // background-clip: padding; + // background-clip: padding-box; + //} + //.vjs-volume-handle { + // &:before { + // color: rgba(0, 0, 0, 0); + // content: '\25CF'; + // font-size: 14px; + // line-height: 17px; + // margin-left: 10px; + // } + //} + //.vjs-progress-control { + // position: absolute; + // top: 19px; + // width: auto; + // height: 18px; + // border-radius: 3px / 2px; + // border-radius: 3px / 2px; + // background-clip: padding-box; + // background-clip: padding-box; + // left: 190px; + // right: 250px; + // padding-top: 10px; + // padding-bottom: 2px; + // cursor: pointer; + // transition: all .1s !important; + // &:hover { + // height: 20px; + // top: 18px; + // & > .vjs-progress-holder > .vjs-seek-handle:before { + // color: $PlayerColor; + // } + // } + //} + //&:hover { + // .vjs-progress-control { + // border-radius: 3px / 2px; + // background-clip: padding; + // background-clip: padding-box; + // } + //} + //.vjs-progress-holder { + // height: calc(100% + 12px); + // top: -10px; + // border-radius: 3px/12px 12px 4px 4px; + // border-top: 10px solid rgba(0,0,0,0); + // border-bottom: 2px solid rgba(0,0,0,0); + // background-clip: padding; + // background-clip: padding-box; + //} + //.vjs-play-progress { + // background-color: $PlayerColor; + // transition: all 0.5s ease; + //} + //@keyframes progress { + // to { background-position: -30px 0; } + //} + //.vjs-load-progress { + // border-radius: 3px / 2px; + // border-radius: 3px / 2px; + // background-clip: padding-box; + // background-clip: padding-box; + // background-size: 6px 6px; + // transition: width 2s; + // animation: progress 2.8s linear infinite; + // background-repeat: repeat-x; + // background-color: white; + // opacity: 0.4; + //} + //.vjs-seek-handle { + // width: 11px; + // height: 11px; + // transition: all 0.5s ease; + // &:before { + // padding-top: 0.1em; + // } + //} + .vjs-volume-panel { + order: 1; + &.vjs-volume-panel-horizontal { + width: 10em; } .vjs-volume-control { - top: 29px; - width: 54px; - float: right; - margin-right: 0px; - overflow: hidden; - height: 6px; - border-radius: 3px/2px; - &:hover { - top: 28px; - height: 8px; - & > .vjs-volume-bar { - height: 8px; - } - } - } - .vjs-volume-bar { - top: 0px; - left: -7px; - height: 6px; - width: 69px; - margin-right: 0px; - border-radius: 3px / 2px; - &:hover { - & > .vjs-volume-level { - height: 8px; - } - & > .vjs-volume-handle:before { - font-size: 14px; - color: rgba(0, 0, 0, 0); - } - } - } - .vjs-volume-menu-button { - .vjs-menu-content { - height: 2.9em; - } - } - .vjs-volume-level { - position: absolute; - top: 0; - left: 0; - height: 6px; - background-color: $PlayerColor; - border-radius: 3px / 2px; - border-radius: 3px / 2px; - background-clip: padding; - background-clip: padding-box; - } - .vjs-volume-handle { - &:before { - color: rgba(0, 0, 0, 0); - content: '\25CF'; - font-size: 14px; - line-height: 17px; - margin-left: 10px; - } - } - .vjs-progress-control { - position: absolute; - top: 19px; - width: auto; - height: 18px; - border-radius: 3px / 2px; - border-radius: 3px / 2px; - background-clip: padding-box; - background-clip: padding-box; - left: 190px; - right: 250px; - padding-top: 10px; - padding-bottom: 2px; - cursor: pointer; - transition: all .1s !important; - &:hover { - height: 20px; - top: 18px; - & > .vjs-progress-holder > .vjs-seek-handle:before { - color: $PlayerColor; - } - } - } - &:hover { - .vjs-progress-control { - border-radius: 3px / 2px; - background-clip: padding; - background-clip: padding-box; - } - } - .vjs-progress-holder { - height: calc(100% + 12px); - top: -10px; - border-radius: 3px/12px 12px 4px 4px; - border-top: 10px solid rgba(0,0,0,0); - border-bottom: 2px solid rgba(0,0,0,0); - background-clip: padding; - background-clip: padding-box; - } - .vjs-play-progress { - background-color: $PlayerColor; - transition: all 0.5s ease; - } - @keyframes progress { - to { background-position: -30px 0; } - } - .vjs-load-progress { - border-radius: 3px / 2px; - border-radius: 3px / 2px; - background-clip: padding-box; - background-clip: padding-box; - background-size: 6px 6px; - transition: width 2s; - animation: progress 2.8s linear infinite; - background-repeat: repeat-x; - background-color: white; - opacity: 0.4; - } - .vjs-seek-handle { - width: 11px; - height: 11px; - transition: all 0.5s ease; - &:before { - padding-top: 0.1em; - } - } - .vjs-time-control { - display: block; - position: relative; - color: #fff; - font-family: "Open Sans", sans-serif; - font-size: 16px; - top: 24px; - } - .vjs-current-time { - position: relative; - float: left; - margin-left: 18px; - } - .vjs-duration { - position: relative; - float: left; - } - .vjs-remaining-time { - display: none; - } - .vjs-fullscreen-control { - position: relative; - top: 23px; - margin-right: 17px; - margin-left: 17px; - cursor: pointer; - float: right; - width: 18px; - height: 18px; - &:hover { - transition: all .5s; - -webkit-filter: brightness(0.70); - &:before { - text-shadow: none !important; - } - } - &:before { - content: "\f065"; - text-shadow: none !important; - font-size: 18px; - font-family: "Font Awesome 6 Free"; - height: 18px; - width: 18px; - color: white; - font-weight: 900; - } - } - &.vjs-fullscreen { - .vjs-fullscreen-control { - &:before { - content: "\f066"; - } - } - } - .vjs-big-play-button { - left: 0.5em; - top: 0.5em; - font-size: 3em; - display: block; - z-index: 2; - position: absolute; - width: 4em; - height: 2.6em; - text-align: center; - vertical-align: middle; - cursor: pointer; - opacity: 1; - background-color: #07141e; - background-color: rgba(7, 20, 30, 0.7); - border: 0.1em solid #3b4249; - border-radius: 0.8em; - box-shadow: 0px 0px 1em rgba(255, 255, 255, 0.25); - transition: all 0.4s; - &:before { - content: "\e001"; - font-family: VideoJS; - line-height: 2.6em; - text-shadow: 0.05em 0.05em 0.1em #000; - text-align: center; - position: absolute; - left: 0; - width: 100%; - height: 100%; - } - } - &.vjs-big-play-centered { - .vjs-big-play-button { - left: 50%; - margin-left: -2.1em; - top: 50%; - margin-top: -1.4000000000000001em; - } - } - .vjs-loading-spinner { - &:before { - content: "\e01e"; - font-family: VideoJS; - position: absolute; - top: 0; - left: 0; - width: 1em; - height: 1em; - text-align: center; - text-shadow: 0em 0em 0.1em $PlayerColor; - color: $PlayerColor; - } - } - .vjs-menu-button { - outline: 0; - position: relative; - float: right; - cursor: pointer; - margin-right: 14px; - height: 18px; - width: 19px; - .vjs-menu { - .vjs-menu-content { - display: block; - padding: 0; - margin: 0; - outline: 0; - position: absolute; - width: 125px; - bottom: 26px; - color: #fff; - max-height: 255px; - overflow: auto; - left: -50px; - background-color: #151517; - opacity: .8; - &::-webkit-scrollbar { - width: 5px; - } - &::-webkit-scrollbar-track { - background-color: #30333c; - border-radius: 2px; - } - &::-webkit-scrollbar-thumb { - background-color: #83888c; - border-radius: 2px; - &:hover { - background-color: #93989c; - } - } - } - } - &:hover { - .vjs-menu { - display: block; - outline: 0; - } - } - ul { - li { - list-style: none; - margin: 0; - padding: 0.3em 0 0.3em 0; - line-height: 1.4em; - font-size: 1.2em; - text-align: center; - outline: 0; - &.vjs-selected { - color: $PlayerColor; - background-color: #151517; - outline: 0; - } - &.vjs-menu-title { - text-align: center; - text-transform: uppercase; - font-size: 1em; - line-height: 2em; - padding: 0; - margin: 0 0 0.3em 0; - font-weight: bold; - cursor: default; - } - } - } - } - .vjs-menu { - display: none; - position: absolute; - bottom: 0; - right: 1px; - width: 20px; - height: 30px; - margin-bottom: 10px; - outline: 0; - } - .vjs_smallersub_button { - &.vjs-control { - outline: 0; - position: relative; - float: right; - cursor: pointer; - margin-right: 14px; - height: 13px; - width: 14px; - &:hover { - transition: all .5s; - -webkit-filter: brightness(0.70); - &:before { - text-shadow: none; - } - } - &:before { - height: 13px; - width: 14px; - font-size: 14px; - line-height: 16px; - content: "A"; - color: #fff; - } - } - } - .vjs_biggersub_button { - &.vjs-control { - outline: 0; - position: relative; - float: right; - cursor: pointer; - margin-right: 14px; - height: 13px; - width: 14px; - &:hover { - transition: all .5s; - -webkit-filter: brightness(0.70); - &:before { - text-shadow: none; - } - } - &:before { - height: 13px; - width: 14px; - font-size: 18px; - line-height: 14px; - content: "A"; - color: #fff; - } - } - } - .vjs-subtitles-button { - &:before { - content: url('../images/icons/Player/Subtitles.png'); - } - &:hover { - &:before { - transition: all .5s; - -webkit-filter: brightness(0.70); - } - } - } - .vjs-hidden { - display: none; - } -} - - - .vjs-popcorn-skin { - &.vjs-has-started { - .vjs-control-bar, .vjs-control-window { - display: block; - visibility: visible; - transition: visibility 0.1s, opacity 0.1s; - transition: visibility 0.1s, opacity 0.1s; - } - } - } - - -.vjs-popcorn-skin .vjs-control:focus:before, -.vjs-popcorn-skin .vjs-control:hover:before { - text-shadow: 0em 0em 1em #ffffff; + &.vjs-volume-horizontal { + width: 5em; + height: 3em; + margin-right: 0; + } + visibility: visible; + opacity: 1; + position: relative; + } + } + .vjs-fullscreen-control { + order: 2; + } + +//.vjs-time-control { + // display: block; + // position: relative; + // color: #fff; + // font-family: "Open Sans", sans-serif; + // font-size: 16px; + // top: 24px; + //} + //.vjs-current-time { + // position: relative; + // float: left; + // margin-left: 18px; + //} + //.vjs-duration { + // position: relative; + // float: left; + //} + //.vjs-remaining-time { + // display: none; + //} + //.vjs-fullscreen-control { + // position: relative; + // top: 23px; + // margin-right: 17px; + // margin-left: 17px; + // cursor: pointer; + // float: right; + // width: 18px; + // height: 18px; + // &:hover { + // transition: all .5s; + // -webkit-filter: brightness(0.70); + // &:before { + // text-shadow: none !important; + // } + // } + // &:before { + // content: "\f065"; + // text-shadow: none !important; + // font-size: 18px; + // font-family: "Font Awesome 5 Free"; + // height: 18px; + // width: 18px; + // color: white; + // font-weight: 900; + // } + //} + //&.vjs-fullscreen { + // .vjs-fullscreen-control { + // &:before { + // content: "\f066"; + // } + // } + //} + //.vjs-big-play-button { + // left: 0.5em; + // top: 0.5em; + // font-size: 3em; + // display: block; + // z-index: 2; + // position: absolute; + // width: 4em; + // height: 2.6em; + // text-align: center; + // vertical-align: middle; + // cursor: pointer; + // opacity: 1; + // background-color: #07141e; + // background-color: rgba(7, 20, 30, 0.7); + // border: 0.1em solid #3b4249; + // border-radius: 0.8em; + // box-shadow: 0px 0px 1em rgba(255, 255, 255, 0.25); + // transition: all 0.4s; + // &:before { + // content: "\e001"; + // font-family: VideoJS; + // line-height: 2.6em; + // text-shadow: 0.05em 0.05em 0.1em #000; + // text-align: center; + // position: absolute; + // left: 0; + // width: 100%; + // height: 100%; + // } + //} + //&.vjs-big-play-centered { + // .vjs-big-play-button { + // left: 50%; + // margin-left: -2.1em; + // top: 50%; + // margin-top: -1.4000000000000001em; + // } + //} + //.vjs-loading-spinner { + // &:before { + // content: "\e01e"; + // font-family: VideoJS; + // position: absolute; + // top: 0; + // left: 0; + // width: 1em; + // height: 1em; + // text-align: center; + // text-shadow: 0em 0em 0.1em $PlayerColor; + // color: $PlayerColor; + // } + //} + //.vjs-menu-button { + // outline: 0; + // position: relative; + // float: right; + // cursor: pointer; + // margin-right: 14px; + // height: 18px; + // width: 19px; + // .vjs-menu { + // .vjs-menu-content { + // display: block; + // padding: 0; + // margin: 0; + // outline: 0; + // position: absolute; + // width: 125px; + // bottom: 26px; + // color: #fff; + // max-height: 255px; + // overflow: auto; + // left: -50px; + // background-color: #151517; + // opacity: .8; + // &::-webkit-scrollbar { + // width: 5px; + // } + // &::-webkit-scrollbar-track { + // background-color: #30333c; + // border-radius: 2px; + // } + // &::-webkit-scrollbar-thumb { + // background-color: #83888c; + // border-radius: 2px; + // &:hover { + // background-color: #93989c; + // } + // } + // } + // } + // &:hover { + // .vjs-menu { + // display: block; + // outline: 0; + // } + // } + // ul { + // li { + // list-style: none; + // margin: 0; + // padding: 0.3em 0 0.3em 0; + // line-height: 1.4em; + // font-size: 1.2em; + // text-align: center; + // outline: 0; + // &.vjs-selected { + // color: $PlayerColor; + // background-color: #151517; + // outline: 0; + // } + // &.vjs-menu-title { + // text-align: center; + // text-transform: uppercase; + // font-size: 1em; + // line-height: 2em; + // padding: 0; + // margin: 0 0 0.3em 0; + // font-weight: bold; + // cursor: default; + // } + // } + // } + //} + //.vjs-menu { + // display: none; + // position: absolute; + // bottom: 0; + // right: 1px; + // width: 20px; + // height: 30px; + // margin-bottom: 10px; + // outline: 0; + //} + //.vjs_smallersub_button { + // &.vjs-control { + // outline: 0; + // position: relative; + // float: right; + // cursor: pointer; + // margin-right: 14px; + // height: 13px; + // width: 14px; + // &:hover { + // transition: all .5s; + // -webkit-filter: brightness(0.70); + // &:before { + // text-shadow: none; + // } + // } + // &:before { + // height: 13px; + // width: 14px; + // font-size: 14px; + // line-height: 16px; + // content: "A"; + // color: #fff; + // } + // } + //} + //.vjs_biggersub_button { + // &.vjs-control { + // outline: 0; + // position: relative; + // float: right; + // cursor: pointer; + // margin-right: 14px; + // height: 13px; + // width: 14px; + // &:hover { + // transition: all .5s; + // -webkit-filter: brightness(0.70); + // &:before { + // text-shadow: none; + // } + // } + // &:before { + // height: 13px; + // width: 14px; + // font-size: 18px; + // line-height: 14px; + // content: "A"; + // color: #fff; + // } + // } + //} + //.vjs-subtitles-button { + // &:before { + // content: url('../images/icons/Player/Subtitles.png'); + // } + // &:hover { + // &:before { + // transition: all .5s; + // -webkit-filter: brightness(0.70); + // } + // } + //} + //.vjs-hidden { + // display: none; + //} } -.vjs-popcorn-skin .vjs-mute-control, -.vjs-popcorn-skin .vjs-volume-menu-button { - top: 25px; - cursor: pointer; - float: right; - height: 16px; - width: 22px; - margin-right: 11px; -} - -.vjs-popcorn-skin .vjs-mute-control:before, -.vjs-popcorn-skin .vjs-volume-menu-button:before { - position: relative; - content: url('../images/icons/Player/Sound3.png'); -} - -.vjs-popcorn-skin .vjs-mute-control.vjs-vol-2:before, -.vjs-popcorn-skin .vjs-volume-menu-button.vjs-vol-2:before { - content: url('../images/icons/Player/Sound2.png'); -} - -.vjs-popcorn-skin .vjs-mute-control.vjs-vol-1:before, -.vjs-popcorn-skin .vjs-volume-menu-button.vjs-vol-1:before { - content: url('../images/icons/Player/Sound1.png'); -} -.vjs-popcorn-skin .vjs-mute-control.vjs-vol-0:before, -.vjs-popcorn-skin .vjs-volume-menu-button.vjs-vol-0:before { - content: url('../images/icons/Player/Sound0.png'); -} - -.vjs-popcorn-skin .vjs-progress-holder .vjs-play-progress, -.vjs-popcorn-skin .vjs-progress-holder .vjs-load-progress { - position: absolute; - display: block; - height: 100%; - margin: 0; - padding: 0; - left: 0; - top: 0; - border-radius: 3px / 2px; - border-radius: 3px / 2px; - background-clip: padding; - background-clip: padding-box; - background-clip: padding-box; -} - -.vjs-current-time-display { - width: 50px; - text-align: right; -} - -.vjs-duration-display { - width: 50px; - text-align: left; -} - -.vjs-time-divider { - position: relative; - color: #fff; - font-family: "Open Sans", sans-serif; - font-size: 16px; - position: relative; - float: left; - margin-left: 4px; - margin-right: 3px; - top: 8px; -} - -.vjs-popcorn-skin:hover .vjs-big-play-button, -.vjs-popcorn-skin .vjs-big-play-button:focus { - outline: 0; - border-color: #fff; - background-color: #505050; - background-color: rgba(50, 50, 50, 0.75); - box-shadow: 0 0 3em #ffffff; - box-shadow: 0 0 3em #ffffff; - transition: all 0s; - transition: all 0s; -} - -.vjs-error { - .vjs-big-play-button { - display: none; - } - .vjs-error-display { - display: block; - position: absolute; - left: 0; - top: 75px; - width: 100%; - height: calc(100% - 115px); - } -} - -.vjs-error-display { - display: none; - div { - top: 40%; - color: #666; - position: absolute; - font-size: 1.6em; - text-align: center; - bottom: 1em; - right: 1em; - left: 1em; - width: 60%; - margin-left: 20%; - } -} - -.vjs-error-display a, -.vjs-error-display a:visited { - color: #F4A460; -} - -.vjs-loading-spinner { - display: none; - position: absolute; - top: 50%; - left: 50%; - font-size: 4em; - line-height: 1; - width: 1em; - height: 1em; - margin-left: -0.5em; - margin-top: -0.5em; - opacity: 0.75; - animation: spin 1.5s infinite linear; -} - -.video-js { - background-color: #000; - position: relative; - padding: 0; - font-size: 10px; - vertical-align: middle; - font-weight: normal; - font-style: normal; - font-family: Arial, sans-serif; - user-select: none; - user-select: none; - &.vjs-error { - .vjs-loading-spinner { - display: none !important; - } - .vjs-text-track { - display: none!important; - } - } - .vjs-tech { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - } - &.vjs-fullscreen { - position: fixed; - overflow: hidden; - z-index: 1000; - left: 0; - top: 0; - bottom: 0; - right: 0; - width: 100% !important; - height: 100% !important; - &.vjs-user-inactive { - cursor: none; - } - } - &:-webkit-full-screen { - width: 100% !important; - height: 100% !important; - } - &.vjs-using-native-controls { - .vjs-poster { - display: none; - } - } - .vjs-text-track-display { - text-align: center; - position: absolute; - bottom: 38px; - left: 1em; - right: 1em; - } - .vjs-text-track { - display: none; - text-align: center; - background-color: transparent; - text-shadow: 0px 0px 10px #000, -2px -2px 1px #000, 2px -2px 1px #000, -2px 2px 1px #000, 2px 2px 1px #000; - pointer-events: none; - } - .vjs-subtitles { - color: #ffffff; - } - .vjs-captions { - color: #ffcc66; - } -} - -.vjs-popcorn-skin .vjs-menu-button .vjs-menu .vjs-menu-content::-webkit-resizer, -.vjs-popcorn-skin .vjs-menu-button .vjs-menu .vjs-menu-content::-webkit-scrollbar-corner, -.vjs-popcorn-skin .vjs-menu-button .vjs-menu .vjs-menu-content::-webkit-scrollbar-button, -.vjs-popcorn-skin .vjs-menu-button .vjs-menu .vjs-menu-content::-webkit-scrollbar-track-piece { - display: none; -} - -.vjs-popcorn-skin .vjs-menu-button ul li:hover, -.vjs-popcorn-skin .vjs-menu-button ul li.vjs-selected:focus, -.vjs-popcorn-skin .vjs-menu-button ul li.vjs-selected:hover { - color: $PlayerColor; -} - -.vjs-popcorn-skin .vjs-captions-button:focus .vjs-control-content:before, -.vjs-popcorn-skin .vjs-captions-button:hover .vjs-control-content:before { - box-shadow: 0 0 1em #ffffff; - box-shadow: 0 0 1em #ffffff; -} - -body { - &.vjs-full-window { - padding: 0; - margin: 0; - height: 100%; - overflow-y: auto; - } -} - -.vjs-poster { - background-repeat: no-repeat; - background-position: 50% 50%; - background-size: contain; - cursor: pointer; - height: 100%; - margin: 0; - padding: 0; - position: relative; - width: 100%; - img { - display: block; - margin: 0 auto; - max-height: 100%; - padding: 0; - width: 100%; - } -} - -.vjs-tt-cue { - display: block; - padding: 5px 10px; -} - -.vjs-lock-showing { - display: block !important; - opacity: 1; - visibility: visible; -} - -.vjs-poster, -.vjs-loading-spinner, -.vjs-big-play-button, -.vjs-text-track-display, -.vjs-youtube .iframeblocker { - pointer-events: none !important; -} - -#vjs-tip { - visibility: hidden; - display: block; - padding: 5px; - font-size: 11px; - position: absolute; - z-index: 100000; - pointer-events: none; -} - -#vjs-tip-arrow { - background: url(unquote('data:image/gif;base64,R0lGODlhCQAJAIABAAAAAAAAACH5BAEAAAEALAAAAAAJAAkAAAIRjAOnwIrcDJxvwkplPtchVQAAOw==')) no-repeat top left; - bottom: 0; - left: 50%; - margin-left: -4px; - background-position: bottom left; - position: absolute; - width: 9px; - height: 5px; - opacity: 0; -} - -#vjs-tip-inner { - border-radius: 3px; - border-radius: 3px; - padding: 5px 8px 4px; - background-color: rgba(0,0,0,0); - color: #fff; - max-width: 200px; - text-align: center; - font-size: 150%; - font-weight: 500; -} + //.vjs-popcorn-skin { + // &.vjs-has-started { + // .vjs-control-bar, .vjs-control-window { + // display: block; + // visibility: visible; + // transition: visibility 0.1s, opacity 0.1s; + // transition: visibility 0.1s, opacity 0.1s; + // } + // } + //} + +// +//.vjs-popcorn-skin .vjs-control:focus:before, +//.vjs-popcorn-skin .vjs-control:hover:before { +// text-shadow: 0em 0em 1em #ffffff; +//} +// +//.vjs-popcorn-skin .vjs-mute-control, +//.vjs-popcorn-skin .vjs-volume-menu-button { +// top: 25px; +// cursor: pointer; +// float: right; +// height: 16px; +// width: 22px; +// margin-right: 11px; +//} +// +//.vjs-popcorn-skin .vjs-mute-control:before, +//.vjs-popcorn-skin .vjs-volume-menu-button:before { +// position: relative; +// content: url('../images/icons/Player/Sound3.png'); +//} +// +//.vjs-popcorn-skin .vjs-mute-control.vjs-vol-2:before, +//.vjs-popcorn-skin .vjs-volume-menu-button.vjs-vol-2:before { +// content: url('../images/icons/Player/Sound2.png'); +//} +// +//.vjs-popcorn-skin .vjs-mute-control.vjs-vol-1:before, +//.vjs-popcorn-skin .vjs-volume-menu-button.vjs-vol-1:before { +// content: url('../images/icons/Player/Sound1.png'); +//} +// +//.vjs-popcorn-skin .vjs-mute-control.vjs-vol-0:before, +//.vjs-popcorn-skin .vjs-volume-menu-button.vjs-vol-0:before { +// content: url('../images/icons/Player/Sound0.png'); +//} +// +//.vjs-popcorn-skin .vjs-progress-holder .vjs-play-progress, +//.vjs-popcorn-skin .vjs-progress-holder .vjs-load-progress { +// position: absolute; +// display: block; +// height: 100%; +// margin: 0; +// padding: 0; +// left: 0; +// top: 0; +// border-radius: 3px / 2px; +// border-radius: 3px / 2px; +// background-clip: padding; +// background-clip: padding-box; +// background-clip: padding-box; +//} +// +//.vjs-current-time-display { +// width: 50px; +// text-align: right; +//} +// +//.vjs-duration-display { +// width: 50px; +// text-align: left; +//} +// +//.vjs-time-divider { +// position: relative; +// color: #fff; +// font-family: "Open Sans", sans-serif; +// font-size: 16px; +// position: relative; +// float: left; +// margin-left: 4px; +// margin-right: 3px; +// top: 8px; +//} +// +//.vjs-popcorn-skin:hover .vjs-big-play-button, +//.vjs-popcorn-skin .vjs-big-play-button:focus { +// outline: 0; +// border-color: #fff; +// background-color: #505050; +// background-color: rgba(50, 50, 50, 0.75); +// box-shadow: 0 0 3em #ffffff; +// box-shadow: 0 0 3em #ffffff; +// transition: all 0s; +// transition: all 0s; +//} +// +//.vjs-error { +// .vjs-big-play-button { +// display: none; +// } +// .vjs-error-display { +// display: block; +// position: absolute; +// left: 0; +// top: 75px; +// width: 100%; +// height: calc(100% - 115px); +// } +//} +// +//.vjs-error-display { +// display: none; +// div { +// top: 40%; +// color: #666; +// position: absolute; +// font-size: 1.6em; +// text-align: center; +// bottom: 1em; +// right: 1em; +// left: 1em; +// width: 60%; +// margin-left: 20%; +// } +//} +// +//.vjs-error-display a, +//.vjs-error-display a:visited { +// color: #F4A460; +//} +// +//.vjs-loading-spinner { +// display: none; +// position: absolute; +// top: 50%; +// left: 50%; +// font-size: 4em; +// line-height: 1; +// width: 1em; +// height: 1em; +// margin-left: -0.5em; +// margin-top: -0.5em; +// opacity: 0.75; +// animation: spin 1.5s infinite linear; +//} +// +//.video-js { +// background-color: #000; +// position: relative; +// padding: 0; +// font-size: 10px; +// vertical-align: middle; +// font-weight: normal; +// font-style: normal; +// font-family: Arial, sans-serif; +// user-select: none; +// user-select: none; +// &.vjs-error { +// .vjs-loading-spinner { +// display: none !important; +// } +// .vjs-text-track { +// display: none!important; +// } +// } +// .vjs-tech { +// position: absolute; +// top: 0; +// left: 0; +// width: 100%; +// height: 100%; +// } +// &.vjs-fullscreen { +// position: fixed; +// overflow: hidden; +// z-index: 1000; +// left: 0; +// top: 0; +// bottom: 0; +// right: 0; +// width: 100% !important; +// height: 100% !important; +// &.vjs-user-inactive { +// cursor: none; +// } +// } +// &:-webkit-full-screen { +// width: 100% !important; +// height: 100% !important; +// } +// &.vjs-using-native-controls { +// .vjs-poster { +// display: none; +// } +// } +// .vjs-text-track-display { +// text-align: center; +// position: absolute; +// bottom: 38px; +// left: 1em; +// right: 1em; +// } +// .vjs-text-track { +// display: none; +// text-align: center; +// background-color: transparent; +// text-shadow: 0px 0px 10px #000, -2px -2px 1px #000, 2px -2px 1px #000, -2px 2px 1px #000, 2px 2px 1px #000; +// pointer-events: none; +// } +// .vjs-subtitles { +// color: #ffffff; +// } +// .vjs-captions { +// color: #ffcc66; +// } +//} +// +//.vjs-popcorn-skin .vjs-menu-button .vjs-menu .vjs-menu-content::-webkit-resizer, +//.vjs-popcorn-skin .vjs-menu-button .vjs-menu .vjs-menu-content::-webkit-scrollbar-corner, +//.vjs-popcorn-skin .vjs-menu-button .vjs-menu .vjs-menu-content::-webkit-scrollbar-button, +//.vjs-popcorn-skin .vjs-menu-button .vjs-menu .vjs-menu-content::-webkit-scrollbar-track-piece { +// display: none; +//} +// +//.vjs-popcorn-skin .vjs-menu-button ul li:hover, +//.vjs-popcorn-skin .vjs-menu-button ul li.vjs-selected:focus, +//.vjs-popcorn-skin .vjs-menu-button ul li.vjs-selected:hover { +// color: $PlayerColor; +//} +// +//.vjs-popcorn-skin .vjs-captions-button:focus .vjs-control-content:before, +//.vjs-popcorn-skin .vjs-captions-button:hover .vjs-control-content:before { +// box-shadow: 0 0 1em #ffffff; +// box-shadow: 0 0 1em #ffffff; +//} +// +//body { +// &.vjs-full-window { +// padding: 0; +// margin: 0; +// height: 100%; +// overflow-y: auto; +// } +//} +// +//.vjs-poster { +// background-repeat: no-repeat; +// background-position: 50% 50%; +// background-size: contain; +// cursor: pointer; +// height: 100%; +// margin: 0; +// padding: 0; +// position: relative; +// width: 100%; +// img { +// display: block; +// margin: 0 auto; +// max-height: 100%; +// padding: 0; +// width: 100%; +// } +//} +// +//.vjs-tt-cue { +// display: block; +// padding: 5px 10px; +//} +// +//.vjs-lock-showing { +// display: block !important; +// opacity: 1; +// visibility: visible; +//} +// +//.vjs-poster, +//.vjs-loading-spinner, +//.vjs-big-play-button, +//.vjs-text-track-display, +//.vjs-youtube .iframeblocker { +// pointer-events: none !important; +//} +// +//#vjs-tip { +// visibility: hidden; +// display: block; +// padding: 5px; +// font-size: 11px; +// position: absolute; +// z-index: 100000; +// pointer-events: none; +//} +// +//#vjs-tip-arrow { +// background: url(unquote('data:image/gif;base64,R0lGODlhCQAJAIABAAAAAAAAACH5BAEAAAEALAAAAAAJAAkAAAIRjAOnwIrcDJxvwkplPtchVQAAOw==')) no-repeat top left; +// bottom: 0; +// left: 50%; +// margin-left: -4px; +// background-position: bottom left; +// position: absolute; +// width: 9px; +// height: 5px; +// opacity: 0; +//} +// +//#vjs-tip-inner { +// border-radius: 3px; +// border-radius: 3px; +// padding: 5px 8px 4px; +// background-color: rgba(0,0,0,0); +// color: #fff; +// max-width: 200px; +// text-align: center; +// font-size: 150%; +// font-weight: 500; +//} diff --git a/src/app/vendor/videojshooks.js b/src/app/vendor/videojshooks.js index f11de80c72..9120f14579 100644 --- a/src/app/vendor/videojshooks.js +++ b/src/app/vendor/videojshooks.js @@ -1,3 +1,4 @@ +videojs.options.resizeManager = false; videojs.options['children'] = { 'mediaLoader': {}, 'posterImage': {}, @@ -5,8 +6,14 @@ videojs.options['children'] = { 'loadingSpinner': {}, //'bigPlayButton': {}, 'controlBar': { - currentTimeDisplay : true, - durationDisplay : true, + playToggle: { + replay: false + }, + currentTimeDisplay: true, + durationDisplay: true, + timeDivider: true, + pictureInPictureToggle: false, + remainingTimeDisplay: false, }, 'errorDisplay': {} }; diff --git a/src/app/vendor/videojsplugins.js b/src/app/vendor/videojsplugins.js index 8c98b9fd27..7a7930c4df 100644 --- a/src/app/vendor/videojsplugins.js +++ b/src/app/vendor/videojsplugins.js @@ -158,49 +158,49 @@ // // }); -/*! videojs-progressTips - v0.1.0 - 2013-09-16 - * https://github.com/mickey/videojs-progressTips - * Copyright (c) 2013 Michael Bensoussan; Licensed MIT */ - -videojs.registerPlugin('progressTips', function (options) { - var init; - init = function () { - var player; - /*if (this.techName !== "Html5") { - return; - }*/ - player = this; - $('.vjs-progress-control').prepend($('
')); - $('#vjs-tip').css('top', '-25px'); - $('.vjs-progress-control').on('mousemove', function (event) { - var time, hours, minutes, seconds, seekBar, timeInSeconds; - seekBar = player.controlBar.progressControl.seekBar; - timeInSeconds = seekBar.calculateDistance(event) * seekBar.player_.duration(); - if (timeInSeconds === seekBar.player_.duration()) { - timeInSeconds = timeInSeconds - 0.1; - } - hours = Math.floor(timeInSeconds / 60 / 60); - minutes = Math.floor(timeInSeconds / 60); - seconds = Math.floor(timeInSeconds - minutes * 60); - if (seconds < 10) { - seconds = '0' + seconds; - } - if (hours > 0) { - minutes = minutes % 60; - if (minutes < 10) { - minutes = '0' + minutes; - } - time = '' + hours + ':' + minutes + ':' + seconds; - } else { - time = '' + minutes + ':' + seconds; - } - $('#vjs-tip-inner').html(time); - $('#vjs-tip').css('left', '' + (event.pageX - $(this).offset().left - ($('#vjs-tip').outerWidth() / 2)) + 'px').css('visibility', 'visible'); - return; - }); - $('.vjs-progress-control, .vjs-play-control').on('mouseout', function () { - $('#vjs-tip').css('visibility', 'hidden'); - }); - }; - this.on('loadedmetadata', init); -}); +// /*! videojs-progressTips - v0.1.0 - 2013-09-16 +// * https://github.com/mickey/videojs-progressTips +// * Copyright (c) 2013 Michael Bensoussan; Licensed MIT */ +// +// videojs.registerPlugin('progressTips', function (options) { +// var init; +// init = function () { +// var player; +// /*if (this.techName !== "Html5") { +// return; +// }*/ +// player = this; +// $('.vjs-progress-control').prepend($('
')); +// $('#vjs-tip').css('top', '-25px'); +// $('.vjs-progress-control').on('mousemove', function (event) { +// var time, hours, minutes, seconds, seekBar, timeInSeconds; +// seekBar = player.controlBar.progressControl.seekBar; +// timeInSeconds = seekBar.calculateDistance(event) * seekBar.player_.duration(); +// if (timeInSeconds === seekBar.player_.duration()) { +// timeInSeconds = timeInSeconds - 0.1; +// } +// hours = Math.floor(timeInSeconds / 60 / 60); +// minutes = Math.floor(timeInSeconds / 60); +// seconds = Math.floor(timeInSeconds - minutes * 60); +// if (seconds < 10) { +// seconds = '0' + seconds; +// } +// if (hours > 0) { +// minutes = minutes % 60; +// if (minutes < 10) { +// minutes = '0' + minutes; +// } +// time = '' + hours + ':' + minutes + ':' + seconds; +// } else { +// time = '' + minutes + ':' + seconds; +// } +// $('#vjs-tip-inner').html(time); +// $('#vjs-tip').css('left', '' + (event.pageX - $(this).offset().left - ($('#vjs-tip').outerWidth() / 2)) + 'px').css('visibility', 'visible'); +// return; +// }); +// $('.vjs-progress-control, .vjs-play-control').on('mouseout', function () { +// $('#vjs-tip').css('visibility', 'hidden'); +// }); +// }; +// this.on('loadedmetadata', init); +// }); From 3db988bb73e56cd2e905debb795f66d089429e2f Mon Sep 17 00:00:00 2001 From: Ivan Borzenkov Date: Sun, 15 Aug 2021 16:44:41 +0300 Subject: [PATCH 07/12] added in core --- src/app/lib/views/player/player.js | 1 - src/app/vendor/videojshooks.js | 79 ------------------------------ src/app/vendor/videojsplugins.js | 47 ------------------ 3 files changed, 127 deletions(-) diff --git a/src/app/lib/views/player/player.js b/src/app/lib/views/player/player.js index caa6cf3ca9..564905892e 100644 --- a/src/app/lib/views/player/player.js +++ b/src/app/lib/views/player/player.js @@ -509,7 +509,6 @@ //biggerSubtitle: {}, //smallerSubtitle: {}, //customSubtitles: {}, - //progressTips: {} } }); this.video.ready(function () { diff --git a/src/app/vendor/videojshooks.js b/src/app/vendor/videojshooks.js index 9120f14579..102358ab45 100644 --- a/src/app/vendor/videojshooks.js +++ b/src/app/vendor/videojshooks.js @@ -18,64 +18,6 @@ videojs.options['children'] = { 'errorDisplay': {} }; -// -// vjs.Player.prototype.debugMouse_ = false; -// vjs.Player.prototype.reportUserActivity = function (event) { -// /** DEBUG MOUSE CTRL+D **/ -// if (this.debugMouse_) { -// console.log('Event fired at: ' + vjs.formatTime(this.player_.currentTime(), this.player_.duration())); -// console.log(event); -// } -// if (event !== undefined && event.type === 'mousemove') { -// if (event.webkitMovementX === 0 && event.webkitMovementY === 0) { -// return; -// } -// } -// this.userActivity_ = true; -// }; -// -// vjs.Player.prototype.listenForUserActivity = function () { -// var onActivity, onMouseDown, mouseInProgress, onMouseUp, -// activityCheck, inactivityTimeout; -// -// onActivity = vjs.bind(this, this.reportUserActivity); -// -// onMouseDown = function (e) { -// onActivity(e); -// clearInterval(mouseInProgress); -// mouseInProgress = setInterval(onActivity, 250); -// }; -// -// onMouseUp = function (e) { -// onActivity(e); -// clearInterval(mouseInProgress); -// }; -// -// this.on('mousedown', onMouseDown); -// this.on('mousemove', onActivity); -// this.on('mouseup', onMouseUp); -// this.on('keydown', onActivity); -// this.on('keyup', onActivity); -// -// activityCheck = setInterval(vjs.bind(this, function () { -// if (this.userActivity_) { -// this.userActivity_ = false; -// this.userActive(true); -// clearTimeout(inactivityTimeout); -// inactivityTimeout = setTimeout(vjs.bind(this, function () { -// if (!this.userActivity_) { -// this.userActive(false); -// } -// }), 2000); -// } -// }), 250); -// -// this.on('dispose', function () { -// clearInterval(activityCheck); -// clearTimeout(inactivityTimeout); -// }); -// }; -// // vjs.Player.prototype.onFullscreenChange = function (e) { // e.stopPropagation(); // if (this.isFullscreen()) { @@ -431,27 +373,6 @@ videojs.options['children'] = { // this.trigger('volumechange'); // }; // -// /** -// * The custom progressbar we create. Updated in player.js -// * -// * @constructor -// */ -// vjs.LoadProgressBar = vjs.Component.extend({ -// init: function (player, options) { -// vjs.Component.call(this, player, options); -// this.on(player, 'progress', this.update); -// } -// }); -// vjs.LoadProgressBar.prototype.createEl = function () { -// return vjs.Component.prototype.createEl.call(this, 'div', { -// className: 'vjs-load-progress', -// innerHTML: '' + this.localize('Loaded') + ': 0%' -// }); -// }; -// vjs.LoadProgressBar.prototype.update = function () { -// return; -// }; -// // vjs.Player.prototype.volume = function (percentAsDecimal) { // var vol; // diff --git a/src/app/vendor/videojsplugins.js b/src/app/vendor/videojsplugins.js index 7a7930c4df..dbda4ee74a 100644 --- a/src/app/vendor/videojsplugins.js +++ b/src/app/vendor/videojsplugins.js @@ -157,50 +157,3 @@ // subtitlesButton.show(); // Always show subtitles button // // }); - -// /*! videojs-progressTips - v0.1.0 - 2013-09-16 -// * https://github.com/mickey/videojs-progressTips -// * Copyright (c) 2013 Michael Bensoussan; Licensed MIT */ -// -// videojs.registerPlugin('progressTips', function (options) { -// var init; -// init = function () { -// var player; -// /*if (this.techName !== "Html5") { -// return; -// }*/ -// player = this; -// $('.vjs-progress-control').prepend($('
')); -// $('#vjs-tip').css('top', '-25px'); -// $('.vjs-progress-control').on('mousemove', function (event) { -// var time, hours, minutes, seconds, seekBar, timeInSeconds; -// seekBar = player.controlBar.progressControl.seekBar; -// timeInSeconds = seekBar.calculateDistance(event) * seekBar.player_.duration(); -// if (timeInSeconds === seekBar.player_.duration()) { -// timeInSeconds = timeInSeconds - 0.1; -// } -// hours = Math.floor(timeInSeconds / 60 / 60); -// minutes = Math.floor(timeInSeconds / 60); -// seconds = Math.floor(timeInSeconds - minutes * 60); -// if (seconds < 10) { -// seconds = '0' + seconds; -// } -// if (hours > 0) { -// minutes = minutes % 60; -// if (minutes < 10) { -// minutes = '0' + minutes; -// } -// time = '' + hours + ':' + minutes + ':' + seconds; -// } else { -// time = '' + minutes + ':' + seconds; -// } -// $('#vjs-tip-inner').html(time); -// $('#vjs-tip').css('left', '' + (event.pageX - $(this).offset().left - ($('#vjs-tip').outerWidth() / 2)) + 'px').css('visibility', 'visible'); -// return; -// }); -// $('.vjs-progress-control, .vjs-play-control').on('mouseout', function () { -// $('#vjs-tip').css('visibility', 'hidden'); -// }); -// }; -// this.on('loadedmetadata', init); -// }); From 4722ac0d20f1be600c4f0b65669ab0e322836cb8 Mon Sep 17 00:00:00 2001 From: Ivan Borzenkov Date: Sun, 15 Aug 2021 20:43:28 +0300 Subject: [PATCH 08/12] subtitles - try to fix --- src/app/lib/views/player/player.js | 3 +- src/app/styl/views/player.styl | 16 ----- src/app/styl/views/videojs.styl | 11 ---- src/app/vendor/videojshooks.js | 11 ++++ src/app/vendor/videojsplugins.js | 100 +++++++++++++++++++++++++++-- 5 files changed, 109 insertions(+), 32 deletions(-) diff --git a/src/app/lib/views/player/player.js b/src/app/lib/views/player/player.js index 564905892e..5425c512b2 100644 --- a/src/app/lib/views/player/player.js +++ b/src/app/lib/views/player/player.js @@ -503,12 +503,13 @@ } else { this.video = videojs('video_player', { nativeControlsForTouch: false, + nativeTextTracks: false, trackTimeOffset: 0, //inactivityTimeout: 2000, plugins: { //biggerSubtitle: {}, //smallerSubtitle: {}, - //customSubtitles: {}, + customSubtitles: {}, } }); this.video.ready(function () { diff --git a/src/app/styl/views/player.styl b/src/app/styl/views/player.styl index 5e1b05b6d8..bad12aa205 100644 --- a/src/app/styl/views/player.styl +++ b/src/app/styl/views/player.styl @@ -459,22 +459,6 @@ font-size: 12px } -.vjs-subtitles-button { - top: 24px -} - -.vjs_smallersub_button { - &.vjs-control { - top: 24px - } -} - -.vjs_biggersub_button { - &.vjs-control { - top: 24px - } -} - .player-header-background { position: absolute background: linear-gradient(rgba(0,0,0,0.7), transparent 95%, transparent) !important diff --git a/src/app/styl/views/videojs.styl b/src/app/styl/views/videojs.styl index c9cf4d736e..96fe03bc5d 100644 --- a/src/app/styl/views/videojs.styl +++ b/src/app/styl/views/videojs.styl @@ -554,17 +554,6 @@ // } // } //} - //.vjs-subtitles-button { - // &:before { - // content: url('../images/icons/Player/Subtitles.png'); - // } - // &:hover { - // &:before { - // transition: all .5s; - // -webkit-filter: brightness(0.70); - // } - // } - //} //.vjs-hidden { // display: none; //} diff --git a/src/app/vendor/videojshooks.js b/src/app/vendor/videojshooks.js index 102358ab45..b2ebcc57c2 100644 --- a/src/app/vendor/videojshooks.js +++ b/src/app/vendor/videojshooks.js @@ -17,6 +17,17 @@ videojs.options['children'] = { }, 'errorDisplay': {} }; +videojs.getComponent('ControlBar').prototype.options_ = { + children: [ + 'playToggle', + 'volumePanel', + 'currentTimeDisplay', + 'timeDivider', + 'durationDisplay', + 'progressControl', + 'remainingTimeDisplay', + 'customControlSpacer', 'subtitlesButton', 'audioTrackButton', 'fullscreenToggle'] +}; // vjs.Player.prototype.onFullscreenChange = function (e) { // e.stopPropagation(); diff --git a/src/app/vendor/videojsplugins.js b/src/app/vendor/videojsplugins.js index dbda4ee74a..fb8a923fb8 100644 --- a/src/app/vendor/videojsplugins.js +++ b/src/app/vendor/videojsplugins.js @@ -1,6 +1,10 @@ -// // VideoJS Plugins -// -// var Button = videojs.getComponent('Button'); +// VideoJS Plugins + +var Button = videojs.getComponent('Button'); +var MenuButton = videojs.getComponent('MenuButton'); +var SubsCapsMenuItem = videojs.getComponent('SubsCapsMenuItem'); +var TextTrackMenuItem = videojs.getComponent('TextTrackMenuItem'); + // var BiggerSubtitleButton = videojs.extend(Button, { // /** @constructor */ // constructor: function() { @@ -71,8 +75,96 @@ // }); // +/** + * Button for subtitles menu + * + * @extends MenuButton + * @class SubtitlesButton + */ +class SubtitlesButton extends MenuButton { + /** + * Constructor for class + * + * @param {Player|Object} player The player + * @param {Object=} options Button options + * @param {string} options.direction back or forward + * @param {Int} options.seconds number of seconds to seek + */ + constructor(player, options) { + super(player, options); + if (this.options_.direction === 'forward') { + this.controlText(this.localize('Seek forward {{seconds}} seconds') + .replace('{{seconds}}', this.options_.seconds)); + } else if (this.options_.direction === 'back') { + this.controlText(this.localize('Seek back {{seconds}} seconds') + .replace('{{seconds}}', this.options_.seconds)); + } + } + + /** + * Return button class names which include the seek amount. + * + * @return {string} css cass string + */ + buildCSSClass() { + return `vjs-subtitles-button ${super.buildCSSClass()}`; + } + + /** + * Seek with the button's configured offset + */ + handleClick() { + console.log('click!'); + // const now = this.player_.currentTime(); + // + // if (this.options_.direction === 'forward') { + // this.player_.currentTime(now + this.options_.seconds); + // } else if (this.options_.direction === 'back') { + // this.player_.currentTime(now - this.options_.seconds); + // } + } +} + +class CustomTrackMenuItem extends TextTrackMenuItem { + constructor(player, options) { + options = options || {}; + // fake 'empty' track + options['track'] = { + kind: 'subtitles', + player: player, + label: i18n.__('Custom...'), + dflt: false, + mode: false, + }; + super(player, options); + } +} + +videojs.registerComponent('сustomTrackMenuItem', CustomTrackMenuItem); +videojs.registerComponent('customSubtitlesButton', SubtitlesButton); + +// Register the plugin with video.js. +videojs.registerPlugin('customSubtitles', function() { + this.ready(() => { + // Find subtitlesButton + var subtitlesButton; + this.controlBar.children().forEach(function (el) { + if (el.name() === 'SubtitlesButton') { + subtitlesButton = el; + } + }); + + console.log(subtitlesButton); + + subtitlesButton.menu.addItem(new CustomTrackMenuItem(this)); + subtitlesButton.show(); // Always show subtitles button + + this.controlBar.customSubtitlesButton = this.controlBar.addChild('customSubtitlesButton', {}, this.controlBar.children_.length - 1); + }); +}); + // // Custom Subtitles Button/Menu -// videojs.plugin('customSubtitles', function () { +// videojs.registerPlugin('customSubtitles', function () { // // // Find subtitlesButton // var subtitlesButton; From 68cbe5be3e82de4c0bcf65a588e141842bf54c97 Mon Sep 17 00:00:00 2001 From: Ivan Borzenkov Date: Wed, 18 Aug 2021 23:51:48 +0300 Subject: [PATCH 09/12] custom subtitles - vtt --- src/app/lib/views/player/player.js | 20 +--- src/app/styl/views/videojs.styl | 9 ++ src/app/vendor/videojshooks.js | 6 +- src/app/vendor/videojsplugins.js | 160 +++++++++++++++++++++-------- 4 files changed, 135 insertions(+), 60 deletions(-) diff --git a/src/app/lib/views/player/player.js b/src/app/lib/views/player/player.js index 5425c512b2..bcdc538cc3 100644 --- a/src/app/lib/views/player/player.js +++ b/src/app/lib/views/player/player.js @@ -509,7 +509,7 @@ plugins: { //biggerSubtitle: {}, //smallerSubtitle: {}, - customSubtitles: {}, + //customSubtitles: {}, } }); this.video.ready(function () { @@ -520,24 +520,6 @@ this.player = this.video; App.PlayerView = this; - /* The following is a hack to make VideoJS listen to - * mouseup instead of mousedown for pause/play on the - * video element. Stops video pausing/playing when - * dragged. TODO: #fixit! - */ - // this.player.tech.off('mousedown'); - // this.player.tech.on('mouseup', function (event) { - // if (event.target.origEvent) { - // if (!event.target.origEvent.originalEvent.defaultPrevented) { - // that.player.tech.onClick(event); - // } - // // clean up after ourselves - // delete event.target.origEvent; - // } else { - // that.player.tech.onClick(event); - // } - // }); - // Force custom controls this.player.usingNativeControls(false); diff --git a/src/app/styl/views/videojs.styl b/src/app/styl/views/videojs.styl index 96fe03bc5d..9a12bd940b 100644 --- a/src/app/styl/views/videojs.styl +++ b/src/app/styl/views/videojs.styl @@ -312,6 +312,15 @@ .vjs-fullscreen-control { order: 2; } + .vjs-menu-button-popup { + .vjs-menu { + width: 15em; + left: -6em; + .vjs-menu-content { + overflow: hidden; + } + } + } //.vjs-time-control { // display: block; diff --git a/src/app/vendor/videojshooks.js b/src/app/vendor/videojshooks.js index b2ebcc57c2..fe32a349bf 100644 --- a/src/app/vendor/videojshooks.js +++ b/src/app/vendor/videojshooks.js @@ -26,7 +26,11 @@ videojs.getComponent('ControlBar').prototype.options_ = { 'durationDisplay', 'progressControl', 'remainingTimeDisplay', - 'customControlSpacer', 'subtitlesButton', 'audioTrackButton', 'fullscreenToggle'] + 'customControlSpacer', + 'customSubtitlesButton', + 'audioTrackButton', + 'fullscreenToggle' + ] }; // vjs.Player.prototype.onFullscreenChange = function (e) { diff --git a/src/app/vendor/videojsplugins.js b/src/app/vendor/videojsplugins.js index fb8a923fb8..65a353ab59 100644 --- a/src/app/vendor/videojsplugins.js +++ b/src/app/vendor/videojsplugins.js @@ -2,8 +2,10 @@ var Button = videojs.getComponent('Button'); var MenuButton = videojs.getComponent('MenuButton'); -var SubsCapsMenuItem = videojs.getComponent('SubsCapsMenuItem'); -var TextTrackMenuItem = videojs.getComponent('TextTrackMenuItem'); +var SubtitlesButton = videojs.getComponent('SubtitlesButton'); +var MenuItem = videojs.getComponent('MenuItem'); +var srt2vtt = require('srt-to-vtt'); +var fs = require('fs'); // var BiggerSubtitleButton = videojs.extend(Button, { // /** @constructor */ @@ -75,13 +77,125 @@ var TextTrackMenuItem = videojs.getComponent('TextTrackMenuItem'); // }); // +class CustomTrackMenuItem extends MenuItem { + constructor(player, options) { + options = options || {}; + options.label = i18n.__('Custom...'); + super(player, options); + + // let that = this; + // this.fileInput_ = $(''); + // $(this.el()).append(this.fileInput_); + // this.fileInput_.on('change', function () { + // that.player_.play(); + // if (this.value === '') { + // return; + // } + // that.loadSubtitle(this.value); + // this.value = null; //reset + // }); + } + + /** + * Seek with the button's configured offset + */ + handleClick() { + console.log('click!'); + this.player_.pause(); + // this.fileInput_.trigger('click'); // redirect to fileInput click + var input = document.createElement('input'); + input.type = 'file'; + input.accept = '.vtt, .srt, .ssa, .ass, .txt'; + + input.onchange = e => { + var file = e.target.files[0]; + console.log(file); + this.loadSubtitle(file); + }; + + input.click(); + // const now = this.player_.currentTime(); + // + // if (this.options_.direction === 'forward') { + // this.player_.currentTime(now + this.options_.seconds); + // } else if (this.options_.direction === 'back') { + // this.player_.currentTime(now - this.options_.seconds); + // } + } + + loadSubtitle(file) { + + //clean tracks + var tracks = this.player_.textTracks() || []; + for (var i = 0; i < tracks.length; ++i) { + if (tracks[i].id_.indexOf('vjs_subtitles_00') !== -1) { + $(tracks[i].el()).remove(); + tracks.splice(i, 1); + break; + } + } + + window['x'] = file; + + file.text().then((x) => fs.writeFileSync(App.settings.tmpLocation + '/temp.srt', x)).then((stream) => { + fs.createReadStream(App.settings.tmpLocation + '/temp.srt') + .pipe(srt2vtt()) + .pipe(fs.createWriteStream(App.settings.tmpLocation + '/temp.vtt')); + }).then(() => { + let file = new Blob(new Uint8Array(fs.readFileSync(App.settings.tmpLocation + '/temp.vtt')), {type: 'text/vtt'}); + console.log(file); + const track = this.player_.addRemoteTextTrack({ + kind: 'subtitles', + language: '01', + label: 'str2vtt', + mode: 'showing', + src: URL.createObjectURL(file) + }, false); + console.log(track); + }); + //return; + + //file.stream().pipe(srt2vtt()).toBlob() + + const track = this.player_.addRemoteTextTrack({ + kind: 'subtitles', + language: '00', + label: 'original', + mode: 'showing', + src: URL.createObjectURL(file) + }, false); + // const track = this.player_.addTextTrack('subtitles', 'Loaded', App.Settings.language, { + // src: filePath + // }); + console.log(track); + //App.vent.trigger('customSubtitles:added', filePath); + //vjs.TextTrackMenuItem.prototype.onClick.call(this); // redirect to TextTrackMenuItem.onClick + } + +} +videojs.registerComponent('сustomTrackMenuItem', CustomTrackMenuItem); + +class CustomSubtitlesButton extends SubtitlesButton +{ + constructor(player, options, ready) { + super(player, options, ready); + } + + createItems(items, TrackMenuItem) { + items = super.createItems(items, TrackMenuItem); + items.push(new CustomTrackMenuItem(this.player())); + return items; + } +} +videojs.registerComponent('customSubtitlesButton', CustomSubtitlesButton); + /** * Button for subtitles menu * * @extends MenuButton * @class SubtitlesButton */ -class SubtitlesButton extends MenuButton { +class CustomButton extends MenuButton { /** * Constructor for class * @@ -115,6 +229,8 @@ class SubtitlesButton extends MenuButton { */ handleClick() { console.log('click!'); + + // const now = this.player_.currentTime(); // // if (this.options_.direction === 'forward') { @@ -125,43 +241,7 @@ class SubtitlesButton extends MenuButton { } } -class CustomTrackMenuItem extends TextTrackMenuItem { - constructor(player, options) { - options = options || {}; - // fake 'empty' track - options['track'] = { - kind: 'subtitles', - player: player, - label: i18n.__('Custom...'), - dflt: false, - mode: false, - }; - super(player, options); - } -} - -videojs.registerComponent('сustomTrackMenuItem', CustomTrackMenuItem); -videojs.registerComponent('customSubtitlesButton', SubtitlesButton); - -// Register the plugin with video.js. -videojs.registerPlugin('customSubtitles', function() { - this.ready(() => { - // Find subtitlesButton - var subtitlesButton; - this.controlBar.children().forEach(function (el) { - if (el.name() === 'SubtitlesButton') { - subtitlesButton = el; - } - }); - - console.log(subtitlesButton); - - subtitlesButton.menu.addItem(new CustomTrackMenuItem(this)); - subtitlesButton.show(); // Always show subtitles button - - this.controlBar.customSubtitlesButton = this.controlBar.addChild('customSubtitlesButton', {}, this.controlBar.children_.length - 1); - }); -}); +videojs.registerComponent('customButton', CustomButton); // // Custom Subtitles Button/Menu // videojs.registerPlugin('customSubtitles', function () { From 6aacc1595c3b6773ddace59d356653298f864a06 Mon Sep 17 00:00:00 2001 From: Ivan Borzenkov Date: Sat, 21 Aug 2021 10:50:44 +0300 Subject: [PATCH 10/12] add str2vtt convert for custom subs --- src/app/vendor/videojsplugins.js | 243 ++++++++++++------------------- 1 file changed, 94 insertions(+), 149 deletions(-) diff --git a/src/app/vendor/videojsplugins.js b/src/app/vendor/videojsplugins.js index 65a353ab59..26cdde6e5e 100644 --- a/src/app/vendor/videojsplugins.js +++ b/src/app/vendor/videojsplugins.js @@ -4,8 +4,6 @@ var Button = videojs.getComponent('Button'); var MenuButton = videojs.getComponent('MenuButton'); var SubtitlesButton = videojs.getComponent('SubtitlesButton'); var MenuItem = videojs.getComponent('MenuItem'); -var srt2vtt = require('srt-to-vtt'); -var fs = require('fs'); // var BiggerSubtitleButton = videojs.extend(Button, { // /** @constructor */ @@ -82,94 +80,128 @@ class CustomTrackMenuItem extends MenuItem { options = options || {}; options.label = i18n.__('Custom...'); super(player, options); - - // let that = this; - // this.fileInput_ = $(''); - // $(this.el()).append(this.fileInput_); - // this.fileInput_.on('change', function () { - // that.player_.play(); - // if (this.value === '') { - // return; - // } - // that.loadSubtitle(this.value); - // this.value = null; //reset - // }); } /** * Seek with the button's configured offset */ handleClick() { - console.log('click!'); this.player_.pause(); - // this.fileInput_.trigger('click'); // redirect to fileInput click var input = document.createElement('input'); input.type = 'file'; input.accept = '.vtt, .srt, .ssa, .ass, .txt'; input.onchange = e => { - var file = e.target.files[0]; - console.log(file); - this.loadSubtitle(file); + let file = e.target.files[0]; + if (file.type === 'text/vtt') { + this.loadSubtitle(file); + return; + } + this.convert2vtt(file).then((file) => { + this.loadSubtitle(file); + }); }; input.click(); - // const now = this.player_.currentTime(); - // - // if (this.options_.direction === 'forward') { - // this.player_.currentTime(now + this.options_.seconds); - // } else if (this.options_.direction === 'back') { - // this.player_.currentTime(now - this.options_.seconds); - // } + } + + // TODO: find some npm module, which works with strings + srt2webvtt(data) { + // remove dos newlines + var srt = data.replace(/\r+/g, ''); + // trim white space start and end + srt = srt.replace(/^\s+|\s+$/g, ''); + + // get cues + var cuelist = srt.split('\n\n'); + var result = ''; + + if (cuelist.length > 0) { + result += 'WEBVTT\n\n'; + for (var i = 0; i < cuelist.length; i=i+1) { + result += this.convertSrtCue(cuelist[i]); + } + } + + return result; + } + + convertSrtCue(caption) { + // remove all html tags for security reasons + //srt = srt.replace(/<[a-zA-Z\/][^>]*>/g, ''); + + var cue = ''; + var s = caption.split(/\n/); + + // concatenate muilt-line string separated in array into one + while (s.length > 3) { + for (var i = 3; i < s.length; i++) { + s[2] += '\n' + s[i]; + } + s.splice(3, s.length - 3); + } + + var line = 0; + + // detect identifier + if (!s[0].match(/\d+:\d+:\d+/) && s[1].match(/\d+:\d+:\d+/)) { + cue += s[0].match(/\w+/) + '\n'; + line += 1; + } + + // get time strings + if (s[line].match(/\d+:\d+:\d+/)) { + // convert time string + var m = s[1].match(/(\d+):(\d+):(\d+)(?:,(\d+))?\s*--?>\s*(\d+):(\d+):(\d+)(?:,(\d+))?/); + if (m) { + cue += m[1]+':'+m[2]+':'+m[3]+'.'+m[4]+' --> ' + +m[5]+':'+m[6]+':'+m[7]+'.'+m[8]+'\n'; + line += 1; + } else { + // Unrecognized timestring + return ''; + } + } else { + // file format error or comment lines + return ''; + } + + // get cue text + if (s[line]) { + cue += s[line] + '\n\n'; + } + + return cue; + } + + async convert2vtt(file) { + let text = await file.text(); + + let vtt = this.srt2webvtt(text); + return new File( + [vtt], + '/temp.vtt', + {type: 'text/vtt'} + ); } loadSubtitle(file) { - //clean tracks - var tracks = this.player_.textTracks() || []; - for (var i = 0; i < tracks.length; ++i) { - if (tracks[i].id_.indexOf('vjs_subtitles_00') !== -1) { - $(tracks[i].el()).remove(); - tracks.splice(i, 1); - break; + // on call removeRemoteTextTrack this.player_ set to null (???) + let tracks = videojs('video_player').remoteTextTracks() || []; + for (let i = tracks.length - 1; i >= 0; --i) { + if (tracks[i].language === '00') { + videojs('video_player').removeRemoteTextTrack(tracks[i]); } } - window['x'] = file; - - file.text().then((x) => fs.writeFileSync(App.settings.tmpLocation + '/temp.srt', x)).then((stream) => { - fs.createReadStream(App.settings.tmpLocation + '/temp.srt') - .pipe(srt2vtt()) - .pipe(fs.createWriteStream(App.settings.tmpLocation + '/temp.vtt')); - }).then(() => { - let file = new Blob(new Uint8Array(fs.readFileSync(App.settings.tmpLocation + '/temp.vtt')), {type: 'text/vtt'}); - console.log(file); - const track = this.player_.addRemoteTextTrack({ - kind: 'subtitles', - language: '01', - label: 'str2vtt', - mode: 'showing', - src: URL.createObjectURL(file) - }, false); - console.log(track); - }); - //return; - - //file.stream().pipe(srt2vtt()).toBlob() - - const track = this.player_.addRemoteTextTrack({ + const track = videojs('video_player').addRemoteTextTrack({ kind: 'subtitles', language: '00', label: 'original', mode: 'showing', src: URL.createObjectURL(file) }, false); - // const track = this.player_.addTextTrack('subtitles', 'Loaded', App.Settings.language, { - // src: filePath - // }); - console.log(track); - //App.vent.trigger('customSubtitles:added', filePath); - //vjs.TextTrackMenuItem.prototype.onClick.call(this); // redirect to TextTrackMenuItem.onClick } } @@ -242,90 +274,3 @@ class CustomButton extends MenuButton { } videojs.registerComponent('customButton', CustomButton); - -// // Custom Subtitles Button/Menu -// videojs.registerPlugin('customSubtitles', function () { -// -// // Find subtitlesButton -// var subtitlesButton; -// this.controlBar.children().forEach(function (el) { -// if (el.name() === 'subtitlesButton') { -// subtitlesButton = el; -// } -// }); -// -// var CustomTrackMenuItem = vjs.TextTrackMenuItem.extend({ -// -// /*@ Constructor */ -// init: function (player, options) { -// options = options || {}; -// // fake 'empty' track -// options['track'] = { -// kind: function () { -// return 'subtitles'; -// }, -// player: player, -// label: function () { -// return i18n.__('Custom...'); -// }, -// dflt: function () { -// return false; -// }, -// mode: function () { -// return false; -// } -// }; -// -// this.fileInput_ = $(''); -// $(this.el()).append(this.fileInput_); -// -// var that = this; -// -// App.vent.on('videojs:drop_sub', function () { -// var subname = Settings.droppedSub; -// var subpath = path.join(App.settings.tmpLocation, subname); -// win.info('Subtitles dropped:', subname); -// that.loadSubtitle(subpath); -// }); -// -// this.fileInput_.on('change', function () { -// that.player_.play(); -// if (this.value === '') { -// return; -// } -// that.loadSubtitle(this.value); -// this.value = null; //reset -// }); -// -// vjs.TextTrackMenuItem.call(this, player, options); -// } -// }); -// -// CustomTrackMenuItem.prototype.onClick = function () { -// this.player_.pause(); -// this.fileInput_.trigger('click'); // redirect to fileInput click -// }; -// -// CustomTrackMenuItem.prototype.loadSubtitle = function (filePath) { -// -// //clean tracks -// var tracks = this.player_.textTracks() || []; -// for (var i = 0; i < tracks.length; ++i) { -// if (tracks[i].id_.indexOf('vjs_subtitles_00') !== -1) { -// $(tracks[i].el()).remove(); -// tracks.splice(i, 1); -// break; -// } -// } -// -// this.track = this.player_.addTextTrack('subtitles', i18n.__('Custom...'), '00', { -// src: filePath -// }); -// App.vent.trigger('customSubtitles:added', filePath); -// vjs.TextTrackMenuItem.prototype.onClick.call(this); // redirect to TextTrackMenuItem.onClick -// }; -// -// subtitlesButton.menu.addItem(new CustomTrackMenuItem(this)); -// subtitlesButton.show(); // Always show subtitles button -// -// }); From a4537e07122b910e18d78ed931d1e9a03d96ba57 Mon Sep 17 00:00:00 2001 From: Ivan Borzenkov Date: Sat, 21 Aug 2021 10:58:35 +0300 Subject: [PATCH 11/12] small fixes --- src/app/vendor/videojsplugins.js | 59 ++------------------------------ 1 file changed, 2 insertions(+), 57 deletions(-) diff --git a/src/app/vendor/videojsplugins.js b/src/app/vendor/videojsplugins.js index 26cdde6e5e..a3b83fc6f7 100644 --- a/src/app/vendor/videojsplugins.js +++ b/src/app/vendor/videojsplugins.js @@ -1,7 +1,6 @@ // VideoJS Plugins var Button = videojs.getComponent('Button'); -var MenuButton = videojs.getComponent('MenuButton'); var SubtitlesButton = videojs.getComponent('SubtitlesButton'); var MenuItem = videojs.getComponent('MenuItem'); @@ -180,7 +179,7 @@ class CustomTrackMenuItem extends MenuItem { let vtt = this.srt2webvtt(text); return new File( [vtt], - '/temp.vtt', + 'loaded.vtt', {type: 'text/vtt'} ); } @@ -198,7 +197,7 @@ class CustomTrackMenuItem extends MenuItem { const track = videojs('video_player').addRemoteTextTrack({ kind: 'subtitles', language: '00', - label: 'original', + label: i18n.__('Custom...'), mode: 'showing', src: URL.createObjectURL(file) }, false); @@ -220,57 +219,3 @@ class CustomSubtitlesButton extends SubtitlesButton } } videojs.registerComponent('customSubtitlesButton', CustomSubtitlesButton); - -/** - * Button for subtitles menu - * - * @extends MenuButton - * @class SubtitlesButton - */ -class CustomButton extends MenuButton { - /** - * Constructor for class - * - * @param {Player|Object} player The player - * @param {Object=} options Button options - * @param {string} options.direction back or forward - * @param {Int} options.seconds number of seconds to seek - */ - constructor(player, options) { - super(player, options); - if (this.options_.direction === 'forward') { - this.controlText(this.localize('Seek forward {{seconds}} seconds') - .replace('{{seconds}}', this.options_.seconds)); - } else if (this.options_.direction === 'back') { - this.controlText(this.localize('Seek back {{seconds}} seconds') - .replace('{{seconds}}', this.options_.seconds)); - } - } - - /** - * Return button class names which include the seek amount. - * - * @return {string} css cass string - */ - buildCSSClass() { - return `vjs-subtitles-button ${super.buildCSSClass()}`; - } - - /** - * Seek with the button's configured offset - */ - handleClick() { - console.log('click!'); - - - // const now = this.player_.currentTime(); - // - // if (this.options_.direction === 'forward') { - // this.player_.currentTime(now + this.options_.seconds); - // } else if (this.options_.direction === 'back') { - // this.player_.currentTime(now - this.options_.seconds); - // } - } -} - -videojs.registerComponent('customButton', CustomButton); From d54623e8434fe903be8ff8a29514b7d587cce1f4 Mon Sep 17 00:00:00 2001 From: Ivan Borzenkov Date: Sat, 19 Feb 2022 23:45:29 +0300 Subject: [PATCH 12/12] some bigger video control bar --- src/app/styl/views/videojs.styl | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/app/styl/views/videojs.styl b/src/app/styl/views/videojs.styl index 9a12bd940b..2f263b5822 100644 --- a/src/app/styl/views/videojs.styl +++ b/src/app/styl/views/videojs.styl @@ -293,6 +293,19 @@ // padding-top: 0.1em; // } //} + .vjs-control-bar { + font-size: 14px; + } + + .vjs-time-control { + display: block; + padding: 0; + min-width: 0; + &.vjs-time-divider { + margin: 0 5px; + } + } + .vjs-volume-panel { order: 1; &.vjs-volume-panel-horizontal {