From 7ad7a8f83ab25a723098467a3cbd23dac471dab4 Mon Sep 17 00:00:00 2001 From: Ayushya Amitabh Date: Thu, 21 May 2020 10:49:05 -0400 Subject: [PATCH] v1.2.0-beta/fix file structure --- config/env.js | 93 - config/jest/cssTransform.js | 14 - config/jest/fileTransform.js | 12 - config/paths.js | 55 - config/polyfills.js | 22 - config/webpack.config.dev.js | 264 - config/webpack.config.prod.js | 346 - config/webpackDevServer.config.js | 95 - package-lock.json | 16448 ---------------------------- package.json | 114 - public/android-icon-144x144.png | Bin 2097 -> 0 bytes public/android-icon-192x192.png | Bin 1379 -> 0 bytes public/background.js | 131 - public/favicon-128x128.png | Bin 5088 -> 0 bytes public/favicon-16x16.png | Bin 915 -> 0 bytes public/favicon-32x32.png | Bin 1204 -> 0 bytes public/favicon-96x96.png | Bin 1751 -> 0 bytes public/favicon.ico | Bin 1150 -> 0 bytes public/index.html | 7 - public/logo192.png | Bin 8271 -> 0 bytes public/logo512.png | Bin 11066 -> 0 bytes public/manifest.json | 66 - public/popup.html | 54 - public/robots.txt | 3 - scripts/build.js | 150 - scripts/start.js | 102 - scripts/test.js | 27 - src/Api.js | 111 - src/App.js | 93 - src/Chat.js | 280 - src/Create.js | 180 - src/Inactive.js | 13 - src/Loading.js | 10 - src/Thread.css | 95 - src/Thread.js | 70 - src/VideoListener.js | 304 - src/index.css | 302 - src/index.js | 70 - 38 files changed, 19531 deletions(-) delete mode 100644 config/env.js delete mode 100644 config/jest/cssTransform.js delete mode 100644 config/jest/fileTransform.js delete mode 100644 config/paths.js delete mode 100644 config/polyfills.js delete mode 100644 config/webpack.config.dev.js delete mode 100644 config/webpack.config.prod.js delete mode 100644 config/webpackDevServer.config.js delete mode 100644 package-lock.json delete mode 100644 package.json delete mode 100644 public/android-icon-144x144.png delete mode 100644 public/android-icon-192x192.png delete mode 100644 public/background.js delete mode 100644 public/favicon-128x128.png delete mode 100644 public/favicon-16x16.png delete mode 100644 public/favicon-32x32.png delete mode 100644 public/favicon-96x96.png delete mode 100644 public/favicon.ico delete mode 100644 public/index.html delete mode 100644 public/logo192.png delete mode 100644 public/logo512.png delete mode 100644 public/manifest.json delete mode 100644 public/popup.html delete mode 100644 public/robots.txt delete mode 100644 scripts/build.js delete mode 100644 scripts/start.js delete mode 100644 scripts/test.js delete mode 100644 src/Api.js delete mode 100644 src/App.js delete mode 100644 src/Chat.js delete mode 100644 src/Create.js delete mode 100644 src/Inactive.js delete mode 100644 src/Loading.js delete mode 100644 src/Thread.css delete mode 100644 src/Thread.js delete mode 100644 src/VideoListener.js delete mode 100644 src/index.css delete mode 100644 src/index.js diff --git a/config/env.js b/config/env.js deleted file mode 100644 index 30a6c7f..0000000 --- a/config/env.js +++ /dev/null @@ -1,93 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const paths = require('./paths'); - -// Make sure that including paths.js after env.js will read .env variables. -delete require.cache[require.resolve('./paths')]; - -const NODE_ENV = process.env.NODE_ENV; -if (!NODE_ENV) { - throw new Error( - 'The NODE_ENV environment variable is required but was not specified.' - ); -} - -// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use -var dotenvFiles = [ - `${paths.dotenv}.${NODE_ENV}.local`, - `${paths.dotenv}.${NODE_ENV}`, - // Don't include `.env.local` for `test` environment - // since normally you expect tests to produce the same - // results for everyone - NODE_ENV !== 'test' && `${paths.dotenv}.local`, - paths.dotenv, -].filter(Boolean); - -// Load environment variables from .env* files. Suppress warnings using silent -// if this file is missing. dotenv will never modify any environment variables -// that have already been set. Variable expansion is supported in .env files. -// https://github.com/motdotla/dotenv -// https://github.com/motdotla/dotenv-expand -dotenvFiles.forEach(dotenvFile => { - if (fs.existsSync(dotenvFile)) { - require('dotenv-expand')( - require('dotenv').config({ - path: dotenvFile, - }) - ); - } -}); - -// We support resolving modules according to `NODE_PATH`. -// This lets you use absolute paths in imports inside large monorepos: -// https://github.com/facebookincubator/create-react-app/issues/253. -// It works similar to `NODE_PATH` in Node itself: -// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders -// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored. -// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims. -// https://github.com/facebookincubator/create-react-app/issues/1023#issuecomment-265344421 -// We also resolve them to make sure all tools using them work consistently. -const appDirectory = fs.realpathSync(process.cwd()); -process.env.NODE_PATH = (process.env.NODE_PATH || '') - .split(path.delimiter) - .filter(folder => folder && !path.isAbsolute(folder)) - .map(folder => path.resolve(appDirectory, folder)) - .join(path.delimiter); - -// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be -// injected into the application via DefinePlugin in Webpack configuration. -const REACT_APP = /^REACT_APP_/i; - -function getClientEnvironment(publicUrl) { - const raw = Object.keys(process.env) - .filter(key => REACT_APP.test(key)) - .reduce( - (env, key) => { - env[key] = process.env[key]; - return env; - }, - { - // Useful for determining whether we’re running in production mode. - // Most importantly, it switches React into the correct mode. - NODE_ENV: process.env.NODE_ENV || 'development', - // Useful for resolving the correct path to static assets in `public`. - // For example, . - // This should only be used as an escape hatch. Normally you would put - // images into the `src` and `import` them in code to get their paths. - PUBLIC_URL: publicUrl, - } - ); - // Stringify all values so we can feed into Webpack DefinePlugin - const stringified = { - 'process.env': Object.keys(raw).reduce((env, key) => { - env[key] = JSON.stringify(raw[key]); - return env; - }, {}), - }; - - return { raw, stringified }; -} - -module.exports = getClientEnvironment; diff --git a/config/jest/cssTransform.js b/config/jest/cssTransform.js deleted file mode 100644 index 8f65114..0000000 --- a/config/jest/cssTransform.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -// This is a custom Jest transformer turning style imports into empty objects. -// http://facebook.github.io/jest/docs/en/webpack.html - -module.exports = { - process() { - return 'module.exports = {};'; - }, - getCacheKey() { - // The output is always the same. - return 'cssTransform'; - }, -}; diff --git a/config/jest/fileTransform.js b/config/jest/fileTransform.js deleted file mode 100644 index 9e4047d..0000000 --- a/config/jest/fileTransform.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; - -const path = require('path'); - -// This is a custom Jest transformer turning file imports into filenames. -// http://facebook.github.io/jest/docs/en/webpack.html - -module.exports = { - process(src, filename) { - return `module.exports = ${JSON.stringify(path.basename(filename))};`; - }, -}; diff --git a/config/paths.js b/config/paths.js deleted file mode 100644 index 6d16efc..0000000 --- a/config/paths.js +++ /dev/null @@ -1,55 +0,0 @@ -'use strict'; - -const path = require('path'); -const fs = require('fs'); -const url = require('url'); - -// Make sure any symlinks in the project folder are resolved: -// https://github.com/facebookincubator/create-react-app/issues/637 -const appDirectory = fs.realpathSync(process.cwd()); -const resolveApp = relativePath => path.resolve(appDirectory, relativePath); - -const envPublicUrl = process.env.PUBLIC_URL; - -function ensureSlash(path, needsSlash) { - const hasSlash = path.endsWith('/'); - if (hasSlash && !needsSlash) { - return path.substr(path, path.length - 1); - } else if (!hasSlash && needsSlash) { - return `${path}/`; - } else { - return path; - } -} - -const getPublicUrl = appPackageJson => - envPublicUrl || require(appPackageJson).homepage; - -// We use `PUBLIC_URL` environment variable or "homepage" field to infer -// "public path" at which the app is served. -// Webpack needs to know it to put the right - - - - Hulu - Netflix - Prime Video - - diff --git a/public/robots.txt b/public/robots.txt deleted file mode 100644 index e9e57dc..0000000 --- a/public/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: diff --git a/scripts/build.js b/scripts/build.js deleted file mode 100644 index 5709f48..0000000 --- a/scripts/build.js +++ /dev/null @@ -1,150 +0,0 @@ -'use strict'; - -// Do this as the first thing so that any code reading it knows the right env. -process.env.BABEL_ENV = 'production'; -process.env.NODE_ENV = 'production'; - -// Makes the script crash on unhandled rejections instead of silently -// ignoring them. In the future, promise rejections that are not handled will -// terminate the Node.js process with a non-zero exit code. -process.on('unhandledRejection', err => { - throw err; -}); - -// Ensure environment variables are read. -require('../config/env'); - -const path = require('path'); -const chalk = require('chalk'); -const fs = require('fs-extra'); -const webpack = require('webpack'); -const config = require('../config/webpack.config.prod'); -const paths = require('../config/paths'); -const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); -const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages'); -const printHostingInstructions = require('react-dev-utils/printHostingInstructions'); -const FileSizeReporter = require('react-dev-utils/FileSizeReporter'); -const printBuildError = require('react-dev-utils/printBuildError'); - -const measureFileSizesBeforeBuild = - FileSizeReporter.measureFileSizesBeforeBuild; -const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild; -const useYarn = fs.existsSync(paths.yarnLockFile); - -// These sizes are pretty large. We'll warn for bundles exceeding them. -const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024; -const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024; - -// Warn and crash if required files are missing -if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { - process.exit(1); -} - -// First, read the current file sizes in build directory. -// This lets us display how much they changed later. -measureFileSizesBeforeBuild(paths.appBuild) - .then(previousFileSizes => { - // Remove all content but keep the directory so that - // if you're in it, you don't end up in Trash - fs.emptyDirSync(paths.appBuild); - // Merge with the public folder - copyPublicFolder(); - // Start the webpack build - return build(previousFileSizes); - }) - .then( - ({ stats, previousFileSizes, warnings }) => { - if (warnings.length) { - console.log(chalk.yellow('Compiled with warnings.\n')); - console.log(warnings.join('\n\n')); - console.log( - '\nSearch for the ' + - chalk.underline(chalk.yellow('keywords')) + - ' to learn more about each warning.' - ); - console.log( - 'To ignore, add ' + - chalk.cyan('// eslint-disable-next-line') + - ' to the line before.\n' - ); - } else { - console.log(chalk.green('Compiled successfully.\n')); - } - - console.log('File sizes after gzip:\n'); - printFileSizesAfterBuild( - stats, - previousFileSizes, - paths.appBuild, - WARN_AFTER_BUNDLE_GZIP_SIZE, - WARN_AFTER_CHUNK_GZIP_SIZE - ); - console.log(); - - const appPackage = require(paths.appPackageJson); - const publicUrl = paths.publicUrl; - const publicPath = config.output.publicPath; - const buildFolder = path.relative(process.cwd(), paths.appBuild); - printHostingInstructions( - appPackage, - publicUrl, - publicPath, - buildFolder, - useYarn - ); - }, - err => { - console.log(chalk.red('Failed to compile.\n')); - printBuildError(err); - process.exit(1); - } - ); - -// Create the production build and print the deployment instructions. -function build(previousFileSizes) { - console.log('Creating an optimized production build...'); - - let compiler = webpack(config); - return new Promise((resolve, reject) => { - compiler.run((err, stats) => { - if (err) { - return reject(err); - } - const messages = formatWebpackMessages(stats.toJson({}, true)); - if (messages.errors.length) { - // Only keep the first error. Others are often indicative - // of the same problem, but confuse the reader with noise. - if (messages.errors.length > 1) { - messages.errors.length = 1; - } - return reject(new Error(messages.errors.join('\n\n'))); - } - if ( - process.env.CI && - (typeof process.env.CI !== 'string' || - process.env.CI.toLowerCase() !== 'false') && - messages.warnings.length - ) { - console.log( - chalk.yellow( - '\nTreating warnings as errors because process.env.CI = true.\n' + - 'Most CI servers set it automatically.\n' - ) - ); - return reject(new Error(messages.warnings.join('\n\n'))); - } - return resolve({ - stats, - previousFileSizes, - warnings: messages.warnings, - }); - }); - }); -} - -function copyPublicFolder() { - fs.copySync(paths.appPublic, paths.appBuild, { - dereference: true, - filter: file => file !== paths.appHtml, - }); -} diff --git a/scripts/start.js b/scripts/start.js deleted file mode 100644 index 4a6ddff..0000000 --- a/scripts/start.js +++ /dev/null @@ -1,102 +0,0 @@ -'use strict'; - -// Do this as the first thing so that any code reading it knows the right env. -process.env.BABEL_ENV = 'development'; -process.env.NODE_ENV = 'development'; - -// Makes the script crash on unhandled rejections instead of silently -// ignoring them. In the future, promise rejections that are not handled will -// terminate the Node.js process with a non-zero exit code. -process.on('unhandledRejection', (err) => { - throw err; -}); - -// Ensure environment variables are read. -require('../config/env'); - -const fs = require('fs'); -const chalk = require('chalk'); -const webpack = require('webpack'); -const WebpackDevServer = require('webpack-dev-server'); -const clearConsole = require('react-dev-utils/clearConsole'); -const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); -const { - choosePort, - createCompiler, - prepareProxy, - prepareUrls, -} = require('react-dev-utils/WebpackDevServerUtils'); -const openBrowser = require('react-dev-utils/openBrowser'); -const paths = require('../config/paths'); -const config = require('../config/webpack.config.dev'); -const createDevServerConfig = require('../config/webpackDevServer.config'); - -const useYarn = fs.existsSync(paths.yarnLockFile); -const isInteractive = process.stdout.isTTY; - -// Warn and crash if required files are missing -if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { - process.exit(1); -} - -// Tools like Cloud9 rely on this. -const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; -const HOST = process.env.HOST || '0.0.0.0'; - -if (process.env.HOST) { - console.log( - chalk.cyan( - `Attempting to bind to HOST environment variable: ${chalk.yellow( - chalk.bold(process.env.HOST) - )}` - ) - ); - console.log(`If this was unintentional, check that you haven't mistakenly set it in your shell.`); - console.log(`Learn more here: ${chalk.yellow('http://bit.ly/2mwWSwH')}`); - console.log(); -} - -// We attempt to use the default port but if it is busy, we offer the user to -// run on a different port. `choosePort()` Promise resolves to the next free port. -choosePort(HOST, DEFAULT_PORT) - .then((port) => { - if (port == null) { - // We have not found a port. - return; - } - const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; - const appName = require(paths.appPackageJson).name; - const urls = prepareUrls(protocol, HOST, port); - // Create a webpack compiler that is configured with custom messages. - const compiler = createCompiler({ webpack, config, appName, urls, useYarn }); - // Load proxy config - const proxySetting = require(paths.appPackageJson).proxy; - const proxyConfig = prepareProxy(proxySetting, paths.appPublic); - // Serve webpack assets generated by the compiler over a web sever. - const serverConfig = createDevServerConfig(proxyConfig, urls.lanUrlForConfig); - const devServer = new WebpackDevServer(compiler, serverConfig); - // Launch WebpackDevServer. - devServer.listen(port, HOST, (err) => { - if (err) { - return console.log(err); - } - if (isInteractive) { - clearConsole(); - } - console.log(chalk.cyan('Starting the development server...\n')); - openBrowser(urls.localUrlForBrowser); - }); - - ['SIGINT', 'SIGTERM'].forEach(function (sig) { - process.on(sig, function () { - devServer.close(); - process.exit(); - }); - }); - }) - .catch((err) => { - if (err && err.message) { - console.log(err.message); - } - process.exit(1); - }); diff --git a/scripts/test.js b/scripts/test.js deleted file mode 100644 index 45a643a..0000000 --- a/scripts/test.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; - -// Do this as the first thing so that any code reading it knows the right env. -process.env.BABEL_ENV = 'test'; -process.env.NODE_ENV = 'test'; -process.env.PUBLIC_URL = ''; - -// Makes the script crash on unhandled rejections instead of silently -// ignoring them. In the future, promise rejections that are not handled will -// terminate the Node.js process with a non-zero exit code. -process.on('unhandledRejection', err => { - throw err; -}); - -// Ensure environment variables are read. -require('../config/env'); - -const jest = require('jest'); -let argv = process.argv.slice(2); - -// Watch unless on CI or in coverage mode -if (!process.env.CI && argv.indexOf('--coverage') < 0) { - argv.push('--watch'); -} - - -jest.run(argv); diff --git a/src/Api.js b/src/Api.js deleted file mode 100644 index 92bc5bb..0000000 --- a/src/Api.js +++ /dev/null @@ -1,111 +0,0 @@ -/*global chrome*/ - -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'; - 'https://us-central1-watch-party-crx.cloudfunctions.net/widgets'; - -export const PLAYER_STATUS = { - PLAYING: 'PLAYING', - PAUSED: 'PAUSED', - NOT_PLAYING: 'NOT_PLAYING', -}; - -export const PLAYER_SOURCE = { - NETFLIX: 'https://www.netflix.', - AMAZON: 'https://www.amazon.', - HULU: 'https://www.hulu.', - DISNEY: 'https://www.disneyplus.', - YOUTUBE: 'https://www.youtube.', - HBONOW: 'https://play.hbonow.', - LOCAL: 'http://localhost', -}; - -export const getPlayerSource = () => { - const HREF = window.location.href; - if (HREF.startsWith(PLAYER_SOURCE.NETFLIX)) return PLAYER_SOURCE.NETFLIX; - if (HREF.startsWith(PLAYER_SOURCE.HULU)) return PLAYER_SOURCE.HULU; - if (HREF.startsWith(PLAYER_SOURCE.AMAZON)) return PLAYER_SOURCE.AMAZON; - if (HREF.startsWith(PLAYER_SOURCE.DISNEY)) return PLAYER_SOURCE.DISNEY; - if (HREF.startsWith(PLAYER_SOURCE.YOUTUBE)) return PLAYER_SOURCE.YOUTUBE; - if (HREF.startsWith(PLAYER_SOURCE.HBONOW)) return PLAYER_SOURCE.HBONOW; - if (HREF.startsWith(PLAYER_SOURCE.LOCAL)) return PLAYER_SOURCE.LOCAL; -}; - -export const getUserUid = async () => - new Promise((resolve, reject) => { - chrome.runtime.sendMessage( - { - type: 'GET_AUTH', - }, - (response) => { - const { uid } = response; - window.localStorage.setItem('watchPartyUserUid', uid); - resolve(uid); - } - ); - }); - -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) => { - return fetcher({ - endpoint: 'create', - method: 'POST', - body: JSON.stringify(data), - }); -}; - -export const JoinRoomApi = async (data) => { - return fetcher({ - endpoint: 'join', - method: 'POST', - body: JSON.stringify(data), - }); -}; - -export const SendMessageApi = async (data) => { - return fetcher({ - endpoint: 'message', - method: 'POST', - body: JSON.stringify(data), - }); -}; - -export const LeaveRoomApi = async (data) => { - return fetcher({ - endpoint: `leave/${data.roomId}/users/${data.uid}`, - method: 'DELETE', - }); -}; - -export const DeleteRoomApi = async (data) => { - return fetcher({ - endpoint: `delete/${data.roomId}`, - method: 'DELETE', - }); -}; - -export const UpdatePlayerApi = async (data) => { - return fetcher({ - endpoint: 'updatePlayer', - method: 'POST', - body: JSON.stringify(data), - }); -}; diff --git a/src/App.js b/src/App.js deleted file mode 100644 index 793af17..0000000 --- a/src/App.js +++ /dev/null @@ -1,93 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import Router from 'route-lite'; -import { Fab, createMuiTheme, ThemeProvider, Snackbar } from '@material-ui/core'; -import Create from './Create'; -import Loading from './Loading'; -import firebase from 'firebase/app'; -import 'firebase/firestore'; -import Inactive from './Inactive'; -import { getUserUid } from './Api'; - -const darkTheme = createMuiTheme({ - palette: { - type: 'dark', - primary: { - main: '#a6d4fa', - }, - }, -}); - -const Routes = (props) => ( - - - -); - -const App = () => { - const closedNotification = { open: false, message: '' }; - - const [status, setStatus] = useState({ active: false, message: '' }); - const [visible, setVisible] = useState(false); - const [loading, setLoading] = useState(false); - const [notification, setNotification] = useState(closedNotification); - - useEffect(() => { - setLoading(true); - getUserUid(); - firebase - .firestore() - .collection('server') - .doc('status') - .onSnapshot((statusSnap) => { - setStatus(statusSnap.data()); - setLoading(false); - }); - }, []); - - // HANDLE VISIBILITY STYLING - const PartyRoutesWrapper = document.getElementById('party-routes-wrapper'); - if (visible) { - document.body.classList.add('visible'); - PartyRoutesWrapper && PartyRoutesWrapper.classList.add('visible'); - } else { - document.body.classList.remove('visible'); - PartyRoutesWrapper && PartyRoutesWrapper.classList.remove('visible'); - } - - // HANDLE FULLSCREEN EVENT - document.onfullscreenchange = () => { - if (document.fullscreenElement) setVisible(false); - }; - - return ( - - setNotification(closedNotification)} - message={notification.message} - resumeHideDuration={500} - autoHideDuration={2000} - /> -
-
- {loading && } - {status.active ? ( - setNotification({ open: true, message })} - /> - ) : ( - - )} -
- setVisible(!visible)} className="watch-party-fab"> - - -
-
- ); -}; - -export default App; diff --git a/src/Chat.js b/src/Chat.js deleted file mode 100644 index c34842b..0000000 --- a/src/Chat.js +++ /dev/null @@ -1,280 +0,0 @@ -/*global chrome */ -import React, { Component } from 'react'; -import { - Typography, - TextField, - InputAdornment, - IconButton, - ButtonGroup, - Button, -} from '@material-ui/core'; -import Thread from './Thread'; -import Send from '@material-ui/icons/Send'; -import Exit from '@material-ui/icons/ExitToApp'; -import Share from '@material-ui/icons/Share'; -import Delete from '@material-ui/icons/Delete'; -import Gif from '@material-ui/icons/Gif'; -import { Carousel } from '@giphy/react-components'; -import { GiphyFetch } from '@giphy/js-fetch-api'; -import { - SendMessageApi, - LeaveRoomApi, - DeleteRoomApi, - UpdatePlayerApi, - getPlayerSource, - PLAYER_SOURCE, -} from './Api'; -import { goTo } from 'route-lite'; -import Create from './Create'; -import VideoListener from './VideoListener'; - -const giphyFetch = new GiphyFetch('ojJbIMUN6XRMn4mHiFFav3rMCpXUg8sq'); -const alertMessage = { - name: '', - text: 'Functionality may be buggy, support on this site is in beta.', - time: '', - uid: '', -}; -export default class Chat extends Component { - constructor(props) { - super(props); - this.state = { - name: '', - messages: [], - newMessage: '', - admin: null, - gif: false, - }; - this.sendMessage = this.sendMessage.bind(this); - this.sendMessageInvoker = this.sendMessageInvoker.bind(this); - this.endParty = this.endParty.bind(this); - this.leaveParty = this.leaveParty.bind(this); - this.shareParty = this.shareParty.bind(this); - this.syncPlayer = this.syncPlayer.bind(this); - this.videoEventListener = this.videoEventListener.bind(this); - this.mVideoListener = new VideoListener(this.videoEventListener); - this.port = null; - this.getCarousel = this.getCarousel.bind(this); - this.gifClick = this.gifClick.bind(this); - } - componentDidMount() { - // EVENT CAPTURE FOR ENTER TO SEND - window.onkeypress = (ev) => { - if (ev.code === 'Enter') { - if (ev.target === document.getElementById('chat-message-box-input')) { - if (ev.shiftKey === false && this.state.gif === true) ev.preventDefault(); - if (ev.shiftKey === false && this.state.gif === false) { - ev.preventDefault(); - this.sendMessageInvoker(); - } - } - } - }; - - // VIDEO LISTENER START - this.mVideoListener.start(); - - // CHROME FIREBASE FIRESTORE LISTENER - this.port = chrome.runtime.connect({ name: window.localStorage.getItem('watchPartyRoomId') }); - // Initialize listener - this.port.postMessage({ - type: 'INIT', - roomId: window.localStorage.getItem('watchPartyRoomId'), - }); - // Listener - this.port.onMessage.addListener((response) => { - if (response.isError === true) { - this.props.notify('Uh oh. Got lost from the party.'); - goTo(Create, this.props); - return; - } - this.setState(response); - if (response.player) this.mVideoListener.doUpdate(response.player); - const pcc = document.getElementsByClassName('thread-container')[0]; - if (pcc) pcc.scrollTop = pcc.scrollHeight; - }); - - // DONE WITH MOUNTING TASKS - this.props.updateLoading(false); - } - componentWillUnmount() { - this.mVideoListener.end(); - } - videoEventListener(video) { - this.syncPlayer(video); - } - syncPlayer(video) { - const { status, showName, time, source, element, showChanged } = video; - if (element) { - UpdatePlayerApi({ - roomId: window.localStorage.getItem('watchPartyRoomId'), - showChanged, - userName: window.localStorage.getItem('watchPartyUserName'), - player: { - status, - showName, - time, - source, - updatedBy: window.localStorage.getItem('watchPartyUserUid'), - }, - }).catch((err) => { - this.props.updateLoading(false); - this.props.notify(err.message || err.statusText); - console.error('Sync Party API error', err); - }); - } else { - this.mVideoListener.start(); - } - } - endParty() { - this.props.notify('Ending party...'); - this.props.updateLoading(true); - const data = { - roomId: window.localStorage.getItem('watchPartyRoomId'), - }; - DeleteRoomApi(data) - .then((res) => { - this.props.notify('Ended party'); - window.localStorage.removeItem('watchPartyRoomId'); - goTo(Create, this.props); - this.props.updateLoading(false); - }) - .catch((err) => { - this.props.updateLoading(false); - this.props.notify(err.message || err.statusText); - console.error('End Party API error', err); - }); - } - leaveParty() { - this.props.notify('Leaving party...'); - this.props.updateLoading(true); - const data = { - roomId: window.localStorage.getItem('watchPartyRoomId'), - uid: window.localStorage.getItem('watchPartyUserUid'), - }; - LeaveRoomApi(data) - .then((res) => { - this.props.notify('Left party'); - window.localStorage.removeItem('watchPartyRoomId'); - goTo(Create, this.props); - this.props.updateLoading(false); - }) - .catch((err) => { - this.props.updateLoading(false); - this.props.notify(err.message || err.statusText); - console.error('End Party API error', err); - }); - } - shareParty() { - const el = document.createElement('textarea'); - el.value = window.localStorage.getItem('watchPartyRoomId'); - document.body.appendChild(el); - el.select(); - document.execCommand('copy'); - document.body.removeChild(el); - this.props.notify('Copied room code'); - } - sendMessage(message) { - const data = { - roomId: window.localStorage.getItem('watchPartyRoomId'), - name: window.localStorage.getItem('watchPartyUserName'), - uid: window.localStorage.getItem('watchPartyUserUid'), - text: message, - time: new Date(), - type: '', - }; - if (this.state.gif === true) data.type = 'giphy'; - SendMessageApi(data).catch((err) => { - this.props.notify(err.message || err.statusText); - console.error('Send Message API error', err); - }); - } - sendMessageInvoker(overrideMessage) { - if (overrideMessage) this.sendMessage(overrideMessage); - else { - const trim = this.state.newMessage.replace(/^\s+|\s+$/g, ''); - if (trim !== '') this.sendMessage(trim); - } - this.setState({ newMessage: '' }); - } - gifClick(iGif, ev) { - ev.preventDefault(); - this.sendMessageInvoker(iGif.images.original.url); - } - getCarousel() { - const trendingFetch = (offset) => giphyFetch.trending({ offset, limit: 5 }); - const searchFetch = (offset) => giphyFetch.search(this.state.newMessage, { offset, limit: 5 }); - return ( - - ); - } - render() { - const { admin, name, messages, newMessage, gif } = this.state; - if (getPlayerSource() === PLAYER_SOURCE.HBONOW && messages[0] !== alertMessage) - messages.unshift(alertMessage); - return ( -
-
-
- - WATCH PARTY - - - {name} - -
- - - - {admin && ( - - )} - -
-
- -
- this.setState({ newMessage: e.target.value, gif: false })} - InputProps={{ - id: 'chat-message-box-input', - endAdornment: ( - - this.sendMessageInvoker(newMessage)} edge="end"> - - - - ), - startAdornment: ( - - this.setState({ gif: !gif })} edge="start"> - - - - ), - }} - /> - {gif ? this.getCarousel() : null} -
- ); - } -} diff --git a/src/Create.js b/src/Create.js deleted file mode 100644 index bbeb0dd..0000000 --- a/src/Create.js +++ /dev/null @@ -1,180 +0,0 @@ -import React, { useState } from 'react'; -import { - Button, - InputAdornment, - TextField, - Typography, - IconButton, - Paper, -} from '@material-ui/core'; -import Save from '@material-ui/icons/Save'; -import { JoinRoomApi, CreateRoomApi, PLAYER_STATUS, getPlayerSource } from './Api'; -import { goTo } from 'route-lite'; -import Chat from './Chat'; - -const saveName = (data) => { - const { name, notify } = data; - window.localStorage.setItem('watchPartyUserName', name); - notify('Saved name'); -}; -const getName = () => window.localStorage.getItem('watchPartyUserName'); - -const saveRoomId = (data) => { - const { rid, notify } = data; - window.localStorage.setItem('watchPartyRoomId', rid); - notify('Saved room'); -}; -const getRoomId = () => window.localStorage.getItem('watchPartyRoomId'); - -const joinRoom = async (data) => { - data.props.updateLoading(true); - data.props.notify('Joining party...'); - const apidata = { - roomId: data.joinName.trim(), - userName: data.name.trim(), - source: getPlayerSource(), - }; - const confirmedRoomId = await JoinRoomApi(apidata) - .then((res) => res.json()) - .then((res) => res.roomId) - .catch((err) => { - data.props.updateLoading(false); - data.props.notify(err.message || err.statusText); - console.error('Join Room API error', err); - }); - if (confirmedRoomId && confirmedRoomId === apidata.roomId) { - saveName({ - name: apidata.userName, - notify: data.props.notify, - }); - saveRoomId({ - rid: confirmedRoomId, - notify: data.props.notify, - }); - data.props.notify('Joined party'); - goTo(Chat, data.props); - } -}; - -const createRoom = async (data) => { - data.props.updateLoading(true); - data.props.notify('Starting party...'); - - const apidata = { - roomName: data.createName, - userName: data.name, - player: { - source: getPlayerSource(), - status: PLAYER_STATUS.PAUSED, - time: 0, - url: '', - }, - }; - - CreateRoomApi(apidata) - .then((res) => res.json()) - .then((res) => { - if (res.status <= 299) { - saveName({ - name: data.name, - notify: data.props.notify, - }); - saveRoomId({ - rid: res.roomId, - notify: data.props.notify, - }); - data.props.notify('Started party'); - goTo(Chat, data.props); - } else { - data.props.updateLoading(false); - data.props.notify(res.message || res.statusText); - } - }) - .catch((err) => { - data.props.updateLoading(false); - data.props.notify(err.message || err.statusText); - console.error('Create Room API error', err); - }); -}; - -const Create = (props) => { - const [name, setName] = useState(getName() || ''); - const [createName, setCreateName] = useState(''); - const [joinName, setJoinName] = useState(getRoomId() || ''); - const { notify } = props; - - return ( -
- - WATCH PARTY - -
- (e.target.value.length <= 24 ? setName(e.target.value) : null)} - className="name-field" - label="Name" - variant="filled" - helperText={name.length > 0 ? `${name.length}/24` : null} - InputProps={{ - endAdornment: ( - - saveName({ name, notify })}> - - - - ), - }} - /> - - - CREATE PARTY - - (e.target.value.length <= 24 ? setCreateName(e.target.value) : null)} - helperText={createName.length > 0 ? `${createName.length}/24` : null} - label="Party Name" - /> - - - - - JOIN PARTY - - setJoinName(e.target.value)} - label="Party Code" - helperText="Ask your party leader for this code" - /> - - -
-
- ); -}; - -export default Create; diff --git a/src/Inactive.js b/src/Inactive.js deleted file mode 100644 index ab81e9a..0000000 --- a/src/Inactive.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import { Typography } from '@material-ui/core'; -import { Warning } from '@material-ui/icons'; - -const Inactive = (props) => ( -
- - PARTY IS PAUSED FOR A LITTLE CLEANUP - {props.status.message} -
-); - -export default Inactive; diff --git a/src/Loading.js b/src/Loading.js deleted file mode 100644 index e377817..0000000 --- a/src/Loading.js +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react'; -import { CircularProgress } from '@material-ui/core'; - -const Loading = () => ( -
- -
-); - -export default Loading; diff --git a/src/Thread.css b/src/Thread.css deleted file mode 100644 index 102db89..0000000 --- a/src/Thread.css +++ /dev/null @@ -1,95 +0,0 @@ -.thread-item { - width: 100%; - white-space: pre-wrap; - margin-top: 25px !important; - font-size: 12px !important; - position: relative; -} -.thread-item.no-space { - margin-top: 0 !important; -} -.system-message { - display: block; - text-align: center; - width: 100%; - text-align: center; - font-size: 12px; - margin-top: 7.5px !important; - color: rgba(147, 147, 147, 0.8) !important; -} -.system-message.alert { - background-color: black; - border-radius: 1rem; - color: white !important; - padding: 5px 10px; - position: sticky; - top: 2px; - z-index: 1; -} -.my-message { - display: block; - width: fit-content; - text-align: right; - margin-left: auto !important; - margin-right: 5px !important; - margin-top: 5px !important; - padding: 2.5px 10px !important; - border-radius: 13px; - max-width: 60%; - word-wrap: break-word; - background-color: rgb(49, 49, 49); -} -img.my-message { - margin-right: 0 !important; - padding-right: 0 !important; - border-radius: 1rem; - max-width: 60%; - background: none; - border-radius: 2rem; -} -.party-message { - font-size: 1rem !important; - display: block; - width: fit-content; - max-width: 60%; - word-wrap: break-word; - margin-top: 5px !important; - padding: 2.5px 10px !important; - border-radius: 13px; - background-color: rgb(88, 88, 88); -} -img.party-message { - border-radius: 1rem; - max-width: 60%; - background: none; - border-radius: 2rem; - margin-left: 0 !important; - padding-left: 0 !important; -} -.thread-item .name { - color: rgb(149, 149, 149); - font-size: 10px !important; -} -.time { - top: 0; - color: #3a3a3a; - position: absolute; - opacity: 0; - transition: all ease-in-out 0.3s; -} -.party-message ~ .time { - right: 0; -} -.party-message:hover ~ .time { - opacity: 1; -} -.my-message ~ .time { - left: 0; -} -.my-message:hover ~ .time { - opacity: 1; -} -body.hulu .my-message, -body.hulu .party-message { - font-size: 1.4rem !important; -} diff --git a/src/Thread.js b/src/Thread.js deleted file mode 100644 index 7a5f77b..0000000 --- a/src/Thread.js +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react'; -import { Typography } from '@material-ui/core'; -import './Thread.css'; -import firebase from 'firebase/app'; -import 'firebase/firestore'; - -const Thread = (props) => - props.messages.map((m, midx) => { - const userUid = window.localStorage.getItem('watchPartyUserUid'); - if (m.uid === '') { - if (m.name === '') { - return ( - - {m.text} - - ); - } - return ( - - {m.text} - - ); - } else if (m.uid === userUid) { - return ( -
0 ? (props.messages[midx - 1].uid !== m.uid ? '' : 'no-space') : '' - }`} - key={m.id} - > - {m.type === 'giphy' ? ( - giphy gif - ) : ( - - {m.text} - - )} - {new Date(m.time.seconds * 1000).toLocaleTimeString()} -
- ); - } else { - return ( -
0 ? (props.messages[midx - 1].uid !== m.uid ? '' : 'no-space') : '' - }`} - key={m.id} - > - - {midx > 0 ? (props.messages[midx - 1].uid !== m.uid ? m.name : '') : m.name} - - {m.type === 'giphy' ? ( - giphy gif - ) : ( - - {m.text} - - )} - {new Date(m.time.seconds * 1000).toLocaleTimeString()} -
- ); - } - }); - -export default Thread; diff --git a/src/VideoListener.js b/src/VideoListener.js deleted file mode 100644 index ff250cd..0000000 --- a/src/VideoListener.js +++ /dev/null @@ -1,304 +0,0 @@ -import { PLAYER_STATUS, getPlayerSource, PLAYER_SOURCE } from './Api'; - -const templateListener = (video) => console.log('MISSING VIDEO LISTENER'); - -export default class VideoListener { - constructor(listener = templateListener) { - this.video = { - status: PLAYER_STATUS.NOT_PLAYING, - time: 0, - showName: '', - source: '', - element: null, - }; - this.isUpdating = false; - this.listener = listener; - this.updateStatus = this.updateStatus.bind(this); - this.firstTimeSync = this.firstTimeSync.bind(this); - this.doUpdate = this.doUpdate.bind(this); - this.start = this.start.bind(this); - this.onpause = this.onpause.bind(this); - this.onplay = this.onplay.bind(this); - this.shouldPushSync = this.shouldPushSync.bind(this); - } - shouldPushSync() { - return ( - this.isUpdating === false && - this.server !== null && - this.server !== undefined && - this.video.element !== null && - this.video.element !== undefined && - this.video.status !== PLAYER_STATUS.NOT_PLAYING && - this.video.showName !== '' && - this.video.showName !== null && - (this.video.status !== this.server.status || - Math.abs(this.video.element.currentTime - this.server.time) > 1.5) - ); - } - updateStatus(newStatus) { - this.video = Object.assign({}, this.video, newStatus); - if (this.shouldPushSync()) { - this.listener({ - ...this.video, - showChanged: this.video.showName !== this.server.showName, - }); - } - } - async doUpdate(serverPlayer) { - this.server = serverPlayer; - if ( - this.isUpdating === false && - serverPlayer.showName === this.video.showName && - serverPlayer.updatedBy !== window.localStorage.getItem('watchPartyUserUid') - ) { - this.isUpdating = true; - if (this.video.element) { - // REMOVE LISTENER BEFORE SYNCING - this.video.element.removeEventListener('playing', this.onplay); - this.video.element.removeEventListener('pause', this.onpause); - await this.timeout(250); - // SEEK - if (Math.abs(serverPlayer.time - this.video.element.currentTime) > 1.5) { - switch (serverPlayer.source) { - case PLAYER_SOURCE.NETFLIX: - window.postMessage({ type: 'SEEK', time: serverPlayer.time * 1000 }, '*'); - break; - case PLAYER_SOURCE.AMAZON: - if (this.video.status === PLAYER_STATUS.PAUSED) - await this.video.element - .play() - .catch((err) => console.error('WatchParty erred when syncing time.')); - this.video.element.currentTime = serverPlayer.time; - await this.timeout(500); - break; - case PLAYER_SOURCE.DISNEY: - this.video.element.currentTime = serverPlayer.time; - await this.timeout(500); - break; - case PLAYER_SOURCE.YOUTUBE: - this.video.element.currentTime = serverPlayer.time; - break; - case PLAYER_SOURCE.HULU: - window.postMessage({ type: 'SEEK', time: serverPlayer.time }, '*'); - break; - default: - break; - } - } - // TOGGLE PLAYER STATUS - switch (serverPlayer.status) { - case PLAYER_STATUS.PAUSED: - if ( - PLAYER_SOURCE.HULU === this.video.source || - PLAYER_SOURCE.NETFLIX === this.video.source - ) - window.postMessage({ type: 'PAUSE', time: serverPlayer.time }, '*'); - else await this.video.element.pause(); - break; - case PLAYER_STATUS.PLAYING: - if ( - PLAYER_SOURCE.HULU === this.video.source || - PLAYER_SOURCE.NETFLIX === this.video.source - ) - window.postMessage({ type: 'PLAY', time: serverPlayer.time }, '*'); - else - await this.video.element - .play() - .catch((err) => console.error('WatchParty erred when syncing play.')); - break; - default: - break; - } - await this.timeout(500); - // RE-ADD LISTENERS FOR FUTURE SYNC - this.video.element.addEventListener('playing', this.onplay); - this.video.element.addEventListener('pause', this.onpause); - } - this.isUpdating = false; - } - } - timeout(n) { - return new Promise((resolve, reject) => { - setTimeout(resolve, n); - }); - } - async 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') - ? titleContainer.querySelector('h4').innerHTML - : titleContainer.innerHTML; - let nepisode = ''; - titleContainer.querySelectorAll('span').forEach((e) => { - if (e.innerHTML) nepisode += e.innerHTML + ' '; - }); - return nshow === '' && nepisode === '' ? null : nshow + '\n' + nepisode; - } - break; - case PLAYER_SOURCE.AMAZON: - const ashow = document.querySelector('.f3w9jrr.ff48h02').firstChild.innerHTML; - const aepisode = document.querySelector('.f3w9jrr.ff48h02').lastChild.innerHTML; - return ashow === '' && aepisode === '' ? null : ashow + '\n' + aepisode; - 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 === '' ? null : hshow + '\n' + hepisode; - case PLAYER_SOURCE.DISNEY: - this.video.element.parentElement.click(); - await this.timeout(200); - const dshow = document.querySelector('.title-field') - ? document.querySelector('.title-field').innerHTML - : ''; - const depisode = document.querySelector('.subtitle-field') - ? document.querySelector('.subtitle-field').innerHTML - : ''; - return dshow === '' && depisode === '' ? null : dshow + '\n' + depisode; - case PLAYER_SOURCE.YOUTUBE: - const yshow = document.querySelector('h1.title').innerText; - const yepisode = document.querySelector('yt-formatted-string.super-title').innerText; - return yshow === '' && yepisode === '' ? null : yshow + '\n' + yepisode; - default: - break; - } - } - async onplay(ev) { - this.updateStatus({ - status: PLAYER_STATUS.PLAYING, - time: this.video.element.currentTime, - showName: await this.getShowName(), - }); - } - async onpause(ev) { - this.updateStatus({ - status: PLAYER_STATUS.PAUSED, - time: this.video.element.currentTime, - showName: await this.getShowName(), - }); - } - async firstTimeSync(videoElement) { - this.updateStatus({ - element: videoElement, - }); - this.updateStatus({ - showName: await this.getShowName(), - }); - // if (videoElement.currentTime > 0 && !videoElement.paused) { - // this.updateStatus({ - // time: videoElement.currentTime, - // status: PLAYER_STATUS.PLAYING, - // }); - // } - videoElement.addEventListener('playing', this.onplay); - videoElement.addEventListener('pause', this.onpause); - } - async start() { - this.updateStatus({ source: getPlayerSource(), showName: await this.getShowName() }); - switch (this.video.source) { - case PLAYER_SOURCE.NETFLIX: - const seekInject = `window.seekScriptLoaded=!0;var getVideoPlayer=function(){var e=window.netflix.appContext.state.playerApp.getAPI().videoPlayer,t=e.getAllPlayerSessionIds()[0];return e.getVideoPlayerBySessionId(t)},seekInteraction=function(e){if(e.source==window){if(e.data.type&&"SEEK"==e.data.type){getVideoPlayer().pause();getVideoPlayer().seek(e.data.time);}if(e.data.type&&e.data.type==="PAUSE"){getVideoPlayer().pause();}if(e.data.type&&e.data.type==="PLAY"){getVideoPlayer().play();}e.data.type&&"teardown"==e.data.type&&(window.removeEventListener("message",seekInteraction,!1),window.seekScriptLoaded=!1)}};window.addEventListener("message",seekInteraction,!1);`; - const seekInjectScript = document.createElement('script'); - seekInjectScript.text = seekInject; - document.head.appendChild(seekInjectScript); - if (document.getElementsByClassName('AkiraPlayer')[0]) { - const videoElement = document - .getElementsByClassName('AkiraPlayer')[0] - .getElementsByTagName('video')[0]; - if (videoElement) { - this.firstTimeSync(videoElement); - } - } else { - document.addEventListener('DOMNodeInserted', (e) => { - if (e.target) { - if (e.target.classList) { - 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; - case PLAYER_SOURCE.HULU: - const huluSeekInject = `window.seekScriptLoaded=!0;var getVideoPlayer=function(){var e=document.getElementsByClassName('content-video-player')[0].__HuluDashPlayer__;return e;},seekInteraction=function(e){if(e.source==window){if(e.data.type&&"SEEK"==e.data.type){getVideoPlayer().seek(e.data.time,e.data.time);}if(e.data.type&&e.data.type==="PAUSE"){getVideoPlayer().pause();}if(e.data.type&&e.data.type==="PLAY"){getVideoPlayer().play();}e.data.type&&"teardown"==e.data.type&&(window.removeEventListener("message",seekInteraction,!1),window.seekScriptLoaded=!1)}};window.addEventListener("message",seekInteraction,!1);`; - const huluSeekInjectScript = document.createElement('script'); - huluSeekInjectScript.text = huluSeekInject; - document.head.appendChild(huluSeekInjectScript); - const videoElement = document.getElementsByClassName('content-video-player')[0]; - if (videoElement) { - this.firstTimeSync(videoElement); - } - break; - case PLAYER_SOURCE.AMAZON: - if (document.getElementsByClassName('webPlayerSDKContainer')[0]) { - const videoElement = document - .getElementsByClassName('webPlayerSDKContainer')[0] - .getElementsByTagName('video')[0]; - if (videoElement) { - this.firstTimeSync(videoElement); - } - } - break; - case PLAYER_SOURCE.DISNEY: - const disneyVideoElement = document.querySelector('video.btm-media-client-element'); - if (disneyVideoElement) { - this.firstTimeSync(disneyVideoElement); - } else { - setInterval( - this.video.element - ? null - : () => { - var dve = document.querySelector('video.btm-media-client-element'); - if (dve !== null && (this.video.element !== dve || this.video.element === null)) { - this.firstTimeSync(dve); - } - }, - 1000 - ); - } - break; - case PLAYER_SOURCE.YOUTUBE: - const youtubeVideoElement = document.querySelector('video.video-stream.html5-main-video'); - if (youtubeVideoElement) this.firstTimeSync(youtubeVideoElement); - else { - setInterval( - this.video.element - ? null - : () => { - var yve = document.querySelector('video.video-stream.html5-main-video'); - if (yve !== null && (this.video.element !== yve || this.video.element === null)) { - this.firstTimeSync(yve); - } - }, - 1000 - ); - } - break; - case PLAYER_SOURCE.LOCAL: - const localVideoElement = document.getElementsByTagName('video')[0]; - if (localVideoElement) { - this.firstTimeSync(localVideoElement); - } - break; - default: - break; - } - } - end() { - if (this.video.element) { - this.video.element.removeEventListener('playing', this.onplay); - this.video.element.removeEventListener('pause', this.onpause); - } - } -} diff --git a/src/index.css b/src/index.css deleted file mode 100644 index ea36fe5..0000000 --- a/src/index.css +++ /dev/null @@ -1,302 +0,0 @@ -:root { - --party-width: 350px; - --neg-party-width: -350px; - --body-width: calc(100% - var(--party-width)); -} -body { - margin: 0 !important; - background-color: black; - transition: max-width ease-in-out 0.35s; -} -body.visible { - width: var(--body-width); -} -body.visible .watch-party-fab { - right: var(--party-width) !important; - transform: translateX(50%); - top: 1.5rem; -} -body.visible .party-notification-container { - display: block !important; -} - -body.netflix.visible .AkiraPlayer, /* NETFLIX */ -body.hulu.visible .Player__container,/* HULU */ -body.amazon-prime.visible #dv-web-player.dv-player-fullscreen, /* AMAZON PRIME */ -body.disney.visible #hudson-wrapper, /* DISNEY */ -body.youtube.visible #content.ytd-app, /* YOUTUBE */ -body.youtube.visible #masthead-container, /* YOUTUBE HEADER */ -body.hbo.visible video.default { - max-width: var(--body-width) !important; -} -/* HULU MINIMIZED VIDEO */ -body.hulu.visible #__player__ .Player__container.Player__container--modal { - right: calc(var(--party-width) + 2rem) !important; - z-index: 99999 !important; -} -/* HULU, DISNEY & AMAZON PRIME FIX */ -body.disney #party-routes-wrapper, -body.hulu #party-routes-wrapper, -body.amazon-prime #party-routes-wrapper { - width: var(--party-width) !important; - height: 100% !important; -} -/* DISNEY FULL SCREEN VIDEO FIX */ -body.disney #hudson-wrapper { - left: 0; -} -/* YOUTUBE VIDEO SIZING FIX */ -body.youtube.visible video { - max-width: 100%; - height: auto !important; -} -body.youtube.visible .ytp-chrome-bottom { - max-width: 100% !important; - width: calc(100% - 24px) !important; -} -body.youtube.visible .ytp-chapter-hover-container { - max-width: 100% !important; -} -body.youtube.visible .ytp-tooltip.ytp-bottom.ytp-preview { - bottom: 100px !important; - top: unset !important; -} -body.youtube.visible td-two-column-browse-results-renderer.grid:not(.grid-disabled) { - max-width: calc(100% - 48px); -} -/* AMAZON STYLING FIX */ -body.amazon-prime input, -body.amazon-prime textarea { - background-color: inherit !important; - border: initial !important; - box-shadow: none !important; -} -body.amazon-prime input.MuiInputBase-input { - height: 1.1876em !important; - padding: 6px 0 7px !important; -} -body.amazon-prime input.MuiFilledInput-inputAdornedEnd { - padding-right: 0 !important; -} -body.amazon-prime input.MuiFilledInput-input { - padding: 27px 12px 10px !important; -} -body.amazon-prime input:focus, -body.amazon-prime textarea:focus { - border: none !important; - box-shadow: none !important; -} - -@keyframes backgroundpulse { - 0% { - background-color: black; - color: red; - } - 50% { - background-color: red; - color: black; - } - 100% { - background-color: black; - color: red; - } -} -#party-loading { - position: absolute; - width: 100%; - height: 100%; - z-index: 9999; - background-color: rgba(0, 0, 0, 0.8); - display: flex; - top: 0; - left: 0; - align-items: center; - justify-content: center; -} -#party-loading.inactive { - flex-direction: column; - text-align: center; - animation-duration: 4s; - animation-timing-function: linear; - animation-iteration-count: infinite; - animation-name: backgroundpulse; -} -#party-routes-wrapper { - margin: 0; - position: fixed; - background-color: rgb(27, 27, 27); - bottom: 0; - width: calc(var(--party-width) - 2rem); - right: var(--neg-party-width); - transition: all ease-in-out 0.3s; - height: calc(100% - 2rem); - padding: 1rem; - color: white; - display: flex; - flex-direction: column; - z-index: 9999; -} -#party-routes-wrapper.visible { - right: 0; -} -.party-notification-container { - z-index: 99999 !important; - display: none !important; - bottom: 0.8rem !important; - right: 1rem !important; - width: calc(var(--party-width) - 2rem) !important; -} -.party-notification-container .MuiPaper-root { - border-radius: 26px !important; - color: white; - background-color: black; -} -@keyframes showbutton { - 0% { - right: 1rem; - } - 50% { - transform: scale(5) translateX(-100%) translateY(-100%); - } - 100% { - right: -1rem; - transform: scale(1); - } -} -.watch-party-fab { - z-index: 9999; - position: fixed !important; - bottom: 1rem !important; - right: -2rem !important; - border: 1px solid white; - background-color: black !important; - /* background-image: url('/android-icon-192x192.png'); */ - background-image: url('chrome-extension://__MSG_@@extension_id__/android-icon-192x192.png'); - background-position: center; - background-repeat: no-repeat; - background-size: 2rem; - animation-name: showbutton; - animation-iteration-count: 1; - animation-duration: 2s; - transition: all ease-in-out 0.3s !important; -} -.watch-party-fab:hover { - right: 1rem !important; -} -.watch-party-fab .fab-logo { - max-width: 75%; - max-height: 75%; -} - -.party-create-container { - display: flex; - flex-direction: column; - height: 100%; -} -.party-create-container .brand-title { - padding-top: 1.4rem !important; - padding-left: 3.5rem !important; -} -.party-create-container .name-field { - margin-bottom: 2rem !important; -} -.party-create-container .join-card { - padding: 1rem !important; - margin-bottom: 2rem; -} -.party-create-container .join-card .card-field { - margin-bottom: 1rem !important; -} -.party-create-container .party-create-inputs { - flex: 1; - display: flex; - flex-direction: column; - justify-content: center; - padding: 2rem; -} - -.party-chat-container { - display: flex; - max-height: 100%; - flex-direction: column; - flex: 1; -} - -.thread-container { - max-height: 100%; - flex: 1; - overflow-y: auto; - margin-bottom: 1rem; - margin-top: 1rem; -} -.room-title { - text-overflow: ellipsis !important; - word-break: break-word !important; - overflow: hidden !important; - padding-right: 1rem !important; -} -.thread-container::-webkit-scrollbar { - width: 5px; -} -.thread-container::-webkit-scrollbar-track { - background-color: rgb(90, 90, 90); - border-radius: 1rem; -} -.thread-container::-webkit-scrollbar-thumb { - background-color: rgb(118, 182, 255); - border-radius: 13px; -} -textarea::-webkit-scrollbar { - display: none; -} -.chat-message-box > div { - border-radius: 26px; -} -.party-chat-header { - display: flex; - align-items: flex-start; - padding-left: 2.25rem; -} -.party-chat-header-text { - flex: 1; -} -.party-controls { - margin-top: 2rem; -} -.party-controls .MuiButton-startIcon { - margin-right: 0px !important; -} -.party-control-button-text { - display: none; -} -.party-controls button:hover .party-control-button-text { - display: initial; -} -.party-controls button:hover .MuiButton-startIcon { - margin-right: 8px !important; -} -.giphy-carousel { - margin-top: 1rem; - min-height: fit-content; -} -.giphy-carousel img { - border-radius: 1rem; - transform: scale(0.85); - transition: all ease-in-out 0.2s; -} -.giphy-carousel img:hover { - transform: scale(0.95); -} - -.giphy-carousel::-webkit-scrollbar { - width: 5px; - height: 5px; -} -.giphy-carousel::-webkit-scrollbar-track { - background-color: rgb(90, 90, 90); - border-radius: 1rem; -} -.giphy-carousel::-webkit-scrollbar-thumb { - background-color: rgb(118, 182, 255); - border-radius: 13px; -} diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 70335f7..0000000 --- a/src/index.js +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import firebase from 'firebase/app'; -import App from './App'; -import './index.css'; -import { PLAYER_SOURCE, getPlayerSource } from './Api'; - -const firebaseConfig = { - apiKey: 'AIzaSyCJLuYpzXLDRmu2ttzFuSGmYcpFxqToWFU', - 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); - -const PartyWrapper = document.createElement('div'); -PartyWrapper.id = 'party_wrapper'; -document.body.appendChild(PartyWrapper); - -switch (getPlayerSource()) { - case PLAYER_SOURCE.NETFLIX: - document.body.classList.add('netflix'); - break; - 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'); - const ds = document.createElement('script'); - ds.text = `window.doquery=function(){window.huluPlayer=window.queryObjects(window.HuluMediaPlayer);}`; - document.head.appendChild(ds); - break; - case PLAYER_SOURCE.AMAZON: - document.body.classList.add('amazon-prime'); - break; - case PLAYER_SOURCE.DISNEY: - document.body.classList.add('disney'); - break; - case PLAYER_SOURCE.YOUTUBE: - document.body.classList.add('youtube'); - break; - case PLAYER_SOURCE.HBONOW: - document.body.classList.add('hbo'); - break; - case PLAYER_SOURCE.LOCAL: - break; - default: - break; -} - -ReactDOM.render( - - - , - PartyWrapper -);