v1.0.0-beta
This commit is contained in:
+69
-21
@@ -5,11 +5,11 @@ const express = require('express');
|
|||||||
const cors = require('cors');
|
const cors = require('cors');
|
||||||
|
|
||||||
const authenticator = (req, res, next) => {
|
const authenticator = (req, res, next) => {
|
||||||
|
res.set('Access-Control-Allow-Origin', ['*']);
|
||||||
if (req.method === 'OPTIONS') {
|
if (req.method === 'OPTIONS') {
|
||||||
res.status(200).send();
|
res.status(200).send();
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = req.headers.authorization.split(' ')[1];
|
const token = req.headers.authorization.split(' ')[1];
|
||||||
const reqToken = token.split(':')[0];
|
const reqToken = token.split(':')[0];
|
||||||
const reqUid = token.split(':')[1];
|
const reqUid = token.split(':')[1];
|
||||||
@@ -97,8 +97,8 @@ const joinRoom = async (req, res) => {
|
|||||||
.doc(bodydata.uid)
|
.doc(bodydata.uid)
|
||||||
.get()
|
.get()
|
||||||
.then((userSnap) => userSnap.exists);
|
.then((userSnap) => userSnap.exists);
|
||||||
if (userExists) return res.status(200).send({ roomId: bodydata.roomId });
|
if (userExists) res.status(200).send({ roomId: bodydata.roomId });
|
||||||
if (exists && bodydata.roomId && bodydata.userName) {
|
else if (!userExists && exists && bodydata.roomId && bodydata.userName) {
|
||||||
await admin
|
await admin
|
||||||
.firestore()
|
.firestore()
|
||||||
.collection('rooms')
|
.collection('rooms')
|
||||||
@@ -124,9 +124,9 @@ const joinRoom = async (req, res) => {
|
|||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
});
|
});
|
||||||
res.status(200).send({ roomId: bodydata.roomId });
|
res.status(200).send({ roomId: bodydata.roomId });
|
||||||
}
|
} else if (!userExists && !bodydata.userName)
|
||||||
if (!bodydata.userName) res.status(400).send('Missing user name');
|
res.status(400).send({ message: 'Missing user name' });
|
||||||
else res.status(404).send('Party Not Found');
|
else res.status(404).send({ message: 'Party Not Found' });
|
||||||
};
|
};
|
||||||
|
|
||||||
const sendMessage = async (req, res) => {
|
const sendMessage = async (req, res) => {
|
||||||
@@ -143,9 +143,10 @@ const sendMessage = async (req, res) => {
|
|||||||
uid,
|
uid,
|
||||||
})
|
})
|
||||||
.catch((messageErr) => res.status(500).send(messageErr));
|
.catch((messageErr) => res.status(500).send(messageErr));
|
||||||
await admin.firestore().collection('rooms').doc(bodydata.roomId).update({
|
await admin.firestore().collection('rooms').doc(roomId).update({
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
});
|
});
|
||||||
|
res.status(200).send({ message: 'Sent a message' });
|
||||||
};
|
};
|
||||||
|
|
||||||
const leaveRoom = async (req, res) => {
|
const leaveRoom = async (req, res) => {
|
||||||
@@ -158,7 +159,7 @@ const leaveRoom = async (req, res) => {
|
|||||||
.doc(req.params.uid)
|
.doc(req.params.uid)
|
||||||
.delete()
|
.delete()
|
||||||
.catch((err) => res.status(500).send(err));
|
.catch((err) => res.status(500).send(err));
|
||||||
res.status(200).send();
|
res.status(200).send({ message: 'Left the party' });
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteRoom = async (req, res) => {
|
const deleteRoom = async (req, res) => {
|
||||||
@@ -179,7 +180,7 @@ const deleteRoom = async (req, res) => {
|
|||||||
});
|
});
|
||||||
if (!isAdmin) {
|
if (!isAdmin) {
|
||||||
console.log('[UNAUTHORIZED] Requested Delete - Room - ', req.params.rid);
|
console.log('[UNAUTHORIZED] Requested Delete - Room - ', req.params.rid);
|
||||||
res.status(401).send();
|
res.status(401).send({ message: 'Not authorized to end this party.' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await admin
|
await admin
|
||||||
@@ -204,11 +205,30 @@ const deleteRoom = async (req, res) => {
|
|||||||
.doc(req.params.rid)
|
.doc(req.params.rid)
|
||||||
.delete()
|
.delete()
|
||||||
.catch((err) => res.status(500).send(err));
|
.catch((err) => res.status(500).send(err));
|
||||||
res.status(200).send();
|
res.status(200).send({ message: 'Ended the party' });
|
||||||
};
|
};
|
||||||
|
|
||||||
const updatePlayer = async (req, res) => {
|
const updatePlayer = async (req, res) => {
|
||||||
const { player, roomId, uid } = JSON.parse(req.body);
|
const { player, roomId, uid, showChanged, userName } = JSON.parse(req.body);
|
||||||
|
const statusString =
|
||||||
|
player.status === 'PLAYING'
|
||||||
|
? 'started playing from'
|
||||||
|
: player.status === 'PAUSED'
|
||||||
|
? 'paused at'
|
||||||
|
: player.status === 'NOT_PLAYING'
|
||||||
|
? 'stopped at'
|
||||||
|
: 'is at';
|
||||||
|
const timeString =
|
||||||
|
player.time > 3600
|
||||||
|
? new Date(player.time * 1000).toISOString().substr(11, 8)
|
||||||
|
: new Date(player.time * 1000).toISOString().substr(14, 5);
|
||||||
|
const [roomExists, roomData] = await admin
|
||||||
|
.firestore()
|
||||||
|
.collection('rooms')
|
||||||
|
.doc(roomId)
|
||||||
|
.get()
|
||||||
|
.then((docSnap) => [docSnap.exists, docSnap.data()]);
|
||||||
|
if (!roomExists) return res.status(404).send({ message: 'Party not found.' });
|
||||||
const userExists = await admin
|
const userExists = await admin
|
||||||
.firestore()
|
.firestore()
|
||||||
.collection('rooms')
|
.collection('rooms')
|
||||||
@@ -218,17 +238,45 @@ const updatePlayer = async (req, res) => {
|
|||||||
.get()
|
.get()
|
||||||
.then((userSnap) => userSnap.exists);
|
.then((userSnap) => userSnap.exists);
|
||||||
if (userExists) {
|
if (userExists) {
|
||||||
await admin
|
if (showChanged === true) {
|
||||||
.firestore()
|
await admin
|
||||||
.collection('rooms')
|
.firestore()
|
||||||
.doc(roomId)
|
.collection('rooms')
|
||||||
.update({
|
.doc(roomId)
|
||||||
player,
|
.collection('messages')
|
||||||
})
|
.add({
|
||||||
.catch((err) => res.status(500).send(err));
|
uid: '<system>',
|
||||||
res.status(200).send();
|
name: '',
|
||||||
|
text: `${userName} changed show to \n${player.showName}`,
|
||||||
|
time: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (roomData.status !== player.status) {
|
||||||
|
await admin
|
||||||
|
.firestore()
|
||||||
|
.collection('rooms')
|
||||||
|
.doc(roomId)
|
||||||
|
.update({
|
||||||
|
player,
|
||||||
|
})
|
||||||
|
.catch((err) => res.status(500).send(err));
|
||||||
|
await admin
|
||||||
|
.firestore()
|
||||||
|
.collection('rooms')
|
||||||
|
.doc(roomId)
|
||||||
|
.collection('messages')
|
||||||
|
.add({
|
||||||
|
uid: '<system>',
|
||||||
|
name: '',
|
||||||
|
text: `${userName} ${statusString} ${timeString}`,
|
||||||
|
time: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
return res.status(200).send({ message: 'Synced party player' });
|
||||||
|
} else {
|
||||||
|
return res.status(208).send({ message: 'Player already up to date' });
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(401).send('Not in room to sync');
|
return res.status(401).send('Not in room to sync');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "functions",
|
"name": "watchparty",
|
||||||
"description": "Cloud Functions for Firebase",
|
"version": "1.0.0-beta",
|
||||||
|
"description": "Cloud Functions for Watch Party",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"serve": "firebase emulators:start --only functions",
|
"serve": "firebase emulators:start --only functions",
|
||||||
|
|||||||
+115
-6
@@ -1,8 +1,117 @@
|
|||||||
// Called when the user clicks on the browser action
|
/* global chrome */
|
||||||
chrome.browserAction.onClicked.addListener(function(tab) {
|
/*global firebase*/
|
||||||
// Send a message to the active tab
|
|
||||||
chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
|
const firebaseConfig = {
|
||||||
var activeTab = tabs[0];
|
apiKey: 'AIzaSyCJLuYpzXLDRmu2ttzFuSGmYcpFxqToWFU',
|
||||||
chrome.tabs.sendMessage(activeTab.id, { message: 'clicked_browser_action' });
|
authDomain: 'watch-party-crx.firebaseapp.com',
|
||||||
|
databaseURL: 'https://watch-party-crx.firebaseio.com',
|
||||||
|
projectId: 'watch-party-crx',
|
||||||
|
storageBucket: 'watch-party-crx.appspot.com',
|
||||||
|
messagingSenderId: '712242707190',
|
||||||
|
appId: '1:712242707190:web:65fa7f772e30da364b0ad7',
|
||||||
|
measurementId: 'G-EZS4PEVG4T',
|
||||||
|
};
|
||||||
|
|
||||||
|
firebase.initializeApp(firebaseConfig);
|
||||||
|
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL);
|
||||||
|
|
||||||
|
const isAuthed = () => true && firebase.auth().currentUser;
|
||||||
|
const doAuth = () => firebase.auth().signInAnonymously();
|
||||||
|
|
||||||
|
const fetcher = async (request, sendResponse) => {
|
||||||
|
if (!isAuthed()) await doAuth();
|
||||||
|
const { url, method } = request;
|
||||||
|
delete request.type;
|
||||||
|
delete request.url;
|
||||||
|
delete request.method;
|
||||||
|
const idToken = await firebase.auth().currentUser.getIdToken();
|
||||||
|
let resStatus = {};
|
||||||
|
fetch(url, {
|
||||||
|
method,
|
||||||
|
headers: {
|
||||||
|
Authorization: `Token ${idToken}:${firebase.auth().currentUser.uid}`,
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
},
|
||||||
|
...request,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
resStatus = {
|
||||||
|
status: res.status,
|
||||||
|
statusText: res.statusText,
|
||||||
|
};
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.then((res) => sendResponse({ ...res, ...resStatus }))
|
||||||
|
.catch((err) => sendResponse({ ...err, status: 503, statusText: "Couldn't talk to server" }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const sendAuth = async (sendResponse) => {
|
||||||
|
if (!isAuthed()) await doAuth();
|
||||||
|
sendResponse(firebase.auth().currentUser);
|
||||||
|
};
|
||||||
|
|
||||||
|
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||||
|
const { type } = request;
|
||||||
|
switch (type) {
|
||||||
|
case 'API_CALL':
|
||||||
|
fetcher(request, sendResponse);
|
||||||
|
break;
|
||||||
|
case 'GET_AUTH':
|
||||||
|
sendAuth(sendResponse);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn('Unknown message type: <', type, '>');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
chrome.runtime.onConnect.addListener((port) => {
|
||||||
|
port.onDisconnect.addListener(() => {});
|
||||||
|
port.onMessage.addListener((request) => {
|
||||||
|
const { type, roomId } = request;
|
||||||
|
if (type === 'INIT') {
|
||||||
|
firebase
|
||||||
|
.firestore()
|
||||||
|
.collection('rooms')
|
||||||
|
.doc(roomId)
|
||||||
|
.onSnapshot(
|
||||||
|
(snap) => {
|
||||||
|
if (snap) {
|
||||||
|
port.postMessage(snap.data());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(err) => {}
|
||||||
|
);
|
||||||
|
firebase
|
||||||
|
.firestore()
|
||||||
|
.collection('rooms')
|
||||||
|
.doc(roomId)
|
||||||
|
.collection('users')
|
||||||
|
.onSnapshot(
|
||||||
|
(snap) => {
|
||||||
|
if (snap) {
|
||||||
|
const isAdmin = snap.docs
|
||||||
|
.filter((user) => user.id === firebase.auth().currentUser.uid)[0]
|
||||||
|
.data().admin;
|
||||||
|
port.postMessage({ admin: isAdmin });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(err) => {}
|
||||||
|
);
|
||||||
|
firebase
|
||||||
|
.firestore()
|
||||||
|
.collection('rooms')
|
||||||
|
.doc(roomId)
|
||||||
|
.collection('messages')
|
||||||
|
.orderBy('time')
|
||||||
|
.onSnapshot(
|
||||||
|
(snap) => {
|
||||||
|
if (snap)
|
||||||
|
port.postMessage({ messages: snap.docs.map((v) => ({ ...v.data(), id: v.id })) });
|
||||||
|
},
|
||||||
|
(err) => {}
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "WatchParty",
|
"name": "WatchParty",
|
||||||
"short_name": "WP",
|
"short_name": "WP",
|
||||||
"version": "1.0",
|
"version": "1.0.0",
|
||||||
"description": "Watch streamed content together.",
|
"description": "Watch streamed content together.",
|
||||||
"background": {
|
"background": {
|
||||||
"scripts": ["background.js"]
|
"page": "popup.html"
|
||||||
},
|
|
||||||
"browser_action": {
|
|
||||||
"default_popup": "popup.html"
|
|
||||||
},
|
},
|
||||||
"permissions": ["https://*.hulu.com/*", "https://*.netflix.com/*", "https://*.amazon.com/*"],
|
"permissions": ["https://*.hulu.com/*", "https://*.netflix.com/*", "https://*.amazon.com/*"],
|
||||||
|
"content_security_policy": "script-src 'self' https://www.gstatic.com/ https://*.firebaseio.com https://www.googleapis.com; object-src 'self'",
|
||||||
"content_scripts": [
|
"content_scripts": [
|
||||||
{
|
{
|
||||||
"matches": ["https://*.hulu.com/*"],
|
"matches": ["https://*.hulu.com/*"],
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta
|
||||||
|
http-equiv="Content-Security-Policy"
|
||||||
|
content="default-src *; style-src 'self' https://* 'unsafe-inline'; script-src 'self' http://* 'unsafe-inline' 'unsafe-eval'"
|
||||||
|
/>
|
||||||
<style>
|
<style>
|
||||||
html {
|
html {
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
@@ -39,6 +43,10 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<script src="https://www.gstatic.com/firebasejs/7.14.1/firebase-app.js"></script>
|
||||||
|
<script src="https://www.gstatic.com/firebasejs/7.14.1/firebase-auth.js"></script>
|
||||||
|
<script src="https://www.gstatic.com/firebasejs/7.14.1/firebase-firestore.js"></script>
|
||||||
|
<script src="background.js"></script>
|
||||||
<a target="_blank" href="https://www.hulu.com/">Hulu</a>
|
<a target="_blank" href="https://www.hulu.com/">Hulu</a>
|
||||||
<a target="_blank" href="https://www.netflix.com/browse">Netflix</a>
|
<a target="_blank" href="https://www.netflix.com/browse">Netflix</a>
|
||||||
<a target="_blank" href="https://www.amazon.com/gp/video/storefront">Prime Video</a>
|
<a target="_blank" href="https://www.amazon.com/gp/video/storefront">Prime Video</a>
|
||||||
|
|||||||
+45
-36
@@ -1,5 +1,4 @@
|
|||||||
import firebase from 'firebase/app';
|
/*global chrome*/
|
||||||
import 'firebase/auth';
|
|
||||||
|
|
||||||
const API_HOST = window.location.href.startsWith('http://localhost')
|
const API_HOST = window.location.href.startsWith('http://localhost')
|
||||||
? 'http://localhost:5001/watch-party-crx/us-central1/widgets'
|
? 'http://localhost:5001/watch-party-crx/us-central1/widgets'
|
||||||
@@ -26,70 +25,80 @@ export const getPlayerSource = () => {
|
|||||||
if (HREF.startsWith(PLAYER_SOURCE.LOCAL)) return PLAYER_SOURCE.LOCAL;
|
if (HREF.startsWith(PLAYER_SOURCE.LOCAL)) return PLAYER_SOURCE.LOCAL;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isAuthed = () => true && firebase.auth().currentUser;
|
export const getUserUid = async () =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
export const doAuth = () => firebase.auth().signInAnonymously();
|
chrome.runtime.sendMessage(
|
||||||
|
{
|
||||||
export const fetcher = async ({ ENDPOINT, METHOD, ...args }) => {
|
type: 'GET_AUTH',
|
||||||
const idToken = await firebase.auth().currentUser.getIdToken();
|
},
|
||||||
return fetch(`${API_HOST}/${ENDPOINT}`, {
|
(response) => {
|
||||||
method: METHOD,
|
const { uid } = response;
|
||||||
headers: {
|
window.localStorage.setItem('watchPartyUserUid', uid);
|
||||||
Authorization: `Token ${idToken}:${firebase.auth().currentUser.uid}`,
|
resolve(uid);
|
||||||
},
|
}
|
||||||
...args,
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const fetcher = async ({ endpoint, method, ...args }) => {
|
||||||
|
const url = `${API_HOST}/${endpoint}`;
|
||||||
|
return new Promise((resolve, reject) =>
|
||||||
|
chrome.runtime.sendMessage(
|
||||||
|
{
|
||||||
|
type: 'API_CALL',
|
||||||
|
url,
|
||||||
|
method,
|
||||||
|
...args,
|
||||||
|
},
|
||||||
|
(response) => {
|
||||||
|
if (response.status > 299) reject(response);
|
||||||
|
else resolve({ json: () => response });
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CreateRoomApi = async (data) => {
|
export const CreateRoomApi = async (data) => {
|
||||||
if (!isAuthed()) await doAuth();
|
|
||||||
return fetcher({
|
return fetcher({
|
||||||
ENDPOINT: 'create',
|
endpoint: 'create',
|
||||||
METHOD: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const JoinRoomApi = async (data) => {
|
export const JoinRoomApi = async (data) => {
|
||||||
if (!isAuthed()) await doAuth();
|
|
||||||
return fetcher({
|
return fetcher({
|
||||||
ENDPOINT: 'join',
|
endpoint: 'join',
|
||||||
METHOD: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SendMessageApi = async (data) => {
|
export const SendMessageApi = async (data) => {
|
||||||
if (!isAuthed()) await doAuth();
|
|
||||||
return fetcher({
|
return fetcher({
|
||||||
ENDPOINT: 'message',
|
endpoint: 'message',
|
||||||
METHOD: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LeaveRoomApi = async (data) => {
|
export const LeaveRoomApi = async (data) => {
|
||||||
if (!isAuthed()) await doAuth();
|
|
||||||
return fetcher({
|
return fetcher({
|
||||||
ENDPOINT: `leave/${data.roomId}/users/${data.uid}`,
|
endpoint: `leave/${data.roomId}/users/${data.uid}`,
|
||||||
METHOD: 'DELETE',
|
method: 'DELETE',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DeleteRoomApi = async (data) => {
|
export const DeleteRoomApi = async (data) => {
|
||||||
if (!isAuthed()) await doAuth();
|
|
||||||
return fetcher({
|
return fetcher({
|
||||||
ENDPOINT: `delete/${data.roomId}`,
|
endpoint: `delete/${data.roomId}`,
|
||||||
METHOD: 'DELETE',
|
method: 'DELETE',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const UpdatePlayerApi = async (data) => {
|
export const UpdatePlayerApi = async (data) => {
|
||||||
if (isAuthed()) {
|
return fetcher({
|
||||||
return fetcher({
|
endpoint: 'updatePlayer',
|
||||||
ENDPOINT: 'updatePlayer',
|
method: 'POST',
|
||||||
METHOD: 'POST',
|
body: JSON.stringify(data),
|
||||||
body: JSON.stringify(data),
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import Loading from './Loading';
|
|||||||
import firebase from 'firebase/app';
|
import firebase from 'firebase/app';
|
||||||
import 'firebase/firestore';
|
import 'firebase/firestore';
|
||||||
import Inactive from './Inactive';
|
import Inactive from './Inactive';
|
||||||
|
import { getUserUid } from './Api';
|
||||||
|
|
||||||
const darkTheme = createMuiTheme({
|
const darkTheme = createMuiTheme({
|
||||||
palette: {
|
palette: {
|
||||||
@@ -32,6 +33,7 @@ const App = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
getUserUid();
|
||||||
firebase
|
firebase
|
||||||
.firestore()
|
.firestore()
|
||||||
.collection('server')
|
.collection('server')
|
||||||
|
|||||||
+63
-62
@@ -1,3 +1,4 @@
|
|||||||
|
/*global chrome */
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import {
|
import {
|
||||||
Typography,
|
Typography,
|
||||||
@@ -7,16 +8,19 @@ import {
|
|||||||
ButtonGroup,
|
ButtonGroup,
|
||||||
Button,
|
Button,
|
||||||
} from '@material-ui/core';
|
} from '@material-ui/core';
|
||||||
import firebase from 'firebase/app';
|
|
||||||
import 'firebase/firestore';
|
|
||||||
import 'firebase/auth';
|
|
||||||
import Thread from './Thread';
|
import Thread from './Thread';
|
||||||
import Send from '@material-ui/icons/SendRounded';
|
import Send from '@material-ui/icons/SendRounded';
|
||||||
import Sync from '@material-ui/icons/SyncOutlined';
|
|
||||||
import Exit from '@material-ui/icons/ExitToAppRounded';
|
import Exit from '@material-ui/icons/ExitToAppRounded';
|
||||||
import Share from '@material-ui/icons/ShareRounded';
|
import Share from '@material-ui/icons/ShareRounded';
|
||||||
import Delete from '@material-ui/icons/Delete';
|
import Delete from '@material-ui/icons/Delete';
|
||||||
import { SendMessageApi, LeaveRoomApi, DeleteRoomApi, UpdatePlayerApi } from './Api';
|
import {
|
||||||
|
SendMessageApi,
|
||||||
|
LeaveRoomApi,
|
||||||
|
DeleteRoomApi,
|
||||||
|
UpdatePlayerApi,
|
||||||
|
getPlayerSource,
|
||||||
|
PLAYER_STATUS,
|
||||||
|
} from './Api';
|
||||||
import { goTo } from 'route-lite';
|
import { goTo } from 'route-lite';
|
||||||
import Create from './Create';
|
import Create from './Create';
|
||||||
import VideoListener from './VideoListener';
|
import VideoListener from './VideoListener';
|
||||||
@@ -28,7 +32,7 @@ export default class Chat extends Component {
|
|||||||
name: '',
|
name: '',
|
||||||
messages: [],
|
messages: [],
|
||||||
newMessage: '',
|
newMessage: '',
|
||||||
admin: false,
|
admin: null,
|
||||||
player: {},
|
player: {},
|
||||||
localPlayer: {},
|
localPlayer: {},
|
||||||
};
|
};
|
||||||
@@ -36,73 +40,74 @@ export default class Chat extends Component {
|
|||||||
this.endParty = this.endParty.bind(this);
|
this.endParty = this.endParty.bind(this);
|
||||||
this.leaveParty = this.leaveParty.bind(this);
|
this.leaveParty = this.leaveParty.bind(this);
|
||||||
this.shareParty = this.shareParty.bind(this);
|
this.shareParty = this.shareParty.bind(this);
|
||||||
|
this.syncPlayer = this.syncPlayer.bind(this);
|
||||||
this.videoEventListener = this.videoEventListener.bind(this);
|
this.videoEventListener = this.videoEventListener.bind(this);
|
||||||
this.mVideoListener = new VideoListener(this.videoEventListener);
|
this.mVideoListener = new VideoListener(this.videoEventListener);
|
||||||
|
this.port = null;
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
window.addEventListener('keyup', (ev) => {
|
window.onkeypress = (ev) => {
|
||||||
if (ev.code === 'Enter') {
|
if (ev.code === 'Enter') {
|
||||||
if (ev.target === document.getElementById('chat-message-box-input')) {
|
if (ev.target === document.getElementById('chat-message-box-input')) {
|
||||||
if (ev.shiftKey === false) {
|
if (ev.shiftKey === false) {
|
||||||
|
ev.preventDefault();
|
||||||
const trim = this.state.newMessage.replace(/^\s+|\s+$/g, '');
|
const trim = this.state.newMessage.replace(/^\s+|\s+$/g, '');
|
||||||
if (trim !== '') this.sendMessage(trim);
|
if (trim !== '') this.sendMessage(trim);
|
||||||
this.setState({ newMessage: '' });
|
this.setState({ newMessage: '' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
this.port = chrome.runtime.connect({ name: window.localStorage.getItem('watchPartyRoomId') });
|
||||||
|
this.port.postMessage({
|
||||||
|
type: 'INIT',
|
||||||
|
roomId: window.localStorage.getItem('watchPartyRoomId'),
|
||||||
|
});
|
||||||
|
this.port.onMessage.addListener((response) => {
|
||||||
|
this.setState(response);
|
||||||
|
if (response.player && this.state.localPlayer.status !== response.player.status) {
|
||||||
|
if (response.player.source !== getPlayerSource()) {
|
||||||
|
this.props.updateLoading(true);
|
||||||
|
this.props.notify('This party is for a different website');
|
||||||
|
goTo(Create, this.props);
|
||||||
|
this.props.updateLoading(false);
|
||||||
|
} else {
|
||||||
|
if (this.mVideoListener.isUpdating === false)
|
||||||
|
this.mVideoListener.doUpdate(response.player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const pcc = document.getElementsByClassName('thread-container')[0];
|
||||||
|
if (pcc) pcc.scrollTop = pcc.scrollHeight;
|
||||||
});
|
});
|
||||||
firebase
|
|
||||||
.firestore()
|
|
||||||
.collection('rooms')
|
|
||||||
.doc(window.localStorage.getItem('watchPartyRoomId'))
|
|
||||||
.onSnapshot(
|
|
||||||
(snap) => {
|
|
||||||
if (snap.data().player.status !== this.state.localPlayer.status) {
|
|
||||||
this.mVideoListener.doUpdate(snap.data().player);
|
|
||||||
}
|
|
||||||
this.setState(snap.data());
|
|
||||||
},
|
|
||||||
(err) => {}
|
|
||||||
);
|
|
||||||
firebase
|
|
||||||
.firestore()
|
|
||||||
.collection('rooms')
|
|
||||||
.doc(window.localStorage.getItem('watchPartyRoomId'))
|
|
||||||
.collection('users')
|
|
||||||
.onSnapshot((snap) => {
|
|
||||||
const isAdmin = snap.docs
|
|
||||||
.filter((user) => user.id === firebase.auth().currentUser.uid)[0]
|
|
||||||
.data().admin;
|
|
||||||
this.setState({ admin: isAdmin });
|
|
||||||
});
|
|
||||||
firebase
|
|
||||||
.firestore()
|
|
||||||
.collection('rooms')
|
|
||||||
.doc(window.localStorage.getItem('watchPartyRoomId'))
|
|
||||||
.collection('messages')
|
|
||||||
.orderBy('time')
|
|
||||||
.onSnapshot((snap) => {
|
|
||||||
this.setState({ messages: snap.docs.map((v) => ({ ...v.data(), id: v.id })) });
|
|
||||||
const pcc = document.getElementsByClassName('thread-container')[0];
|
|
||||||
if (pcc) pcc.scrollTop = pcc.scrollHeight;
|
|
||||||
});
|
|
||||||
this.mVideoListener.start();
|
this.mVideoListener.start();
|
||||||
this.props.updateLoading(false);
|
this.props.updateLoading(false);
|
||||||
}
|
}
|
||||||
videoEventListener(video) {
|
videoEventListener(video) {
|
||||||
const { status, url, time, source } = video;
|
this.setState({ localPlayer: video });
|
||||||
if (this.state.player.status !== status) {
|
if (
|
||||||
|
this.state.player.status !== video.status &&
|
||||||
|
video.showName &&
|
||||||
|
video.status !== PLAYER_STATUS.NOT_PLAYING
|
||||||
|
)
|
||||||
|
this.syncPlayer(video);
|
||||||
|
}
|
||||||
|
syncPlayer(video) {
|
||||||
|
const { status, showName, time, source, element } = video;
|
||||||
|
if (element) {
|
||||||
UpdatePlayerApi({
|
UpdatePlayerApi({
|
||||||
roomId: window.localStorage.getItem('watchPartyRoomId'),
|
roomId: window.localStorage.getItem('watchPartyRoomId'),
|
||||||
|
showChanged: showName !== this.state.player.showName,
|
||||||
|
userName: window.localStorage.getItem('watchPartyUserName'),
|
||||||
player: {
|
player: {
|
||||||
status,
|
status: showName !== this.state.player.showName ? PLAYER_STATUS.PAUSED : status,
|
||||||
url,
|
showName,
|
||||||
time,
|
time,
|
||||||
source,
|
source,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
this.mVideoListener.start();
|
||||||
}
|
}
|
||||||
this.setState({ localPlayer: video });
|
|
||||||
}
|
}
|
||||||
endParty() {
|
endParty() {
|
||||||
this.props.notify('Ending party...');
|
this.props.notify('Ending party...');
|
||||||
@@ -111,11 +116,10 @@ export default class Chat extends Component {
|
|||||||
roomId: window.localStorage.getItem('watchPartyRoomId'),
|
roomId: window.localStorage.getItem('watchPartyRoomId'),
|
||||||
};
|
};
|
||||||
DeleteRoomApi(data).then((res) => {
|
DeleteRoomApi(data).then((res) => {
|
||||||
if (res.status === 200) {
|
this.props.notify('Ended party');
|
||||||
this.props.notify('Ended party');
|
window.localStorage.removeItem('watchPartyRoomId');
|
||||||
window.localStorage.removeItem('watchPartyRoomId');
|
goTo(Create, this.props);
|
||||||
goTo(Create, this.props);
|
this.props.updateLoading(false);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
leaveParty() {
|
leaveParty() {
|
||||||
@@ -123,14 +127,13 @@ export default class Chat extends Component {
|
|||||||
this.props.updateLoading(true);
|
this.props.updateLoading(true);
|
||||||
const data = {
|
const data = {
|
||||||
roomId: window.localStorage.getItem('watchPartyRoomId'),
|
roomId: window.localStorage.getItem('watchPartyRoomId'),
|
||||||
uid: firebase.auth().currentUser.uid,
|
uid: window.localStorage.getItem('watchPartyUserUid'),
|
||||||
};
|
};
|
||||||
LeaveRoomApi(data).then((res) => {
|
LeaveRoomApi(data).then((res) => {
|
||||||
if (res.status === 200) {
|
this.props.notify('Left party');
|
||||||
this.props.notify('Left party');
|
window.localStorage.removeItem('watchPartyRoomId');
|
||||||
window.localStorage.removeItem('watchPartyRoomId');
|
goTo(Create, this.props);
|
||||||
goTo(Create, this.props);
|
this.props.updateLoading(false);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
shareParty() {
|
shareParty() {
|
||||||
@@ -146,7 +149,7 @@ export default class Chat extends Component {
|
|||||||
const data = {
|
const data = {
|
||||||
roomId: window.localStorage.getItem('watchPartyRoomId'),
|
roomId: window.localStorage.getItem('watchPartyRoomId'),
|
||||||
name: window.localStorage.getItem('watchPartyUserName'),
|
name: window.localStorage.getItem('watchPartyUserName'),
|
||||||
uid: firebase.auth().currentUser.uid,
|
uid: window.localStorage.getItem('watchPartyUserUid'),
|
||||||
text: message,
|
text: message,
|
||||||
time: new Date().toISOString(),
|
time: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
@@ -166,7 +169,6 @@ export default class Chat extends Component {
|
|||||||
<Button onClick={this.shareParty} startIcon={<Share />}>
|
<Button onClick={this.shareParty} startIcon={<Share />}>
|
||||||
Share
|
Share
|
||||||
</Button>
|
</Button>
|
||||||
<Button startIcon={<Sync />}>Sync</Button>
|
|
||||||
<Button onClick={this.leaveParty} startIcon={<Exit />}>
|
<Button onClick={this.leaveParty} startIcon={<Exit />}>
|
||||||
Leave
|
Leave
|
||||||
</Button>
|
</Button>
|
||||||
@@ -180,13 +182,12 @@ export default class Chat extends Component {
|
|||||||
<Thread messages={messages} />
|
<Thread messages={messages} />
|
||||||
</div>
|
</div>
|
||||||
<TextField
|
<TextField
|
||||||
onSubmit={(e) => console.log(e)}
|
|
||||||
multiline
|
multiline
|
||||||
rowsMax="3"
|
rowsMax="3"
|
||||||
size="small"
|
size="small"
|
||||||
placeholder="New message... (<Enter> to send)"
|
placeholder="New message... (<Enter> to send)"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
className="chat-message-box"
|
className="chat-message-box addFocus"
|
||||||
value={newMessage}
|
value={newMessage}
|
||||||
onChange={(e) => this.setState({ newMessage: e.target.value })}
|
onChange={(e) => this.setState({ newMessage: e.target.value })}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
|
|||||||
+23
-31
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
@@ -38,10 +38,10 @@ const joinRoom = async (data) => {
|
|||||||
.then((res) => res.roomId)
|
.then((res) => res.roomId)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
data.props.updateLoading(false);
|
data.props.updateLoading(false);
|
||||||
data.props.notify('Something went wrong');
|
data.props.notify(err.statusText);
|
||||||
console.error('Join Room API error', err);
|
console.error('Join Room API error', err);
|
||||||
});
|
});
|
||||||
if (confirmedRoomId === apidata.roomId) {
|
if (confirmedRoomId && confirmedRoomId === apidata.roomId) {
|
||||||
saveName({
|
saveName({
|
||||||
name: apidata.userName,
|
name: apidata.userName,
|
||||||
notify: data.props.notify,
|
notify: data.props.notify,
|
||||||
@@ -73,21 +73,26 @@ const createRoom = async (data) => {
|
|||||||
CreateRoomApi(apidata)
|
CreateRoomApi(apidata)
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
saveName({
|
if (res.status <= 299) {
|
||||||
name: data.name,
|
saveName({
|
||||||
notify: data.props.notify,
|
name: data.name,
|
||||||
});
|
notify: data.props.notify,
|
||||||
saveRoomId({
|
});
|
||||||
rid: res.roomId,
|
saveRoomId({
|
||||||
notify: data.props.notify,
|
rid: res.roomId,
|
||||||
});
|
notify: data.props.notify,
|
||||||
data.props.notify('Started party');
|
});
|
||||||
goTo(Chat, data.props);
|
data.props.notify('Started party');
|
||||||
|
goTo(Chat, data.props);
|
||||||
|
} else {
|
||||||
|
data.props.updateLoading(false);
|
||||||
|
data.props.notify(res.statusText);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
data.props.updateLoading(false);
|
data.props.updateLoading(false);
|
||||||
data.props.notify('Something went wrong');
|
data.props.notify(err.statusText);
|
||||||
console.error('Join Room API error', err);
|
console.error('Create Room API error', err);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -95,20 +100,7 @@ const Create = (props) => {
|
|||||||
const [name, setName] = useState(getName() || '');
|
const [name, setName] = useState(getName() || '');
|
||||||
const [createName, setCreateName] = useState('');
|
const [createName, setCreateName] = useState('');
|
||||||
const [joinName, setJoinName] = useState(getRoomId() || '');
|
const [joinName, setJoinName] = useState(getRoomId() || '');
|
||||||
const { notify, updateLoading } = props;
|
const { notify } = props;
|
||||||
|
|
||||||
const joinOnMount = () => {
|
|
||||||
updateLoading(false);
|
|
||||||
// NEEDS FIX - REPETITIVE API CALLS
|
|
||||||
// if (getName() && getRoomId()) {
|
|
||||||
// joinRoom({
|
|
||||||
// joinName,
|
|
||||||
// name,
|
|
||||||
// props,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
};
|
|
||||||
useEffect(joinOnMount, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="party-create-container">
|
<div className="party-create-container">
|
||||||
@@ -140,7 +132,7 @@ const Create = (props) => {
|
|||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
value={createName}
|
value={createName}
|
||||||
className="card-field"
|
className="card-field addFocus"
|
||||||
onChange={(e) => setCreateName(e.target.value)}
|
onChange={(e) => setCreateName(e.target.value)}
|
||||||
label="Party Name"
|
label="Party Name"
|
||||||
/>
|
/>
|
||||||
@@ -162,7 +154,7 @@ const Create = (props) => {
|
|||||||
color="secondary"
|
color="secondary"
|
||||||
fullWidth
|
fullWidth
|
||||||
value={joinName}
|
value={joinName}
|
||||||
className="card-field"
|
className="card-field addFocus"
|
||||||
onChange={(e) => setJoinName(e.target.value)}
|
onChange={(e) => setJoinName(e.target.value)}
|
||||||
label="Party Name"
|
label="Party Name"
|
||||||
/>
|
/>
|
||||||
|
|||||||
+2
-3
@@ -1,18 +1,17 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Typography } from '@material-ui/core';
|
import { Typography } from '@material-ui/core';
|
||||||
import './Thread.css';
|
import './Thread.css';
|
||||||
import firebase from 'firebase/app';
|
|
||||||
import 'firebase/auth';
|
|
||||||
|
|
||||||
const Thread = (props) =>
|
const Thread = (props) =>
|
||||||
props.messages.map((m, midx) => {
|
props.messages.map((m, midx) => {
|
||||||
|
const userUid = window.localStorage.getItem('watchPartyUserUid');
|
||||||
if (m.uid === '<system>') {
|
if (m.uid === '<system>') {
|
||||||
return (
|
return (
|
||||||
<Typography variant="body2" className="thread-item system-message" key={m.id} disabled>
|
<Typography variant="body2" className="thread-item system-message" key={m.id} disabled>
|
||||||
{m.text}
|
{m.text}
|
||||||
</Typography>
|
</Typography>
|
||||||
);
|
);
|
||||||
} else if (m.uid === firebase.auth().currentUser.uid) {
|
} else if (m.uid === userUid) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`thread-item ${
|
className={`thread-item ${
|
||||||
|
|||||||
+75
-44
@@ -7,7 +7,7 @@ export default class VideoListener {
|
|||||||
this.video = {
|
this.video = {
|
||||||
status: PLAYER_STATUS.NOT_PLAYING,
|
status: PLAYER_STATUS.NOT_PLAYING,
|
||||||
time: 0,
|
time: 0,
|
||||||
url: '',
|
showName: '',
|
||||||
source: '',
|
source: '',
|
||||||
element: null,
|
element: null,
|
||||||
};
|
};
|
||||||
@@ -16,23 +16,57 @@ export default class VideoListener {
|
|||||||
this.firstTimeSync = this.firstTimeSync.bind(this);
|
this.firstTimeSync = this.firstTimeSync.bind(this);
|
||||||
this.doUpdate = this.doUpdate.bind(this);
|
this.doUpdate = this.doUpdate.bind(this);
|
||||||
this.start = this.start.bind(this);
|
this.start = this.start.bind(this);
|
||||||
|
this.isUpdating = false;
|
||||||
}
|
}
|
||||||
updateStatus(newStatus) {
|
updateStatus(newStatus) {
|
||||||
this.video = Object.assign({}, this.video, newStatus);
|
if (this.isUpdating === false && newStatus.status !== this.video.status) {
|
||||||
this.listener(this.video);
|
this.isUpdating = true;
|
||||||
|
this.video = Object.assign({}, this.video, newStatus);
|
||||||
|
this.listener(this.video);
|
||||||
|
this.isUpdating = false;
|
||||||
|
} else return;
|
||||||
}
|
}
|
||||||
doUpdate(serverPlayer) {
|
doUpdate(serverPlayer) {
|
||||||
if (this.video.element) this.video.element.currentTime = serverPlayer.time;
|
if (this.video.element && this.video.status !== serverPlayer.status) {
|
||||||
switch (serverPlayer.status) {
|
switch (serverPlayer.status) {
|
||||||
case PLAYER_STATUS.PAUSED:
|
case PLAYER_STATUS.PAUSED:
|
||||||
if (this.video.element) this.video.element.pause();
|
this.video.element.pause();
|
||||||
break;
|
break;
|
||||||
case PLAYER_STATUS.NOT_PLAYING:
|
case PLAYER_STATUS.NOT_PLAYING:
|
||||||
if (this.video.element) this.video.element.pause();
|
this.video.element.pause();
|
||||||
break;
|
break;
|
||||||
case PLAYER_STATUS.PLAYING:
|
case PLAYER_STATUS.PLAYING:
|
||||||
if (this.video.element) this.video.element.play();
|
this.video.element.play();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getShowName() {
|
||||||
|
switch (this.video.source) {
|
||||||
|
case PLAYER_SOURCE.NETFLIX:
|
||||||
|
const titleContainerParent = document.querySelector(
|
||||||
|
'.PlayerControls--control-element.text-control.video-title'
|
||||||
|
);
|
||||||
|
if (titleContainerParent) {
|
||||||
|
const titleContainer = titleContainerParent.firstChild;
|
||||||
|
const nshow = titleContainer.querySelector('h4').innerHTML;
|
||||||
|
let nepisode = '';
|
||||||
|
titleContainer.querySelectorAll('span').forEach((e) => {
|
||||||
|
if (e.innerHTML) nepisode += e.innerHTML + ' ';
|
||||||
|
});
|
||||||
|
return nshow + '\n' + nepisode;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
case PLAYER_SOURCE.AMAZON:
|
||||||
|
const ashow = document.querySelector('.f3w9jrr.ff48h02').firstChild.innerHTML;
|
||||||
|
const aepisode = document.querySelector('.f3w9jrr.ff48h02').lastChild.innerHTML;
|
||||||
|
return ashow !== '' && aepisode !== '' ? ashow + '\n' + aepisode : null;
|
||||||
|
case PLAYER_SOURCE.HULU:
|
||||||
|
const hshow = document.querySelector('.metadata-area__second-line').innerHTML;
|
||||||
|
const hepisode = document.querySelector('.metadata-area__third-line').innerHTML;
|
||||||
|
return hshow !== '' && hepisode !== '' ? hshow + '\n' + hepisode : null;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -40,6 +74,7 @@ export default class VideoListener {
|
|||||||
firstTimeSync(videoElement) {
|
firstTimeSync(videoElement) {
|
||||||
this.updateStatus({
|
this.updateStatus({
|
||||||
element: videoElement,
|
element: videoElement,
|
||||||
|
showName: this.getShowName(),
|
||||||
});
|
});
|
||||||
if (videoElement.paused) {
|
if (videoElement.paused) {
|
||||||
this.updateStatus({
|
this.updateStatus({
|
||||||
@@ -54,17 +89,24 @@ export default class VideoListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
videoElement.onplaying = (ev) => {
|
videoElement.onplaying = (ev) => {
|
||||||
this.updateStatus({ status: PLAYER_STATUS.PLAYING, time: ev.timeStamp });
|
this.updateStatus({
|
||||||
if (this.video.url === '') this.updateStatus({ url: window.location.href });
|
status: PLAYER_STATUS.PLAYING,
|
||||||
|
time: videoElement.currentTime,
|
||||||
|
showName: this.getShowName(),
|
||||||
|
});
|
||||||
};
|
};
|
||||||
videoElement.onpause = (ev) =>
|
videoElement.onpause = (ev) =>
|
||||||
this.updateStatus({ status: PLAYER_STATUS.PAUSED, time: ev.timeStamp });
|
this.updateStatus({
|
||||||
|
status: PLAYER_STATUS.PAUSED,
|
||||||
|
time: videoElement.currentTime,
|
||||||
|
showName: this.getShowName(),
|
||||||
|
});
|
||||||
videoElement.onended = (ev) => {
|
videoElement.onended = (ev) => {
|
||||||
this.updateStatus({ status: PLAYER_STATUS.NOT_PLAYING, url: '', time: 0 });
|
this.updateStatus({ status: PLAYER_STATUS.NOT_PLAYING, showName: '', time: 0 });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
start() {
|
start() {
|
||||||
this.updateStatus({ source: getPlayerSource(), url: window.location.href });
|
this.updateStatus({ source: getPlayerSource(), showName: this.getShowName() });
|
||||||
switch (this.video.source) {
|
switch (this.video.source) {
|
||||||
case PLAYER_SOURCE.NETFLIX:
|
case PLAYER_SOURCE.NETFLIX:
|
||||||
if (document.getElementsByClassName('AkiraPlayer')[0]) {
|
if (document.getElementsByClassName('AkiraPlayer')[0]) {
|
||||||
@@ -75,25 +117,28 @@ export default class VideoListener {
|
|||||||
this.firstTimeSync(videoElement);
|
this.firstTimeSync(videoElement);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
document.body.addEventListener('DOMNodeInserted', (ev) => {
|
document.addEventListener('DOMNodeInserted', (e) => {
|
||||||
if (ev.target.tagName === 'VIDEO') {
|
if (e.target) {
|
||||||
document.body.removeEventListener('DOMNodeInserted');
|
if (e.target.classList) {
|
||||||
this.start();
|
if (
|
||||||
|
e.target.classList.contains('nfp') &&
|
||||||
|
e.target.classList.contains('AkiraPlayer')
|
||||||
|
) {
|
||||||
|
e.target.addEventListener('DOMNodeInserted', (ev) => {
|
||||||
|
if (ev.target.children[0].id) {
|
||||||
|
this.firstTimeSync(ev.target.children[0].firstChild);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PLAYER_SOURCE.HULU:
|
case PLAYER_SOURCE.HULU:
|
||||||
const videoElement = document.getElementsByClassName('video-player')[0];
|
const videoElement = document.getElementsByClassName('content-video-player')[0];
|
||||||
if (videoElement) {
|
if (videoElement) {
|
||||||
this.firstTimeSync(videoElement);
|
this.firstTimeSync(videoElement);
|
||||||
} else {
|
|
||||||
document.body.addEventListener('DOMNodeInserted', (ev) => {
|
|
||||||
if (ev.target.tagName === 'VIDEO') {
|
|
||||||
document.body.removeEventListener('DOMNodeInserted');
|
|
||||||
this.start();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PLAYER_SOURCE.AMAZON:
|
case PLAYER_SOURCE.AMAZON:
|
||||||
@@ -104,26 +149,12 @@ export default class VideoListener {
|
|||||||
if (videoElement) {
|
if (videoElement) {
|
||||||
this.firstTimeSync(videoElement);
|
this.firstTimeSync(videoElement);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
document.body.addEventListener('DOMNodeInserted', (ev) => {
|
|
||||||
if (ev.target.tagName === 'VIDEO') {
|
|
||||||
document.body.removeEventListener('DOMNodeInserted');
|
|
||||||
this.start();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PLAYER_SOURCE.LOCAL:
|
case PLAYER_SOURCE.LOCAL:
|
||||||
const localVideoElement = document.getElementsByTagName('video')[0];
|
const localVideoElement = document.getElementsByTagName('video')[0];
|
||||||
if (localVideoElement) {
|
if (localVideoElement) {
|
||||||
this.firstTimeSync(localVideoElement);
|
this.firstTimeSync(localVideoElement);
|
||||||
} else {
|
|
||||||
document.body.addEventListener('DOMNodeInserted', (ev) => {
|
|
||||||
if (ev.target.tagName === 'VIDEO') {
|
|
||||||
document.body.removeEventListener('DOMNodeInserted');
|
|
||||||
this.start();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
+8
-3
@@ -7,7 +7,8 @@ body.visible {
|
|||||||
width: 65%;
|
width: 65%;
|
||||||
}
|
}
|
||||||
body.visible .watch-party-fab {
|
body.visible .watch-party-fab {
|
||||||
right: calc(35% - 4rem) !important;
|
right: 35% !important;
|
||||||
|
transform: translateX(50%);
|
||||||
top: 1.5rem;
|
top: 1.5rem;
|
||||||
}
|
}
|
||||||
body.visible .party-notification-container {
|
body.visible .party-notification-container {
|
||||||
@@ -15,13 +16,14 @@ body.visible .party-notification-container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body.netflix.visible .AkiraPlayer, /* NETFLIX */
|
body.netflix.visible .AkiraPlayer, /* NETFLIX */
|
||||||
body.hulu.visible .Player__container.addFocus,/* HULU */
|
body.hulu.visible .Player__container,/* HULU */
|
||||||
body.amazon-prime.visible #dv-web-player.dv-player-fullscreen /* AMAZON PRIME */ {
|
body.amazon-prime.visible #dv-web-player.dv-player-fullscreen /* AMAZON PRIME */ {
|
||||||
max-width: 65% !important;
|
max-width: 65% !important;
|
||||||
}
|
}
|
||||||
/* HULU MINIMIZED VIDEO */
|
/* HULU MINIMIZED VIDEO */
|
||||||
body.hulu.visible #__player__.Player__container.Player__container--modal {
|
body.hulu.visible #__player__ .Player__container.Player__container--modal {
|
||||||
right: calc(35% + 2rem) !important;
|
right: calc(35% + 2rem) !important;
|
||||||
|
z-index: 99999 !important;
|
||||||
}
|
}
|
||||||
/* HULU & AMAZON PRIME FIX */
|
/* HULU & AMAZON PRIME FIX */
|
||||||
body.hulu #party-routes-wrapper,
|
body.hulu #party-routes-wrapper,
|
||||||
@@ -77,11 +79,13 @@ body.amazon-prime #party-routes-wrapper {
|
|||||||
color: white;
|
color: white;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
z-index: 9999;
|
||||||
}
|
}
|
||||||
#party-routes-wrapper.visible {
|
#party-routes-wrapper.visible {
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
.party-notification-container {
|
.party-notification-container {
|
||||||
|
z-index: 99999 !important;
|
||||||
display: none !important;
|
display: none !important;
|
||||||
bottom: 0.8rem !important;
|
bottom: 0.8rem !important;
|
||||||
right: 1rem !important;
|
right: 1rem !important;
|
||||||
@@ -97,6 +101,7 @@ body.amazon-prime #party-routes-wrapper {
|
|||||||
position: fixed !important;
|
position: fixed !important;
|
||||||
bottom: 1rem !important;
|
bottom: 1rem !important;
|
||||||
right: -2rem !important;
|
right: -2rem !important;
|
||||||
|
border: 1px solid white;
|
||||||
background-color: black !important;
|
background-color: black !important;
|
||||||
/* background-image: url('/logo192.png'); */
|
/* background-image: url('/logo192.png'); */
|
||||||
background-image: url('chrome-extension://__MSG_@@extension_id__/logo192.png');
|
background-image: url('chrome-extension://__MSG_@@extension_id__/logo192.png');
|
||||||
|
|||||||
@@ -27,11 +27,34 @@ switch (getPlayerSource()) {
|
|||||||
document.body.classList.add('netflix');
|
document.body.classList.add('netflix');
|
||||||
break;
|
break;
|
||||||
case PLAYER_SOURCE.HULU:
|
case PLAYER_SOURCE.HULU:
|
||||||
|
document.addEventListener(
|
||||||
|
'keydown',
|
||||||
|
(ev) => {
|
||||||
|
if (ev.target.tagName !== 'INPUT' || ev.target.tagName !== 'TEXTAREA') {
|
||||||
|
ev.stopImmediatePropagation();
|
||||||
|
ev.stopPropagation();
|
||||||
|
} else {
|
||||||
|
ev.target.focus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ capture: true }
|
||||||
|
);
|
||||||
document.body.classList.add('hulu');
|
document.body.classList.add('hulu');
|
||||||
break;
|
break;
|
||||||
case PLAYER_SOURCE.AMAZON:
|
case PLAYER_SOURCE.AMAZON:
|
||||||
document.body.classList.add('amazon-prime');
|
document.body.classList.add('amazon-prime');
|
||||||
break;
|
break;
|
||||||
|
case PLAYER_SOURCE.LOCAL:
|
||||||
|
const VideoPlayer = document.createElement('video');
|
||||||
|
VideoPlayer.autoplay = true;
|
||||||
|
VideoPlayer.muted = true;
|
||||||
|
VideoPlayer.controls = true;
|
||||||
|
VideoPlayer.style.width = '300px';
|
||||||
|
VideoPlayer.src =
|
||||||
|
'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4';
|
||||||
|
VideoPlayer.addEventListener('change', (e) => console.log(e));
|
||||||
|
document.body.appendChild(VideoPlayer);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user