mirror of
https://github.com/phit/video2webxr.git
synced 2026-10-18 08:01:17 +02:00
Initial commit
This commit is contained in:
commit
fc49fea217
10 files changed
+237
No files matched your search
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
_metadata
|
||||
package-lock.json
|
||||
@@ -0,0 +1,32 @@
|
||||
# Enable Youtube PC VR in Chromium
|
||||
|
||||
I couldn't find a way to watch Youtube VR videos on the PC without paying?
|
||||
|
||||
This is a Chromium extension to enable WebXR on Youtube videos that are non-3D and 360 degrees thanks to https://threejs.org/
|
||||
|
||||
### Install Instructions - Easy way
|
||||
1. Open the Edge extension store and download "Enable Youtube PC VR in Edge"
|
||||
|
||||
### Install Instructions - Manual way
|
||||
1. Install a Chromium based browser - Chrome, Edge, Brave etc.
|
||||
2. Download the project from github and unzip it to a folder
|
||||
3. Open the extensions in the browser and enable developer mode
|
||||
4. Click "Load Unpacked" and choose the folder
|
||||
|
||||
### Usage Instructions
|
||||
1. Turn VR on first
|
||||
2. Start a new browser so that it detects the hardware
|
||||
3. Open a non-3D 360 video on https://www.youtube.com/vr/
|
||||
4. Click on the white cardboard icon in the bottom right hand corner of the video
|
||||
5. Click on the "Enter VR" button in the middle bottom of the video
|
||||
6. Enjoy
|
||||
|
||||
### Troubleshooting
|
||||
If it says "VR NOT SUPPPORTED" then the browser hasn't detected your hardware
|
||||
- Make sure your VR is turned on and calibrated to your room
|
||||
- Make sure you have given Youtube.com permission to access "Virtual reality" in the "site permissions"
|
||||
- I have tested this on a HTC Vive Cosmos, please let me know if it works on other hardware configurations - it is generic and should work most devices
|
||||
|
||||
If you don't see the white cardboard icon in the bottom right hand corner of the youtube.com video then the extension is not installed or disabled
|
||||
|
||||
There isn't much error handling, pull requests welcome
|
||||
@@ -0,0 +1,110 @@
|
||||
import * as THREE from 'three';
|
||||
import { VRButton } from 'three/addons/webxr/VRButton.js';
|
||||
|
||||
let camera, scene, renderer;
|
||||
|
||||
// Function to be executed when the cardboard icon is clicked
|
||||
function handleCardboardIconClick() {
|
||||
const videoElement = document.querySelectorAll('video')[0]
|
||||
console.log("clicked cardboard button");
|
||||
EnableVRVideo(videoElement)
|
||||
animate();
|
||||
}
|
||||
|
||||
// Function to add the cardboard icon to a video element
|
||||
function addCardboardIconToVideo() {
|
||||
// Create a new <img> element for the cardboard icon
|
||||
const iconImg = document.createElement('img');
|
||||
const cardboardimg = 'data:application/octet-stream;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAAA0CAYAAADFeBvrAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAANnSURBVGhD7ZhNaxNBGMezMdsEigRa8IUeBMGUCj1JUehFQSwe6hfwoDf9BB700Lsfwp7Egy+oVQqiR6keJAejhEgC6UmkREjMa5vE/9P8DaYzm9lNUkjo/GDYeWb+88zz7OzMbhKyWCwWi8VisUwsDq8KjUZj1nXdGKrtTsvY4CC2SjQa/U27ByWhVCoVXlhYeOg4zi0UF01jl1C73a6jrGez2fuJRKLFdj17e3t3IZ4IEOsdht0lzOv/XON1EljhtYuSEBKXx2wi0MWqW6Fx2zP9UGLVJTTR2ITGnYETwoZM4dh822q1tlCvsnlg4KMmvsSn+Gbz8Ozu7r6GQ08w6Xdorubz+WMcEqrX6/Nof0lJYJrN5gbe/ufpLpTL5SKYYwU+M5RokVg5xJt+CWGCHIKfo1QB/S8o9Q2SeYWh2k8wJHkGPvOUKgydEPpuUqYFyZ5FAEXKjUD7B2MSHK4Fj+BtyhV0CfneQxi/gzv2jqYWfDDmoPtE0wi0WxiToakFCcue2qFpxHdC+FAtYPIiTU+g22bVCLR5Vj2Zmpoqytw0jQRZoelarRal6Ql0s6wa8aPFCkVlbppGgqzQHFZoiaaWSqUyA90lmkagvShjaGrBCi3J3DSNBHoPhcPhtWQy2T2uD4KE72HyUzT/IZs/LUXqnaYO0J6WMTQVZC6wRnMw+p1yAo7ZZ9Vq9STl++CdFMFp9ICSLkjiB/xdTqfTESlSlzZ2d5Gx4oPu9pE5ZC5KtOhOOeX8F1EkElmlqQW+fqK8QZG7fgIrdx13e7HT2wF9dQS6jEfmC5v2wUl5Af4/Qt+zH6H/imQ3Uf2FvnmUVZSDq90D/G+4rnuDph7TCvkFd/c5XSpIH2VDoVuhQHsoCJhvnVWFfn3DcigJIeB0uVx+T1NB+kRDc6QcVkKP4/F4jaaC9ImG5kgZeUIItIw98oSmJ6IRLc2RoSSESVgbDIzfxMmWpemJaERLc2QoCeEIHiojHL2PWDUSRKsDx7qvP0k+8xoY3PFvhULhA00josWYYX6dmmMtlUrT8obG3RPkbe+3bONFd4VufIMX7bKMPeDLVFqI8anESjddPP+sx5f1Il5cx1E1PYIOvreaeFQzsVhM+we6Ccw1gwDPIU4/h5QjPynwDTi6/x0sFovFYrEcCUKhvx967WCqRNtOAAAAAElFTkSuQmCC'
|
||||
iconImg.src = cardboardimg
|
||||
iconImg.className = 'ytp-button';
|
||||
|
||||
// Attach the onclick event to the cardboard icon
|
||||
iconImg.onclick = handleCardboardIconClick;
|
||||
|
||||
const rightControls = document.querySelector('.ytp-right-controls');
|
||||
if (rightControls) {
|
||||
// Append the image to the div element
|
||||
rightControls.appendChild(iconImg);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a MutationObserver to watch for new video elements
|
||||
const observer = new MutationObserver(mutations => {
|
||||
mutations.forEach(mutation => {
|
||||
mutation.addedNodes.forEach(addedNode => {
|
||||
// Check if the added node is a video element
|
||||
if (addedNode instanceof HTMLVideoElement) {
|
||||
addCardboardIconToVideo(addedNode);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Attach the cardboard icon to each video element
|
||||
const videoElements = document.querySelectorAll('video');
|
||||
videoElements.forEach(video => {
|
||||
addCardboardIconToVideo(video);
|
||||
});
|
||||
|
||||
// Start observing the entire document for changes
|
||||
observer.observe(document, { childList: true, subtree: true });
|
||||
|
||||
function EnableVRVideo(videoElement) {
|
||||
console.log("enabling VR on " + videoElement);
|
||||
|
||||
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 2000 );
|
||||
camera.layers.enable( 1 ); // render left view when no stereo available
|
||||
|
||||
const texture = new THREE.VideoTexture(videoElement);
|
||||
texture.colorSpace = THREE.SRGBColorSpace;
|
||||
|
||||
scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color( 0x101010 );
|
||||
|
||||
texture.minFilter = THREE.LinearFilter;
|
||||
texture.magFilter = THREE.LinearFilter;
|
||||
|
||||
// Create the sphere geometry
|
||||
const sphereGeometry = new THREE.SphereGeometry(500, 60, 40);
|
||||
sphereGeometry.scale(-1, 1, 1); // Invert the geometry to match equirectangular projection
|
||||
|
||||
// Create the sphere material
|
||||
const sphereMaterial = new THREE.MeshBasicMaterial({ map: texture });
|
||||
|
||||
// Create the video sphere
|
||||
const videoSphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
|
||||
scene.add(videoSphere);
|
||||
|
||||
renderer = new THREE.WebGLRenderer();
|
||||
renderer.setPixelRatio( window.devicePixelRatio );
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
renderer.xr.enabled = true;
|
||||
renderer.xr.setReferenceSpaceType( 'local' );
|
||||
|
||||
const container = document.querySelector('.html5-video-container')
|
||||
container.appendChild( renderer.domElement );
|
||||
|
||||
// clean alerts box and add VR button
|
||||
const alertsbox = document.querySelector('#alerts')
|
||||
alertsbox.removeChild(alertsbox.firstChild);
|
||||
alertsbox.appendChild( VRButton.createButton( renderer ) );
|
||||
document.querySelector('#VRButton').style.position='relative'
|
||||
|
||||
window.addEventListener( 'resize', onWindowResize );
|
||||
}
|
||||
|
||||
function onWindowResize() {
|
||||
camera.aspect = window.innerWidth / window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
}
|
||||
|
||||
function animate() {
|
||||
renderer.setAnimationLoop( render );
|
||||
}
|
||||
|
||||
function render() {
|
||||
renderer.render( scene, camera );
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "Enable Youtube PC VR in Chromium browsers",
|
||||
"version": "1.0.0",
|
||||
"description": "Enables PC-VR for non-3D spherical youtube videos - Tested on HTC Vive Cosmos",
|
||||
"manifest_version": 3,
|
||||
"author": "feedthedogs",
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": [ "*://*.youtube.com/*",
|
||||
"*://*.googlevideo.com/*"],
|
||||
"js": ["script.js"]
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
"declarativeNetRequest"
|
||||
],
|
||||
"declarative_net_request": {
|
||||
"rule_resources": [
|
||||
{
|
||||
"id": "useagent",
|
||||
"enabled": true,
|
||||
"path": "rules.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"icons": {
|
||||
"128": "icon.png"
|
||||
},
|
||||
"host_permissions": [
|
||||
"*://*.youtube.com/*",
|
||||
"*://*.googlevideo.com/*"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "Enable Youtube PC VR in Chromium",
|
||||
"version": "1.0.0",
|
||||
"description": "Enables PC-VR for non-3D spherical youtube videos - Tested on HTC Vive Cosmos",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "feedthedogs",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"three": "^0.155.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"webpack": "^5.88.2",
|
||||
"webpack-cli": "^5.1.4"
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
[
|
||||
{
|
||||
"id" : 1,
|
||||
"priority": 1,
|
||||
"action": {
|
||||
"type": "modifyHeaders",
|
||||
"requestHeaders": [
|
||||
{ "header": "User-Agent", "operation": "set", "value": "oculusbrowser" }
|
||||
]
|
||||
},
|
||||
"condition" : {
|
||||
"urlFilter" : "|http*",
|
||||
"resourceTypes" : ["script", "main_frame"],
|
||||
"initiatorDomains": [
|
||||
"youtube.com",
|
||||
"googlevideo.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! For license information please see script.js.LICENSE.txt */
|
||||
(()=>{"use strict";const t="155",e=1,n=2,i=3,r=100,a=0,s=1,o=2,l=0,c=1,h=2,u=3,d=4,p=5,f=301,m=302,g=306,_=1e3,v=1001,x=1002,M=1003,S=1005,y=1006,E=1008,T=1009,b=1012,A=1014,w=1015,R=1016,C=1020,L=1023,P=1026,U=1027,D=33776,I=33777,N=33778,O=33779,F=36492,z=2300,B=2301,H=2302,V=3001,G="srgb",k="srgb-linear",W="display-p3",X=7680,j="300 es",q=1035,Y=2e3,K=2001;class Z{addEventListener(t,e){void 0===this._listeners&&(this._listeners={});const n=this._listeners;void 0===n[t]&&(n[t]=[]),-1===n[t].indexOf(e)&&n[t].push(e)}hasEventListener(t,e){if(void 0===this._listeners)return!1;const n=this._listeners;return void 0!==n[t]&&-1!==n[t].indexOf(e)}removeEventListener(t,e){if(void 0===this._listeners)return;const n=this._listeners[t];if(void 0!==n){const t=n.indexOf(e);-1!==t&&n.splice(t,1)}}dispatchEvent(t){if(void 0===this._listeners)return;const e=this._listeners[t.type];if(void 0!==e){t.target=this;const n=e.slice(0);for(let e=0,i=n.length;e<i;e++)n[e].call(this,t);t.target=null}}}const J=["00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f","10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f","20","21","22","23","24","25","26","27","28","29","2a","2b","2c","2d","2e","2f","30","31","32","33","34","35","36","37","38","39","3a","3b","3c","3d","3e","3f","40","41","42","43","44","45","46","47","48","49","4a","4b","4c","4d","4e","4f","50","51","52","53","54","55","56","57","58","59","5a","5b","5c","5d","5e","5f","60","61","62","63","64","65","66","67","68","69","6a","6b","6c","6d","6e","6f","70","71","72","73","74","75","76","77","78","79","7a","7b","7c","7d","7e","7f","80","81","82","83","84","85","86","87","88","89","8a","8b","8c","8d","8e","8f","90","91","92","93","94","95","96","97","98","99","9a","9b","9c","9d","9e","9f","a0","a1","a2","a3","a4","a5","a6","a7","a8","a9","aa","ab","ac","ad","ae","af","b0","b1","b2","b3","b4","b5","b6","b7","b8","b9","ba","bb","bc","bd","be","bf","c0","c1","c2","c3","c4","c5","c6","c7","c8","c9","ca","cb","cc","cd","ce","cf","d0","d1","d2","d3","d4","d5","d6","d7","d8","d9","da","db","dc","dd","de","df","e0","e1","e2","e3","e4","e5","e6","e7","e8","e9","ea","eb","ec","ed","ee","ef","f0","f1","f2","f3","f4","f5","f6","f7","f8","f9","fa","fb","fc","fd","fe","ff"],Q=Math.PI/180,$=180/Math.PI;function tt(){const t=4294967295*Math.random()|0,e=4294967295*Math.random()|0,n=4294967295*Math.random()|0,i=4294967295*Math.random()|0;return(J[255&t]+J[t>>8&255]+J[t>>16&255]+J[t>>24&255]+"-"+J[255&e]+J[e>>8&255]+"-"+J[e>>16&15|64]+J[e>>24&255]+"-"+J[63&n|128]+J[n>>8&255]+"-"+J[n>>16&255]+J[n>>24&255]+J[255&i]+J[i>>8&255]+J[i>>16&255]+J[i>>24&255]).toLowerCase()}function et(t,e,n){return Math.max(e,Math.min(n,t))}function nt(t,e,n){return(1-n)*t+n*e}function it(t){return 0==(t&t-1)&&0!==t}function rt(t){return Math.pow(2,Math.floor(Math.log(t)/Math.LN2))}function at(t,e){switch(e.constructor){case Float32Array:return t;case Uint32Array:return t/4294967295;case Uint16Array:return t/65535;case Uint8Array:return t/255;case Int32Array:return Math.max(t/2147483647,-1);case Int16Array:return Math.max(t/32767,-1);case Int8Array:return Math.max(t/127,-1);default:throw new Error("Invalid component type.")}}function st(t,e){switch(e.constructor){case Float32Array:return t;case Uint32Array:return Math.round(4294967295*t);case Uint16Array:return Math.round(65535*t);case Uint8Array:return Math.round(255*t);case Int32Array:return Math.round(2147483647*t);case Int16Array:return Math.round(32767*t);case Int8Array:return Math.round(127*t);default:throw new Error("Invalid component type.")}}class ot{constructor(t=0,e=0){ot.prototype.isVector2=!0,this.x=t,this.y=e}get width(){return this.x}set width(t){this.x=t}get height(){return this.y}set height(t){this.y=t}set(t,e){return this.x=t,this.y=e,this}setScalar(t){return this.x=t,this.y=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y)}copy(t){return this.x=t.x,this.y=t.y,this}add(t){return this.x+=t.x,this.y+=t.y,this}addScalar(t){return this.x+=t,this.y+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this}subScalar(t){return this.x-=t,this.y-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this}multiply(t){return this.x*=t.x,this.y*=t.y,this}multiplyScalar(t){return this.x*=t,this.y*=t,this}divide(t){return this.x/=t.x,this.y/=t.y,this}divideScalar(t){return this.multiplyScalar(1/t)}applyMatrix3(t){const e=this.x,n=this.y,i=t.elements;return this.x=i[0]*e+i[3]*n+i[6],this.y=i[1]*e+i[4]*n+i[7],this}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.Line truncated
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2010-2023 Three.js Authors
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
@@ -0,0 +1,14 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: './index.js',
|
||||
output: {
|
||||
filename: 'script.js',
|
||||
path: __dirname,
|
||||
},
|
||||
resolve: {
|
||||
fallback: {
|
||||
fs: false
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user