mirror of
https://github.com/zoriya/Kyoo.git
synced 2026-03-02 06:59:59 -05:00
Web player fixes & fullscreen
This commit is contained in:
parent
a7d5f94dfb
commit
816ee8de14
@ -39,6 +39,8 @@
|
||||
"react-native-web": "^0.21.1",
|
||||
"react-tooltip": "^5.29.1",
|
||||
"sweetalert2": "^11.23.0",
|
||||
"uuid": "^13.0.0",
|
||||
"video.js": "^8.23.4",
|
||||
"yoshiki": "1.2.14",
|
||||
"zod": "^4.1.11",
|
||||
},
|
||||
@ -545,6 +547,12 @@
|
||||
|
||||
"@urql/exchange-retry": ["@urql/exchange-retry@1.3.2", "", { "dependencies": { "@urql/core": "^5.1.2", "wonka": "^6.3.2" } }, "sha512-TQMCz2pFJMfpNxmSfX1VSfTjwUIFx/mL+p1bnfM1xjjdla7Z+KnGMW/EhFbpckp3LyWAH4PgOsMwOMnIN+MBFg=="],
|
||||
|
||||
"@videojs/http-streaming": ["@videojs/http-streaming@3.17.2", "", { "dependencies": { "@babel/runtime": "^7.12.5", "@videojs/vhs-utils": "^4.1.1", "aes-decrypter": "^4.0.2", "global": "^4.4.0", "m3u8-parser": "^7.2.0", "mpd-parser": "^1.3.1", "mux.js": "7.1.0", "video.js": "^7 || ^8" } }, "sha512-VBQ3W4wnKnVKb/limLdtSD2rAd5cmHN70xoMf4OmuDd0t2kfJX04G+sfw6u2j8oOm2BXYM9E1f4acHruqKnM1g=="],
|
||||
|
||||
"@videojs/vhs-utils": ["@videojs/vhs-utils@4.1.1", "", { "dependencies": { "@babel/runtime": "^7.12.5", "global": "^4.4.0" } }, "sha512-5iLX6sR2ownbv4Mtejw6Ax+naosGvoT9kY+gcuHzANyUZZ+4NpeNdKMUhb6ag0acYej1Y7cmr/F2+4PrggMiVA=="],
|
||||
|
||||
"@videojs/xhr": ["@videojs/xhr@2.7.0", "", { "dependencies": { "@babel/runtime": "^7.5.5", "global": "~4.4.0", "is-function": "^1.0.1" } }, "sha512-giab+EVRanChIupZK7gXjHy90y3nncA2phIOyG3Ne5fvpiMJzvqYwiTOnEVW2S4CoYcuKJkomat7bMXA/UoUZQ=="],
|
||||
|
||||
"@xmldom/xmldom": ["@xmldom/xmldom@0.8.10", "", {}, "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw=="],
|
||||
|
||||
"abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="],
|
||||
@ -553,6 +561,8 @@
|
||||
|
||||
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
||||
|
||||
"aes-decrypter": ["aes-decrypter@4.0.2", "", { "dependencies": { "@babel/runtime": "^7.12.5", "@videojs/vhs-utils": "^4.1.1", "global": "^4.4.0", "pkcs7": "^1.0.4" } }, "sha512-lc+/9s6iJvuaRe5qDlMTpCFjnwpkeOXp8qP3oiZ5jsj1MRg+SBVUmmICrhxHvc8OELSmc+fEyyxAuppY6hrWzw=="],
|
||||
|
||||
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
|
||||
|
||||
"ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
|
||||
@ -729,6 +739,8 @@
|
||||
|
||||
"dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="],
|
||||
|
||||
"dom-walk": ["dom-walk@0.1.2", "", {}, "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="],
|
||||
|
||||
"domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="],
|
||||
|
||||
"domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="],
|
||||
@ -875,6 +887,8 @@
|
||||
|
||||
"glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
|
||||
|
||||
"global": ["global@4.4.0", "", { "dependencies": { "min-document": "^2.19.0", "process": "^0.11.10" } }, "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w=="],
|
||||
|
||||
"global-dirs": ["global-dirs@0.1.1", "", { "dependencies": { "ini": "^1.3.4" } }, "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg=="],
|
||||
|
||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||
@ -931,6 +945,8 @@
|
||||
|
||||
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
|
||||
|
||||
"is-function": ["is-function@1.0.2", "", {}, "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ=="],
|
||||
|
||||
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||
|
||||
"is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="],
|
||||
@ -1025,6 +1041,8 @@
|
||||
|
||||
"lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||
|
||||
"m3u8-parser": ["m3u8-parser@7.2.0", "", { "dependencies": { "@babel/runtime": "^7.12.5", "@videojs/vhs-utils": "^4.1.1", "global": "^4.4.0" } }, "sha512-CRatFqpjVtMiMaKXxNvuI3I++vUumIXVVT/JpCpdU/FynV/ceVw1qpPyyBNindL+JlPMSesx+WX1QJaZEJSaMQ=="],
|
||||
|
||||
"makeerror": ["makeerror@1.0.12", "", { "dependencies": { "tmpl": "1.0.5" } }, "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg=="],
|
||||
|
||||
"marky": ["marky@1.3.0", "", {}, "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ=="],
|
||||
@ -1073,6 +1091,8 @@
|
||||
|
||||
"mimic-fn": ["mimic-fn@1.2.0", "", {}, "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="],
|
||||
|
||||
"min-document": ["min-document@2.19.0", "", { "dependencies": { "dom-walk": "^0.1.0" } }, "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ=="],
|
||||
|
||||
"minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||
|
||||
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
||||
@ -1083,8 +1103,12 @@
|
||||
|
||||
"mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="],
|
||||
|
||||
"mpd-parser": ["mpd-parser@1.3.1", "", { "dependencies": { "@babel/runtime": "^7.12.5", "@videojs/vhs-utils": "^4.0.0", "@xmldom/xmldom": "^0.8.3", "global": "^4.4.0" }, "bin": { "mpd-to-m3u8-json": "bin/parse.js" } }, "sha512-1FuyEWI5k2HcmhS1HkKnUAQV7yFPfXPht2DnRRGtoiiAAW+ESTbtEXIDpRkwdU+XyrQuwrIym7UkoPKsZ0SyFw=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"mux.js": ["mux.js@7.1.0", "", { "dependencies": { "@babel/runtime": "^7.11.2", "global": "^4.4.0" }, "bin": { "muxjs-transmux": "bin/transmux.js" } }, "sha512-NTxawK/BBELJrYsZThEulyUMDVlLizKdxyAsMuzoCD1eFj97BVaA8D/CvKsKu6FOLYkFojN5CbM9h++ZTZtknA=="],
|
||||
|
||||
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
|
||||
|
||||
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
@ -1163,6 +1187,8 @@
|
||||
|
||||
"pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="],
|
||||
|
||||
"pkcs7": ["pkcs7@1.0.4", "", { "dependencies": { "@babel/runtime": "^7.5.5" }, "bin": { "pkcs7": "bin/cli.js" } }, "sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ=="],
|
||||
|
||||
"plist": ["plist@3.1.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ=="],
|
||||
|
||||
"pngjs": ["pngjs@3.4.0", "", {}, "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w=="],
|
||||
@ -1177,6 +1203,8 @@
|
||||
|
||||
"proc-log": ["proc-log@4.2.0", "", {}, "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA=="],
|
||||
|
||||
"process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="],
|
||||
|
||||
"progress": ["progress@2.0.3", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="],
|
||||
|
||||
"promise": ["promise@8.3.0", "", { "dependencies": { "asap": "~2.0.6" } }, "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg=="],
|
||||
@ -1227,7 +1255,7 @@
|
||||
|
||||
"react-native-svg-transformer": ["react-native-svg-transformer@1.5.1", "", { "dependencies": { "@svgr/core": "^8.1.0", "@svgr/plugin-jsx": "^8.1.0", "@svgr/plugin-svgo": "^8.1.0", "path-dirname": "^1.0.2" }, "peerDependencies": { "react-native": ">=0.59.0", "react-native-svg": ">=12.0.0" } }, "sha512-dFvBNR8A9VPum9KCfh+LE49YiJEF8zUSnEFciKQroR/bEOhlPoZA0SuQ0qNk7m2iZl2w59FYjdRe0pMHWMDl0Q=="],
|
||||
|
||||
"react-native-video": ["react-native-video@github:zoriya/react-native-video#0bb0dd5", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": ">=0.27.2" } }, "zoriya-react-native-video-0bb0dd5"],
|
||||
"react-native-video": ["react-native-video@github:zoriya/react-native-video#6613ecf", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": ">=0.27.2" } }, "zoriya-react-native-video-6613ecf"],
|
||||
|
||||
"react-native-web": ["react-native-web@0.21.1", "", { "dependencies": { "@babel/runtime": "^7.18.6", "@react-native/normalize-colors": "^0.74.1", "fbjs": "^3.0.4", "inline-style-prefixer": "^7.0.1", "memoize-one": "^6.0.0", "nullthrows": "^1.1.1", "postcss-value-parser": "^4.2.0", "styleq": "^0.1.3" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-BeNsgwwe4AXUFPAoFU+DKjJ+CVQa3h54zYX77p7GVZrXiiNo3vl03WYDYVEy5R2J2HOPInXtQZB5gmj3vuzrKg=="],
|
||||
|
||||
@ -1435,7 +1463,7 @@
|
||||
|
||||
"utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="],
|
||||
|
||||
"uuid": ["uuid@7.0.3", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg=="],
|
||||
"uuid": ["uuid@13.0.0", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w=="],
|
||||
|
||||
"validate-npm-package-name": ["validate-npm-package-name@5.0.1", "", {}, "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ=="],
|
||||
|
||||
@ -1443,6 +1471,14 @@
|
||||
|
||||
"vaul": ["vaul@1.1.2", "", { "dependencies": { "@radix-ui/react-dialog": "^1.1.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA=="],
|
||||
|
||||
"video.js": ["video.js@8.23.4", "", { "dependencies": { "@babel/runtime": "^7.12.5", "@videojs/http-streaming": "^3.17.2", "@videojs/vhs-utils": "^4.1.1", "@videojs/xhr": "2.7.0", "aes-decrypter": "^4.0.2", "global": "4.4.0", "m3u8-parser": "^7.2.0", "mpd-parser": "^1.3.1", "mux.js": "^7.0.1", "videojs-contrib-quality-levels": "4.1.0", "videojs-font": "4.2.0", "videojs-vtt.js": "0.15.5" } }, "sha512-qI0VTlYmKzEqRsz1Nppdfcaww4RSxZAq77z2oNSl3cNg2h6do5C8Ffl0KqWQ1OpD8desWXsCrde7tKJ9gGTEyQ=="],
|
||||
|
||||
"videojs-contrib-quality-levels": ["videojs-contrib-quality-levels@4.1.0", "", { "dependencies": { "global": "^4.4.0" }, "peerDependencies": { "video.js": "^8" } }, "sha512-TfrXJJg1Bv4t6TOCMEVMwF/CoS8iENYsWNKip8zfhB5kTcegiFYezEA0eHAJPU64ZC8NQbxQgOwAsYU8VXbOWA=="],
|
||||
|
||||
"videojs-font": ["videojs-font@4.2.0", "", {}, "sha512-YPq+wiKoGy2/M7ccjmlvwi58z2xsykkkfNMyIg4xb7EZQQNwB71hcSsB3o75CqQV7/y5lXkXhI/rsGAS7jfEmQ=="],
|
||||
|
||||
"videojs-vtt.js": ["videojs-vtt.js@0.15.5", "", { "dependencies": { "global": "^4.3.1" } }, "sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ=="],
|
||||
|
||||
"vlq": ["vlq@1.0.1", "", {}, "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w=="],
|
||||
|
||||
"void-elements": ["void-elements@3.1.0", "", {}, "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="],
|
||||
@ -1713,6 +1749,8 @@
|
||||
|
||||
"write-file-atomic/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
|
||||
|
||||
"xcode/uuid": ["uuid@7.0.3", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg=="],
|
||||
|
||||
"xml2js/xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="],
|
||||
|
||||
"yoshiki/@types/react": ["@types/react@18.3.23", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w=="],
|
||||
|
||||
@ -48,6 +48,8 @@
|
||||
"react-native-web": "^0.21.1",
|
||||
"react-tooltip": "^5.29.1",
|
||||
"sweetalert2": "^11.23.0",
|
||||
"uuid": "^13.0.0",
|
||||
"video.js": "^8.23.4",
|
||||
"yoshiki": "1.2.14",
|
||||
"zod": "^4.1.11"
|
||||
},
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { useState } from "react";
|
||||
import type { ViewProps } from "react-native";
|
||||
import { StyleSheet } from "react-native";
|
||||
import { StyleSheet, View } from "react-native";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import type { VideoPlayer } from "react-native-video";
|
||||
import { useYoshiki } from "yoshiki/native";
|
||||
@ -45,16 +45,16 @@ export const Controls = ({
|
||||
} satisfies ViewProps;
|
||||
|
||||
return (
|
||||
<TouchControls
|
||||
player={player}
|
||||
forceShow={hover || menuOpenned}
|
||||
{...css(StyleSheet.absoluteFillObject)}
|
||||
>
|
||||
<View {...css(StyleSheet.absoluteFillObject)}>
|
||||
<TouchControls
|
||||
player={player}
|
||||
forceShow={hover || menuOpenned}
|
||||
{...css(StyleSheet.absoluteFillObject)}
|
||||
/>
|
||||
<Back
|
||||
name={name}
|
||||
{...css(
|
||||
{
|
||||
// pointerEvents: "auto",
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
@ -94,7 +94,7 @@ export const Controls = ({
|
||||
hoverControls,
|
||||
)}
|
||||
/>
|
||||
</TouchControls>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -6,9 +6,9 @@ import VolumeDown from "@material-symbols/svg-400/rounded/volume_down-fill.svg";
|
||||
import VolumeMute from "@material-symbols/svg-400/rounded/volume_mute-fill.svg";
|
||||
import VolumeOff from "@material-symbols/svg-400/rounded/volume_off-fill.svg";
|
||||
import VolumeUp from "@material-symbols/svg-400/rounded/volume_up-fill.svg";
|
||||
import { type ComponentProps, useState } from "react";
|
||||
import { type ComponentProps, useState, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { type PressableProps, View } from "react-native";
|
||||
import { type PressableProps, View, Platform } from "react-native";
|
||||
import { useEvent, type VideoPlayer } from "react-native-video";
|
||||
import { px, useYoshiki } from "yoshiki/native";
|
||||
import {
|
||||
@ -46,18 +46,39 @@ export const PlayButton = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const toggleFullscreen = async (set?: boolean) => {
|
||||
set ??= document.fullscreenElement === null;
|
||||
try {
|
||||
if (set) {
|
||||
await document.body.requestFullscreen({ navigationUI: "hide" });
|
||||
// @ts-expect-error Firefox does not support this so ts complains
|
||||
await screen.orientation.lock("landscape");
|
||||
} else {
|
||||
if (document.fullscreenElement) await document.exitFullscreen();
|
||||
screen.orientation.unlock();
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
export const FullscreenButton = (
|
||||
props: Partial<ComponentProps<typeof IconButton<PressableProps>>>,
|
||||
) => {
|
||||
// this is a web only component
|
||||
const { t } = useTranslation();
|
||||
|
||||
// TODO: actually implement that
|
||||
const [fullscreen, setFullscreen] = useState(true);
|
||||
const [fullscreen, setFullscreen] = useState(false);
|
||||
useEffect(() => {
|
||||
const update = () => setFullscreen(document.fullscreenElement !== null);
|
||||
document.addEventListener("fullscreenchange", update);
|
||||
return () => document.removeEventListener("fullscreenchange", update);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
icon={fullscreen ? FullscreenExit : Fullscreen}
|
||||
onPress={() => console.log("lol")}
|
||||
onPress={() => toggleFullscreen()}
|
||||
{...tooltip(t("player.fullscreen"), true)}
|
||||
{...props}
|
||||
/>
|
||||
@ -91,9 +112,9 @@ export const VolumeSlider = ({ player, ...props }: { player: VideoPlayer }) => {
|
||||
icon={
|
||||
muted || volume === 0
|
||||
? VolumeOff
|
||||
: volume < 25
|
||||
: volume < 0.25
|
||||
? VolumeMute
|
||||
: volume < 65
|
||||
: volume < 0.65
|
||||
? VolumeDown
|
||||
: VolumeUp
|
||||
}
|
||||
@ -103,9 +124,9 @@ export const VolumeSlider = ({ player, ...props }: { player: VideoPlayer }) => {
|
||||
{...tooltip(t("player.mute"), true)}
|
||||
/>
|
||||
<Slider
|
||||
progress={volume}
|
||||
progress={volume * 100}
|
||||
setProgress={(vol) => {
|
||||
player.volume = vol;
|
||||
player.volume = vol / 100;
|
||||
}}
|
||||
size={4}
|
||||
{...css({ width: px(100) })}
|
||||
|
||||
@ -80,11 +80,11 @@ export const ProgressText = ({
|
||||
}: { player: VideoPlayer } & TextProps) => {
|
||||
const { css } = useYoshiki();
|
||||
|
||||
const [progress, setProgress] = useState(player.currentTime || 0);
|
||||
const [progress, setProgress] = useState(player.currentTime);
|
||||
useEvent(player, "onProgress", (progress) => {
|
||||
setProgress(progress.currentTime);
|
||||
});
|
||||
const [duration, setDuration] = useState(player.duration || 100);
|
||||
const [duration, setDuration] = useState(player.duration);
|
||||
useEvent(player, "onLoad", (info) => {
|
||||
if (info.duration) setDuration(info.duration);
|
||||
});
|
||||
|
||||
@ -8,6 +8,7 @@ import {
|
||||
import { useEvent, type VideoPlayer } from "react-native-video";
|
||||
import { useYoshiki } from "yoshiki/native";
|
||||
import { useIsTouch } from "~/primitives";
|
||||
import { toggleFullscreen } from "./misc";
|
||||
|
||||
export const TouchControls = ({
|
||||
player,
|
||||
@ -62,7 +63,7 @@ export const TouchControls = ({
|
||||
}}
|
||||
onDoublePress={(e) => {
|
||||
if (!isTouch) {
|
||||
// player.toggleFullscreen();
|
||||
toggleFullscreen();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Stack, useRouter } from "expo-router";
|
||||
import { StyleSheet, View } from "react-native";
|
||||
import { Platform, StyleSheet, View } from "react-native";
|
||||
import { useEvent, useVideoPlayer, VideoView } from "react-native-video";
|
||||
import { entryDisplayNumber } from "~/components/entries";
|
||||
import { FullVideo, VideoInfo } from "~/models";
|
||||
@ -9,6 +9,11 @@ import { useLocalSetting } from "~/providers/settings";
|
||||
import { type QueryIdentifier, useFetch } from "~/query";
|
||||
import { useQueryState } from "~/utils";
|
||||
import { Controls, LoadingIndicator } from "./controls";
|
||||
import { useEffect } from "react";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { toggleFullscreen } from "./controls/misc";
|
||||
|
||||
const clientId = uuidv4();
|
||||
|
||||
export const Player = () => {
|
||||
const [slug, setSlug] = useQueryState<string>("slug", undefined!);
|
||||
@ -19,28 +24,40 @@ export const Player = () => {
|
||||
// TODO: map current entry using entries' duration & the current playtime
|
||||
const currentEntry = 0;
|
||||
const entry = data?.entries[currentEntry] ?? data?.entries[0];
|
||||
const title = entry ? `${entry.name} (${entryDisplayNumber(entry)})` : null;
|
||||
|
||||
const { apiUrl, authToken } = useToken();
|
||||
const [playMode] = useLocalSetting<"direct" | "hls">("playMode", "direct");
|
||||
const player = useVideoPlayer(
|
||||
{
|
||||
uri: `${apiUrl}/api/videos/${slug}/${playMode === "direct" ? "direct" : "master.m3u8"}`,
|
||||
headers: {
|
||||
Authorization: `Bearer ${authToken}`,
|
||||
uri: `${apiUrl}/api/videos/${slug}/${playMode === "direct" ? "direct" : "master.m3u8"}?clientId=${clientId}`,
|
||||
// chrome based browsers support matroska but they tell they don't
|
||||
mimeType: info?.mimeCodec?.replace("x-matroska", "mp4"),
|
||||
headers: authToken
|
||||
? {
|
||||
Authorization: `Bearer ${authToken}`,
|
||||
}
|
||||
: {},
|
||||
metadata: {
|
||||
title: title ?? undefined,
|
||||
description: entry?.description ?? undefined,
|
||||
artist: data?.show?.name ?? undefined,
|
||||
imageUri: data?.show?.thumbnail?.high ?? undefined,
|
||||
},
|
||||
// externalSubtitles: info?.subtitles
|
||||
// .filter((x) => x.link)
|
||||
// .map((x) => ({
|
||||
// uri: x.link!,
|
||||
// // TODO: translate this `Unknown`
|
||||
// label: x.title ?? "Unknown",
|
||||
// language: x.language ?? "und",
|
||||
// type: x.codec,
|
||||
// })),
|
||||
externalSubtitles: info?.subtitles
|
||||
.filter((x) => x.link)
|
||||
.map((x) => ({
|
||||
uri: x.link!,
|
||||
// TODO: translate this `Unknown`
|
||||
label: x.title ?? "Unknown",
|
||||
language: x.language ?? "und",
|
||||
type: x.codec,
|
||||
})),
|
||||
},
|
||||
(p) => {
|
||||
p.playWhenInactive = true;
|
||||
p.playInBackground = true;
|
||||
p.showNotificationControls = true;
|
||||
const seek = start ?? data?.progress.time;
|
||||
// TODO: fix console.error bellow
|
||||
if (seek) p.seekTo(seek);
|
||||
@ -60,6 +77,31 @@ export const Player = () => {
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: add the equivalent of this for android
|
||||
useEffect(() => {
|
||||
if (typeof window === "undefined") return;
|
||||
const prev = data?.previous?.video;
|
||||
window.navigator.mediaSession.setActionHandler(
|
||||
"previoustrack",
|
||||
prev
|
||||
? () => {
|
||||
setStart(0);
|
||||
setSlug(prev);
|
||||
}
|
||||
: null,
|
||||
);
|
||||
const next = data?.next?.video;
|
||||
window.navigator.mediaSession.setActionHandler(
|
||||
"nexttrack",
|
||||
next
|
||||
? () => {
|
||||
setStart(0);
|
||||
setSlug(next);
|
||||
}
|
||||
: null,
|
||||
);
|
||||
}, [data?.next?.video, data?.previous?.video, setSlug, setStart]);
|
||||
|
||||
// const [playbackError, setPlaybackError] = useState<string | undefined>(
|
||||
// undefined,
|
||||
// );
|
||||
@ -67,14 +109,13 @@ export const Player = () => {
|
||||
|
||||
// const startTime = startTimeP ?? data?.watchStatus?.watchedTime;
|
||||
|
||||
// const setFullscreen = useSetAtom(fullscreenAtom);
|
||||
// useEffect(() => {
|
||||
// if (Platform.OS !== "web") return;
|
||||
// if (/Mobi/i.test(window.navigator.userAgent)) setFullscreen(true);
|
||||
// return () => {
|
||||
// if (!document.location.href.includes("/watch")) setFullscreen(false);
|
||||
// };
|
||||
// }, [setFullscreen]);
|
||||
useEffect(() => {
|
||||
if (Platform.OS !== "web") return;
|
||||
if (/Mobi/i.test(window.navigator.userAgent)) toggleFullscreen(true);
|
||||
return () => {
|
||||
if (!document.location.href.includes("/watch")) toggleFullscreen(false);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// if (error || infoError || playbackError)
|
||||
// return (
|
||||
@ -95,7 +136,7 @@ export const Player = () => {
|
||||
}}
|
||||
>
|
||||
<Head
|
||||
title={entry ? `${entry.name} (${entryDisplayNumber(entry)})` : null}
|
||||
title={title}
|
||||
description={entry?.description}
|
||||
image={data?.show?.thumbnail?.high}
|
||||
/>
|
||||
|
||||
@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Kyoo - A portable and vast media library solution.
|
||||
* Copyright (c) Kyoo.
|
||||
*
|
||||
* See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
*
|
||||
* Kyoo is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* Kyoo is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
||||
import { useEffect } from "react";
|
||||
import { useRouter } from "solito/router";
|
||||
import { reducerAtom } from "./old/keyboardd";
|
||||
import { durationAtom, playAtom, progressAtom } from "./old/statee";
|
||||
|
||||
export const MediaSessionManager = ({
|
||||
title,
|
||||
subtitle,
|
||||
artist,
|
||||
imageUri,
|
||||
previous,
|
||||
next,
|
||||
}: {
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
artist?: string;
|
||||
imageUri?: string | null;
|
||||
previous?: string;
|
||||
next?: string;
|
||||
}) => {
|
||||
const [isPlaying, setPlay] = useAtom(playAtom);
|
||||
const progress = useAtomValue(progressAtom);
|
||||
const duration = useAtomValue(durationAtom);
|
||||
const reducer = useSetAtom(reducerAtom);
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
if (!("mediaSession" in navigator)) return;
|
||||
navigator.mediaSession.metadata = new MediaMetadata({
|
||||
title: title,
|
||||
album: subtitle,
|
||||
artist: artist,
|
||||
artwork: imageUri ? [{ src: imageUri }] : undefined,
|
||||
});
|
||||
}, [title, subtitle, artist, imageUri]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!("mediaSession" in navigator)) return;
|
||||
const actions: [MediaSessionAction, MediaSessionActionHandler | null][] = [
|
||||
["play", () => setPlay(true)],
|
||||
["pause", () => setPlay(false)],
|
||||
["previoustrack", previous ? () => router.push(previous) : null],
|
||||
["nexttrack", next ? () => router.push(next) : null],
|
||||
[
|
||||
"seekbackward",
|
||||
(evt: MediaSessionActionDetails) =>
|
||||
reducer({ type: "seek", value: evt.seekOffset ? -evt.seekOffset : -10 }),
|
||||
],
|
||||
[
|
||||
"seekforward",
|
||||
(evt: MediaSessionActionDetails) =>
|
||||
reducer({ type: "seek", value: evt.seekOffset ? evt.seekOffset : 10 }),
|
||||
],
|
||||
[
|
||||
"seekto",
|
||||
(evt: MediaSessionActionDetails) => reducer({ type: "seekTo", value: evt.seekTime! }),
|
||||
],
|
||||
];
|
||||
|
||||
for (const [action, handler] of actions) {
|
||||
try {
|
||||
navigator.mediaSession.setActionHandler(action, handler);
|
||||
} catch {}
|
||||
}
|
||||
}, [setPlay, reducer, router, previous, next]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!("mediaSession" in navigator)) return;
|
||||
navigator.mediaSession.playbackState = isPlaying ? "playing" : "paused";
|
||||
}, [isPlaying]);
|
||||
useEffect(() => {
|
||||
if (!("mediaSession" in navigator) || !duration) return;
|
||||
navigator.mediaSession.setPositionState({
|
||||
position: Math.min(progress, duration),
|
||||
duration,
|
||||
playbackRate: 1,
|
||||
});
|
||||
}, [progress, duration]);
|
||||
|
||||
return null;
|
||||
};
|
||||
@ -1,5 +1,5 @@
|
||||
import { NavigationContext, useRoute } from "@react-navigation/native";
|
||||
import { useContext } from "react";
|
||||
import { useCallback, useContext } from "react";
|
||||
import type { Movie, Show } from "~/models";
|
||||
|
||||
export function setServerData(_key: string, _val: any) {}
|
||||
@ -12,9 +12,12 @@ export const useQueryState = <S>(key: string, initial: S) => {
|
||||
const nav = useContext(NavigationContext);
|
||||
|
||||
const state = ((route.params as any)?.[key] as S) ?? initial;
|
||||
const update = (val: S | ((old: S) => S)) => {
|
||||
nav!.setParams({ [key]: val });
|
||||
};
|
||||
const update = useCallback(
|
||||
(val: S | ((old: S) => S)) => {
|
||||
nav!.setParams({ [key]: val });
|
||||
},
|
||||
[nav, key],
|
||||
);
|
||||
return [state, update] as const;
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user