mirror of
https://github.com/mit-regressions/viewer.git
synced 2025-04-09 14:20:15 -04:00
create functional dark mode toggle AND webvtt player!
This commit is contained in:
parent
729b0c94a0
commit
97199d4f7a
104
viewer/package-lock.json
generated
104
viewer/package-lock.json
generated
|
@ -18,10 +18,12 @@
|
|||
"@trpc/server": "^10.0.0",
|
||||
"next": "13.1.1",
|
||||
"next-auth": "^4.18.3",
|
||||
"next-themes": "^0.2.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-player": "^2.11.0",
|
||||
"superjson": "1.9.1",
|
||||
"webvtt-player": "^0.0.16",
|
||||
"zod": "^3.18.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -3043,6 +3045,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/next-themes": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz",
|
||||
"integrity": "sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==",
|
||||
"peerDependencies": {
|
||||
"next": "*",
|
||||
"react": "*",
|
||||
"react-dom": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/next/node_modules/postcss": {
|
||||
"version": "8.4.14",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
|
||||
|
@ -4300,6 +4312,51 @@
|
|||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/webvtt-player": {
|
||||
"version": "0.0.16",
|
||||
"resolved": "https://registry.npmjs.org/webvtt-player/-/webvtt-player-0.0.16.tgz",
|
||||
"integrity": "sha512-I8OBi1wNXj6hQuBNUc2iK72b+Ciz2l0utAn6xlo0qCrhSoM5hOrB1to9RN2cOoRUahx2NgMHGAhDmVsC1tE0oQ==",
|
||||
"dependencies": {
|
||||
"react": "^16.6.0",
|
||||
"react-dom": "^16.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webvtt-player/node_modules/react": {
|
||||
"version": "16.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
|
||||
"integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webvtt-player/node_modules/react-dom": {
|
||||
"version": "16.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz",
|
||||
"integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"scheduler": "^0.19.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webvtt-player/node_modules/scheduler": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
|
||||
"integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
@ -6468,6 +6525,12 @@
|
|||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"next-themes": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz",
|
||||
"integrity": "sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==",
|
||||
"requires": {}
|
||||
},
|
||||
"node-releases": {
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz",
|
||||
|
@ -7296,6 +7359,47 @@
|
|||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||
},
|
||||
"webvtt-player": {
|
||||
"version": "0.0.16",
|
||||
"resolved": "https://registry.npmjs.org/webvtt-player/-/webvtt-player-0.0.16.tgz",
|
||||
"integrity": "sha512-I8OBi1wNXj6hQuBNUc2iK72b+Ciz2l0utAn6xlo0qCrhSoM5hOrB1to9RN2cOoRUahx2NgMHGAhDmVsC1tE0oQ==",
|
||||
"requires": {
|
||||
"react": "^16.6.0",
|
||||
"react-dom": "^16.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": {
|
||||
"version": "16.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
|
||||
"integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2"
|
||||
}
|
||||
},
|
||||
"react-dom": {
|
||||
"version": "16.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz",
|
||||
"integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"scheduler": "^0.19.1"
|
||||
}
|
||||
},
|
||||
"scheduler": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
|
||||
"integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
|
|
@ -19,10 +19,12 @@
|
|||
"@trpc/server": "^10.0.0",
|
||||
"next": "13.1.1",
|
||||
"next-auth": "^4.18.3",
|
||||
"next-themes": "^0.2.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-player": "^2.11.0",
|
||||
"superjson": "1.9.1",
|
||||
"webvtt-player": "^0.0.16",
|
||||
"zod": "^3.18.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
BIN
viewer/public/data/MIT Regressions intro audio.mp3
Normal file
BIN
viewer/public/data/MIT Regressions intro audio.mp3
Normal file
Binary file not shown.
43
viewer/public/data/MIT Regressions intro captions.vtt
Normal file
43
viewer/public/data/MIT Regressions intro captions.vtt
Normal file
|
@ -0,0 +1,43 @@
|
|||
WEBVTT
|
||||
Kind: captions
|
||||
Language: en
|
||||
|
||||
00:00:01.550 --> 00:00:03.361
|
||||
["The Vanishing American Family" by ScubaZ]
|
||||
|
||||
00:00:14.068 --> 00:00:16.837
|
||||
The Massachusetts Institute of Technology began with a promise.
|
||||
|
||||
00:00:19.252 --> 00:00:21.331
|
||||
A promise that with a devotion to technology,
|
||||
|
||||
00:00:22.008 --> 00:00:23.735
|
||||
through rigorous study of math and science,
|
||||
|
||||
00:00:23.939 --> 00:00:25.504
|
||||
we can engineer a better tomorrow.
|
||||
|
||||
00:00:26.603 --> 00:00:27.599
|
||||
we can make
|
||||
|
||||
00:00:27.599 --> 00:00:30.000
|
||||
a Better World.
|
||||
|
||||
00:00:34.095 --> 00:00:35.347
|
||||
In this story,
|
||||
|
||||
00:00:35.347 --> 00:00:37.242
|
||||
we ask a simple question.
|
||||
|
||||
00:00:39.045 --> 00:00:40.283
|
||||
Have we kept our promise?
|
||||
|
||||
00:01:07.526 --> 00:01:10.121
|
||||
MIT was founded in 1861.
|
||||
|
||||
00:01:10.121 --> 00:01:13.448
|
||||
But the Institute as we know it today was born in 1941.
|
||||
|
||||
00:01:13.448 --> 00:01:15.448
|
||||
December 7th, 1941.
|
||||
|
43
viewer/public/data/MIT Regressions intro metadata.vtt
Normal file
43
viewer/public/data/MIT Regressions intro metadata.vtt
Normal file
|
@ -0,0 +1,43 @@
|
|||
WEBVTT
|
||||
Kind: captions
|
||||
Language: en
|
||||
|
||||
00:00:01.550 --> 00:00:03.361
|
||||
["The Vanishing American Family" by ScubaZ]
|
||||
|
||||
00:00:14.068 --> 00:00:16.837
|
||||
The Massachusetts Institute of Technology began with a promise.
|
||||
|
||||
00:00:19.252 --> 00:00:21.331
|
||||
A promise that with a devotion to technology,
|
||||
|
||||
00:00:22.008 --> 00:00:23.735
|
||||
through rigorous study of math and science,
|
||||
|
||||
00:00:23.939 --> 00:00:25.504
|
||||
we can engineer a better tomorrow.
|
||||
|
||||
00:00:26.603 --> 00:00:27.599
|
||||
we can make
|
||||
|
||||
00:00:27.599 --> 00:00:30.000
|
||||
a Better World.
|
||||
|
||||
00:00:34.095 --> 00:00:35.347
|
||||
In this story,
|
||||
|
||||
00:00:35.347 --> 00:00:37.242
|
||||
we ask a simple question.
|
||||
|
||||
00:00:39.045 --> 00:00:40.283
|
||||
Have we kept our promise?
|
||||
|
||||
00:01:07.526 --> 00:01:10.121
|
||||
MIT was founded in 1861.
|
||||
|
||||
00:01:10.121 --> 00:01:13.448
|
||||
But the Institute as we know it today was born in 1941.
|
||||
|
||||
00:01:13.448 --> 00:01:15.448
|
||||
December 7th, 1941.
|
||||
|
|
@ -1,18 +1,47 @@
|
|||
import dynamic from "next/dynamic";
|
||||
const ReactPlayer = dynamic(() => import("react-player/lazy"), { ssr: false });
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { useRouter } from 'next/router';
|
||||
import { Player as WebVttPlayer } from "webvtt-player";
|
||||
|
||||
// functional component PlayerReact that uses ReactPlayer
|
||||
|
||||
// TODO: parameterize video source and VTT source with props (general spec for 3rd party use!)
|
||||
// TODO: parameterize video source and VTT source with props (general spec for 3rd party use!). must define spec.
|
||||
export default function Player() {
|
||||
|
||||
// get files in directory "../../data" without using fs
|
||||
const router = useRouter();
|
||||
|
||||
const audioUrl = router.asPath + 'data/MIT Regressions intro audio.mp3'
|
||||
const transcriptUrl = router.asPath + "data/MIT Regressions intro captions.vtt"
|
||||
const metadataUrl = router.asPath + "data/MIT Regressions intro metadata.vtt"
|
||||
|
||||
return (
|
||||
<div className="player-wrapper">
|
||||
<ReactPlayer
|
||||
className="react-player"
|
||||
url="https://www.youtube.com/watch?v=mToftr444Pc"
|
||||
width="100%"
|
||||
height="100%"
|
||||
/>
|
||||
</div>
|
||||
<>
|
||||
<div className="player-wrapper">
|
||||
<ReactPlayer
|
||||
className="react-player"
|
||||
url="https://youtu.be/TGKk3iwoI9I"
|
||||
width="100%"
|
||||
height="100%"
|
||||
config={{
|
||||
file: {
|
||||
tracks: [
|
||||
{
|
||||
kind: 'subtitles',
|
||||
label: 'test',
|
||||
src: 'subs/mit regressions subtitles unfinished.vtt',
|
||||
srcLang: 'en',
|
||||
default: true
|
||||
},
|
||||
]
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<WebVttPlayer
|
||||
audio={audioUrl}
|
||||
transcript={transcriptUrl}
|
||||
metadata={metadataUrl} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { type Session } from "next-auth";
|
|||
import { SessionProvider } from "next-auth/react";
|
||||
|
||||
import { trpc } from "../utils/trpc";
|
||||
import {ThemeProvider} from 'next-themes'
|
||||
|
||||
import "../styles/globals.css";
|
||||
|
||||
|
@ -12,7 +13,9 @@ const MyApp: AppType<{ session: Session | null }> = ({
|
|||
}) => {
|
||||
return (
|
||||
<SessionProvider session={session}>
|
||||
<Component {...pageProps} />
|
||||
<ThemeProvider attribute="class">
|
||||
<Component {...pageProps} />
|
||||
</ThemeProvider>
|
||||
</SessionProvider>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -5,11 +5,14 @@ import Head from "next/head";
|
|||
import { signIn, signOut, useSession } from "next-auth/react";
|
||||
|
||||
import { trpc } from "../utils/trpc";
|
||||
import {useTheme} from 'next-themes'
|
||||
import Player from '../components/Player'
|
||||
|
||||
const Home: NextPage = () => {
|
||||
|
||||
const hello = trpc.example.hello.useQuery({ text: "from tRPC" });
|
||||
const {theme, setTheme} = useTheme()
|
||||
console.log(theme)
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -18,16 +21,19 @@ const Home: NextPage = () => {
|
|||
<meta name="description" content="Generated by create-t3-app" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
<main className="flex min-h-screen flex-col items-center justify-center bg-black">
|
||||
<main className="flex min-h-screen flex-col items-center justify-center bg-white dark:bg-black">
|
||||
<button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')} className="bg-gray-200 dark:bg-gray-800 text-gray-800 dark:text-gray-200 py-2 px-4 absolute top-4 right-4">
|
||||
toggle theme
|
||||
</button>
|
||||
<div className="container flex flex-col items-center justify-center gap-12 px-4 py-16 ">
|
||||
<h1 className="text-1xl font-extrabold tracking-tight text-white sm:text-[3rem]">
|
||||
<h1 className="text-1xl font-extrabold tracking-tight text-black dark:text-white sm:text-[3rem]">
|
||||
viewer
|
||||
</h1>
|
||||
|
||||
<Player />
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<p className="text-2xl text-white">
|
||||
<p className="text-2xl text-black dark:text-white">
|
||||
{hello.data ? hello.data.greeting : "Loading tRPC query..."}
|
||||
</p>
|
||||
<AuthShowcase />
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: 'class',
|
||||
content: ["./src/**/*.{js,ts,jsx,tsx}"],
|
||||
theme: {
|
||||
fontFamily: {
|
||||
|
|
|
@ -16,6 +16,6 @@
|
|||
"incremental": true,
|
||||
"noUncheckedIndexedAccess": true
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.cjs", "**/*.mjs"],
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.cjs", "**/*.mjs", "webvtt-plaer.d.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
|
1
viewer/webvtt-player.d.ts
vendored
Normal file
1
viewer/webvtt-player.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
declare module 'webvtt-player';
|
Loading…
Reference in New Issue
Block a user