Merge pull request #1 from MarconLP/feature/screen-recording
Add in-browser recording
This commit is contained in:
commit
d89e9a41b2
5 changed files with 840 additions and 74 deletions
454
package-lock.json
generated
454
package-lock.json
generated
|
|
@ -22,6 +22,7 @@
|
|||
"@trpc/next": "^10.18.0",
|
||||
"@trpc/react-query": "^10.18.0",
|
||||
"@trpc/server": "^10.18.0",
|
||||
"@types/recordrtc": "^5.6.11",
|
||||
"@upstash/qstash": "^0.3.6",
|
||||
"axios": "^1.3.5",
|
||||
"dayjs": "^1.11.7",
|
||||
|
|
@ -32,8 +33,10 @@
|
|||
"next-auth": "^4.21.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-media-recorder": "^1.6.6",
|
||||
"react-player": "^2.12.0",
|
||||
"react-popper": "^2.3.0",
|
||||
"recordrtc": "^5.6.2",
|
||||
"stripe": "^12.1.1",
|
||||
"superjson": "1.12.2",
|
||||
"zod": "^3.21.4"
|
||||
|
|
@ -2404,6 +2407,11 @@
|
|||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/recordrtc": {
|
||||
"version": "5.6.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/recordrtc/-/recordrtc-5.6.11.tgz",
|
||||
"integrity": "sha512-X4XD5nltz0cjmyzsPNegQReOPF+C5ARTfSPAPhqnKV7SsfRta/M4FBJ5AtSInCaEveL71FLLSVQE9mg8Uuo++w=="
|
||||
},
|
||||
"node_modules/@types/scheduler": {
|
||||
"version": "0.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
|
||||
|
|
@ -2814,6 +2822,18 @@
|
|||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/automation-events": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/automation-events/-/automation-events-5.0.3.tgz",
|
||||
"integrity": "sha512-ZZWTNYJTkGjcJUOBX5P0MHZrArJOkcrQsbyGWwlzJpZs961Y5YvKUw5MsAf8xLlvh7+1B8SO/VTvjMmVXFkD3w==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"tslib": "^2.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.15.4"
|
||||
}
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.4.14",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz",
|
||||
|
|
@ -2929,6 +2949,17 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/broker-factory": {
|
||||
"version": "3.0.75",
|
||||
"resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.0.75.tgz",
|
||||
"integrity": "sha512-VMC2GBMaoKXdVPC0yH/Z1NbDieYRuKlGPT6PbrrReDwvHSZH2Cl5dJVO3tPTkA9Q+xXOmnRYgcjNktZD/Oz21w==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"fast-unique-numbers": "^7.0.2",
|
||||
"tslib": "^2.5.0",
|
||||
"worker-factory": "^6.0.76"
|
||||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.21.5",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
|
||||
|
|
@ -3129,6 +3160,20 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/compilerr": {
|
||||
"version": "10.0.2",
|
||||
"resolved": "https://registry.npmjs.org/compilerr/-/compilerr-10.0.2.tgz",
|
||||
"integrity": "sha512-CFwUXxJ9OuWsSvnLSbefxi+GLsZ0YnuJh40ry5QdmZ1FWK59OG+QB8XSj6t7Kq+/c5DSS7en+cML6GlzHKH58A==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"dashify": "^2.0.0",
|
||||
"indefinite-article": "0.0.2",
|
||||
"tslib": "^2.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.15.4"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
|
|
@ -3203,6 +3248,14 @@
|
|||
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/dashify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dashify/-/dashify-2.0.0.tgz",
|
||||
"integrity": "sha512-hpA5C/YrPjucXypHPPc0oJ1l9Hf6wWbiOL7Ik42cxnsUOhWiCB/fylKbKqqJalW9FgkNQCw16YO8uW9Hs0Iy1A==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.7",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz",
|
||||
|
|
@ -4004,6 +4057,52 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/extendable-media-recorder": {
|
||||
"version": "6.6.10",
|
||||
"resolved": "https://registry.npmjs.org/extendable-media-recorder/-/extendable-media-recorder-6.6.10.tgz",
|
||||
"integrity": "sha512-gnSmLqDFq40ZdbGfuarnMLNqYPLCPpPr0p21V+g67wG4Pv2oCc/ga8sfsZrEM5GywEi7FcpyRm3z99JWZ/0aPw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.9",
|
||||
"media-encoder-host": "^8.0.76",
|
||||
"multi-buffer-data-view": "^3.0.20",
|
||||
"recorder-audio-worklet": "^5.1.26",
|
||||
"standardized-audio-context": "^25.3.29",
|
||||
"subscribable-things": "^2.1.6",
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/extendable-media-recorder-wav-encoder": {
|
||||
"version": "7.0.85",
|
||||
"resolved": "https://registry.npmjs.org/extendable-media-recorder-wav-encoder/-/extendable-media-recorder-wav-encoder-7.0.85.tgz",
|
||||
"integrity": "sha512-M96Y6twJ/OBordRltfyf8Kl2P2C0e176ogVTpGYquHApEyRnGpnm6LMmNqiRkQC8me0WOOhKLVvKCGmEF3lmvQ==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"extendable-media-recorder-wav-encoder-broker": "^7.0.77",
|
||||
"extendable-media-recorder-wav-encoder-worker": "^8.0.76",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/extendable-media-recorder-wav-encoder-broker": {
|
||||
"version": "7.0.77",
|
||||
"resolved": "https://registry.npmjs.org/extendable-media-recorder-wav-encoder-broker/-/extendable-media-recorder-wav-encoder-broker-7.0.77.tgz",
|
||||
"integrity": "sha512-HNUcsUMtKw8hUx1pHM/78+joa3L7FpCh+R3jX9RRuSrHMUw/ldq29wi/evBs4lMoasyMZLHD3yI1Phz0hYH7pg==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"broker-factory": "^3.0.75",
|
||||
"extendable-media-recorder-wav-encoder-worker": "^8.0.76",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/extendable-media-recorder-wav-encoder-worker": {
|
||||
"version": "8.0.76",
|
||||
"resolved": "https://registry.npmjs.org/extendable-media-recorder-wav-encoder-worker/-/extendable-media-recorder-wav-encoder-worker-8.0.76.tgz",
|
||||
"integrity": "sha512-m/pafu/XodKM05r3wkdY6D+gvprD6VCe1rLKnmF/Ooj4VGQ3DglsOhxWmEXRHVtzFWHIxIpjq6Z14VYaj1sXUg==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"tslib": "^2.5.0",
|
||||
"worker-factory": "^6.0.76"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
|
|
@ -4050,6 +4149,18 @@
|
|||
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fast-unique-numbers": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-7.0.2.tgz",
|
||||
"integrity": "sha512-xnqpsnu889bHbq5cbDMwCJ2BPf6kjFPMu+RHfqKvisRxeEbTOVxY5aW/ZNsZ/r8OlwatxmjdFEVQog2xAhLkvg==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"tslib": "^2.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.15.4"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-xml-parser": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.1.2.tgz",
|
||||
|
|
@ -4539,6 +4650,11 @@
|
|||
"node": ">=0.8.19"
|
||||
}
|
||||
},
|
||||
"node_modules/indefinite-article": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/indefinite-article/-/indefinite-article-0.0.2.tgz",
|
||||
"integrity": "sha512-Au/2XzRkvxq2J6w5uvSSbBKPZ5kzINx5F2wb0SF8xpRL8BP9Lav81TnRbfPp6p+SYjYxwaaLn4EUwI3/MmYKSw=="
|
||||
},
|
||||
"node_modules/inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
|
|
@ -5094,6 +5210,40 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/media-encoder-host": {
|
||||
"version": "8.0.88",
|
||||
"resolved": "https://registry.npmjs.org/media-encoder-host/-/media-encoder-host-8.0.88.tgz",
|
||||
"integrity": "sha512-15pWY8GFLsm3w01JuSQdEIkCh1+KUKqNQg5F6s5SXhAwbj0DuTceFbyuqWFMq+XzV8zZrPt8LtYAAj5ld5IEOw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"media-encoder-host-broker": "^7.0.78",
|
||||
"media-encoder-host-worker": "^9.1.0",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/media-encoder-host-broker": {
|
||||
"version": "7.0.78",
|
||||
"resolved": "https://registry.npmjs.org/media-encoder-host-broker/-/media-encoder-host-broker-7.0.78.tgz",
|
||||
"integrity": "sha512-5IZEZwN4qyCymkP6FCELS6rRCE2xhNFiE3FWr+8R3ySRn1iwPWd/U/YFB4PdvjqFw3MtQ9rHFErfc/YjUf8j9g==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"broker-factory": "^3.0.75",
|
||||
"fast-unique-numbers": "^7.0.2",
|
||||
"media-encoder-host-worker": "^9.1.0",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/media-encoder-host-worker": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/media-encoder-host-worker/-/media-encoder-host-worker-9.1.0.tgz",
|
||||
"integrity": "sha512-dVvb65RH/5Yt5PBxBVGw+BcCFkq8A15/fw3HxEKugtaFJocTcwQsS1IeDUuf1i831Fk/FuCipnXFz8VsGRCZyg==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"extendable-media-recorder-wav-encoder-broker": "^7.0.77",
|
||||
"tslib": "^2.5.0",
|
||||
"worker-factory": "^6.0.76"
|
||||
}
|
||||
},
|
||||
"node_modules/memoize-one": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
||||
|
|
@ -5196,6 +5346,18 @@
|
|||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/multi-buffer-data-view": {
|
||||
"version": "3.0.24",
|
||||
"resolved": "https://registry.npmjs.org/multi-buffer-data-view/-/multi-buffer-data-view-3.0.24.tgz",
|
||||
"integrity": "sha512-jm7Ycplx37ExXyQmqhwl7zfQmAj81y5LLzVx0XyWea4omP9W/xJhLEHs/5b+WojGyYSRt8BHiXZVcYzu68Ma0Q==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"tslib": "^2.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.1"
|
||||
}
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||
|
|
@ -6046,6 +6208,15 @@
|
|||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/react-media-recorder": {
|
||||
"version": "1.6.6",
|
||||
"resolved": "https://registry.npmjs.org/react-media-recorder/-/react-media-recorder-1.6.6.tgz",
|
||||
"integrity": "sha512-VdC4bUINMWJyqOAHw1DaZ8HZhdCyVBK85zJ4cHMo9tsrekui3wq5ZxNtBmNe6nbAFQBTNj/pRnLEsiVrCW+TNQ==",
|
||||
"dependencies": {
|
||||
"extendable-media-recorder": "^6.6.5",
|
||||
"extendable-media-recorder-wav-encoder": "^7.0.68"
|
||||
}
|
||||
},
|
||||
"node_modules/react-player": {
|
||||
"version": "2.12.0",
|
||||
"resolved": "https://registry.npmjs.org/react-player/-/react-player-2.12.0.tgz",
|
||||
|
|
@ -6104,6 +6275,35 @@
|
|||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/recorder-audio-worklet": {
|
||||
"version": "5.1.39",
|
||||
"resolved": "https://registry.npmjs.org/recorder-audio-worklet/-/recorder-audio-worklet-5.1.39.tgz",
|
||||
"integrity": "sha512-w/RazoBwZnkFnEPRsJYNThOHznLQC98/IzWRrutpJQVvCcL0nbLsVSLDaRrnrqVpRUI11VgiXRh30HaHiSdVhQ==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"broker-factory": "^3.0.75",
|
||||
"fast-unique-numbers": "^7.0.2",
|
||||
"recorder-audio-worklet-processor": "^4.2.21",
|
||||
"standardized-audio-context": "^25.3.41",
|
||||
"subscribable-things": "^2.1.14",
|
||||
"tslib": "^2.5.0",
|
||||
"worker-factory": "^6.0.76"
|
||||
}
|
||||
},
|
||||
"node_modules/recorder-audio-worklet-processor": {
|
||||
"version": "4.2.21",
|
||||
"resolved": "https://registry.npmjs.org/recorder-audio-worklet-processor/-/recorder-audio-worklet-processor-4.2.21.tgz",
|
||||
"integrity": "sha512-oiiS2sp6eMxkvjt13yetSYUJvnAxBZk60mIxz0Vf/2lDWa/4svCyMLHIDzYKbHahkISd0UYyqLS9dI7xDlUOCA==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/recordrtc": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/recordrtc/-/recordrtc-5.6.2.tgz",
|
||||
"integrity": "sha512-1QNKKNtl7+KcwD1lyOgP3ZlbiJ1d0HtXnypUy7yq49xEERxk31PHvE9RCciDrulPCY7WJ+oz0R9hpNxgsIurGQ=="
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||
|
|
@ -6200,6 +6400,11 @@
|
|||
"queue-microtask": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/rxjs-interop": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/rxjs-interop/-/rxjs-interop-2.0.0.tgz",
|
||||
"integrity": "sha512-ASEq9atUw7lualXB+knvgtvwkCEvGWV2gDD/8qnASzBkzEARZck9JAyxmY8OS6Nc1pCPEgDTKNcx+YqqYfzArw=="
|
||||
},
|
||||
"node_modules/safe-regex-test": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
|
||||
|
|
@ -6317,6 +6522,16 @@
|
|||
"source-map": "^0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/standardized-audio-context": {
|
||||
"version": "25.3.43",
|
||||
"resolved": "https://registry.npmjs.org/standardized-audio-context/-/standardized-audio-context-25.3.43.tgz",
|
||||
"integrity": "sha512-Wh/6rZCScDh3ZAsRy0kgeGF+g3mGO4E6UiWj8k79uCHKJjqiBJOtbwEFS1MBFfVXMHN3L3U3kn1aVrkCHtlkvw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"automation-events": "^5.0.3",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/statuses": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
||||
|
|
@ -6481,6 +6696,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/subscribable-things": {
|
||||
"version": "2.1.14",
|
||||
"resolved": "https://registry.npmjs.org/subscribable-things/-/subscribable-things-2.1.14.tgz",
|
||||
"integrity": "sha512-+0e6wGpFVa7snrwzY/xwiiQhlpBglvPAhsYK9EhFAcboP5z0eN1W3CQoROYyeY3psiCbwcleb9vaXasKAcvISw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"rxjs-interop": "^2.0.0",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sucrase": {
|
||||
"version": "3.32.0",
|
||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz",
|
||||
|
|
@ -6995,6 +7220,17 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/worker-factory": {
|
||||
"version": "6.0.76",
|
||||
"resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-6.0.76.tgz",
|
||||
"integrity": "sha512-W1iBNPmE9p0asU4aFmYJYCnMxhkvk4qlKc660GlHxWgmflY64NxxTbmKqipu4K5p9LiKKPjqXfcQme6153BZEQ==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"compilerr": "^10.0.2",
|
||||
"fast-unique-numbers": "^7.0.2",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
|
|
@ -8759,6 +8995,11 @@
|
|||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/recordrtc": {
|
||||
"version": "5.6.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/recordrtc/-/recordrtc-5.6.11.tgz",
|
||||
"integrity": "sha512-X4XD5nltz0cjmyzsPNegQReOPF+C5ARTfSPAPhqnKV7SsfRta/M4FBJ5AtSInCaEveL71FLLSVQE9mg8Uuo++w=="
|
||||
},
|
||||
"@types/scheduler": {
|
||||
"version": "0.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
|
||||
|
|
@ -9032,6 +9273,15 @@
|
|||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"automation-events": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/automation-events/-/automation-events-5.0.3.tgz",
|
||||
"integrity": "sha512-ZZWTNYJTkGjcJUOBX5P0MHZrArJOkcrQsbyGWwlzJpZs961Y5YvKUw5MsAf8xLlvh7+1B8SO/VTvjMmVXFkD3w==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"autoprefixer": {
|
||||
"version": "10.4.14",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz",
|
||||
|
|
@ -9113,6 +9363,17 @@
|
|||
"fill-range": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"broker-factory": {
|
||||
"version": "3.0.75",
|
||||
"resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.0.75.tgz",
|
||||
"integrity": "sha512-VMC2GBMaoKXdVPC0yH/Z1NbDieYRuKlGPT6PbrrReDwvHSZH2Cl5dJVO3tPTkA9Q+xXOmnRYgcjNktZD/Oz21w==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"fast-unique-numbers": "^7.0.2",
|
||||
"tslib": "^2.5.0",
|
||||
"worker-factory": "^6.0.76"
|
||||
}
|
||||
},
|
||||
"browserslist": {
|
||||
"version": "4.21.5",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
|
||||
|
|
@ -9241,6 +9502,17 @@
|
|||
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
|
||||
"dev": true
|
||||
},
|
||||
"compilerr": {
|
||||
"version": "10.0.2",
|
||||
"resolved": "https://registry.npmjs.org/compilerr/-/compilerr-10.0.2.tgz",
|
||||
"integrity": "sha512-CFwUXxJ9OuWsSvnLSbefxi+GLsZ0YnuJh40ry5QdmZ1FWK59OG+QB8XSj6t7Kq+/c5DSS7en+cML6GlzHKH58A==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"dashify": "^2.0.0",
|
||||
"indefinite-article": "0.0.2",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
|
|
@ -9294,6 +9566,11 @@
|
|||
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
|
||||
"dev": true
|
||||
},
|
||||
"dashify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dashify/-/dashify-2.0.0.tgz",
|
||||
"integrity": "sha512-hpA5C/YrPjucXypHPPc0oJ1l9Hf6wWbiOL7Ik42cxnsUOhWiCB/fylKbKqqJalW9FgkNQCw16YO8uW9Hs0Iy1A=="
|
||||
},
|
||||
"dayjs": {
|
||||
"version": "1.11.7",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz",
|
||||
|
|
@ -9914,6 +10191,52 @@
|
|||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||
"dev": true
|
||||
},
|
||||
"extendable-media-recorder": {
|
||||
"version": "6.6.10",
|
||||
"resolved": "https://registry.npmjs.org/extendable-media-recorder/-/extendable-media-recorder-6.6.10.tgz",
|
||||
"integrity": "sha512-gnSmLqDFq40ZdbGfuarnMLNqYPLCPpPr0p21V+g67wG4Pv2oCc/ga8sfsZrEM5GywEi7FcpyRm3z99JWZ/0aPw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.18.9",
|
||||
"media-encoder-host": "^8.0.76",
|
||||
"multi-buffer-data-view": "^3.0.20",
|
||||
"recorder-audio-worklet": "^5.1.26",
|
||||
"standardized-audio-context": "^25.3.29",
|
||||
"subscribable-things": "^2.1.6",
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"extendable-media-recorder-wav-encoder": {
|
||||
"version": "7.0.85",
|
||||
"resolved": "https://registry.npmjs.org/extendable-media-recorder-wav-encoder/-/extendable-media-recorder-wav-encoder-7.0.85.tgz",
|
||||
"integrity": "sha512-M96Y6twJ/OBordRltfyf8Kl2P2C0e176ogVTpGYquHApEyRnGpnm6LMmNqiRkQC8me0WOOhKLVvKCGmEF3lmvQ==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"extendable-media-recorder-wav-encoder-broker": "^7.0.77",
|
||||
"extendable-media-recorder-wav-encoder-worker": "^8.0.76",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"extendable-media-recorder-wav-encoder-broker": {
|
||||
"version": "7.0.77",
|
||||
"resolved": "https://registry.npmjs.org/extendable-media-recorder-wav-encoder-broker/-/extendable-media-recorder-wav-encoder-broker-7.0.77.tgz",
|
||||
"integrity": "sha512-HNUcsUMtKw8hUx1pHM/78+joa3L7FpCh+R3jX9RRuSrHMUw/ldq29wi/evBs4lMoasyMZLHD3yI1Phz0hYH7pg==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"broker-factory": "^3.0.75",
|
||||
"extendable-media-recorder-wav-encoder-worker": "^8.0.76",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"extendable-media-recorder-wav-encoder-worker": {
|
||||
"version": "8.0.76",
|
||||
"resolved": "https://registry.npmjs.org/extendable-media-recorder-wav-encoder-worker/-/extendable-media-recorder-wav-encoder-worker-8.0.76.tgz",
|
||||
"integrity": "sha512-m/pafu/XodKM05r3wkdY6D+gvprD6VCe1rLKnmF/Ooj4VGQ3DglsOhxWmEXRHVtzFWHIxIpjq6Z14VYaj1sXUg==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"tslib": "^2.5.0",
|
||||
"worker-factory": "^6.0.76"
|
||||
}
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
|
|
@ -9956,6 +10279,15 @@
|
|||
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
|
||||
"dev": true
|
||||
},
|
||||
"fast-unique-numbers": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-7.0.2.tgz",
|
||||
"integrity": "sha512-xnqpsnu889bHbq5cbDMwCJ2BPf6kjFPMu+RHfqKvisRxeEbTOVxY5aW/ZNsZ/r8OlwatxmjdFEVQog2xAhLkvg==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"fast-xml-parser": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.1.2.tgz",
|
||||
|
|
@ -10293,6 +10625,11 @@
|
|||
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
|
||||
"dev": true
|
||||
},
|
||||
"indefinite-article": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/indefinite-article/-/indefinite-article-0.0.2.tgz",
|
||||
"integrity": "sha512-Au/2XzRkvxq2J6w5uvSSbBKPZ5kzINx5F2wb0SF8xpRL8BP9Lav81TnRbfPp6p+SYjYxwaaLn4EUwI3/MmYKSw=="
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
|
|
@ -10688,6 +11025,40 @@
|
|||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"media-encoder-host": {
|
||||
"version": "8.0.88",
|
||||
"resolved": "https://registry.npmjs.org/media-encoder-host/-/media-encoder-host-8.0.88.tgz",
|
||||
"integrity": "sha512-15pWY8GFLsm3w01JuSQdEIkCh1+KUKqNQg5F6s5SXhAwbj0DuTceFbyuqWFMq+XzV8zZrPt8LtYAAj5ld5IEOw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"media-encoder-host-broker": "^7.0.78",
|
||||
"media-encoder-host-worker": "^9.1.0",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"media-encoder-host-broker": {
|
||||
"version": "7.0.78",
|
||||
"resolved": "https://registry.npmjs.org/media-encoder-host-broker/-/media-encoder-host-broker-7.0.78.tgz",
|
||||
"integrity": "sha512-5IZEZwN4qyCymkP6FCELS6rRCE2xhNFiE3FWr+8R3ySRn1iwPWd/U/YFB4PdvjqFw3MtQ9rHFErfc/YjUf8j9g==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"broker-factory": "^3.0.75",
|
||||
"fast-unique-numbers": "^7.0.2",
|
||||
"media-encoder-host-worker": "^9.1.0",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"media-encoder-host-worker": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/media-encoder-host-worker/-/media-encoder-host-worker-9.1.0.tgz",
|
||||
"integrity": "sha512-dVvb65RH/5Yt5PBxBVGw+BcCFkq8A15/fw3HxEKugtaFJocTcwQsS1IeDUuf1i831Fk/FuCipnXFz8VsGRCZyg==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"extendable-media-recorder-wav-encoder-broker": "^7.0.77",
|
||||
"tslib": "^2.5.0",
|
||||
"worker-factory": "^6.0.76"
|
||||
}
|
||||
},
|
||||
"memoize-one": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
||||
|
|
@ -10765,6 +11136,15 @@
|
|||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"multi-buffer-data-view": {
|
||||
"version": "3.0.24",
|
||||
"resolved": "https://registry.npmjs.org/multi-buffer-data-view/-/multi-buffer-data-view-3.0.24.tgz",
|
||||
"integrity": "sha512-jm7Ycplx37ExXyQmqhwl7zfQmAj81y5LLzVx0XyWea4omP9W/xJhLEHs/5b+WojGyYSRt8BHiXZVcYzu68Ma0Q==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"tslib": "^2.4.1"
|
||||
}
|
||||
},
|
||||
"mz": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||
|
|
@ -11269,6 +11649,15 @@
|
|||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"react-media-recorder": {
|
||||
"version": "1.6.6",
|
||||
"resolved": "https://registry.npmjs.org/react-media-recorder/-/react-media-recorder-1.6.6.tgz",
|
||||
"integrity": "sha512-VdC4bUINMWJyqOAHw1DaZ8HZhdCyVBK85zJ4cHMo9tsrekui3wq5ZxNtBmNe6nbAFQBTNj/pRnLEsiVrCW+TNQ==",
|
||||
"requires": {
|
||||
"extendable-media-recorder": "^6.6.5",
|
||||
"extendable-media-recorder-wav-encoder": "^7.0.68"
|
||||
}
|
||||
},
|
||||
"react-player": {
|
||||
"version": "2.12.0",
|
||||
"resolved": "https://registry.npmjs.org/react-player/-/react-player-2.12.0.tgz",
|
||||
|
|
@ -11314,6 +11703,35 @@
|
|||
"picomatch": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"recorder-audio-worklet": {
|
||||
"version": "5.1.39",
|
||||
"resolved": "https://registry.npmjs.org/recorder-audio-worklet/-/recorder-audio-worklet-5.1.39.tgz",
|
||||
"integrity": "sha512-w/RazoBwZnkFnEPRsJYNThOHznLQC98/IzWRrutpJQVvCcL0nbLsVSLDaRrnrqVpRUI11VgiXRh30HaHiSdVhQ==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"broker-factory": "^3.0.75",
|
||||
"fast-unique-numbers": "^7.0.2",
|
||||
"recorder-audio-worklet-processor": "^4.2.21",
|
||||
"standardized-audio-context": "^25.3.41",
|
||||
"subscribable-things": "^2.1.14",
|
||||
"tslib": "^2.5.0",
|
||||
"worker-factory": "^6.0.76"
|
||||
}
|
||||
},
|
||||
"recorder-audio-worklet-processor": {
|
||||
"version": "4.2.21",
|
||||
"resolved": "https://registry.npmjs.org/recorder-audio-worklet-processor/-/recorder-audio-worklet-processor-4.2.21.tgz",
|
||||
"integrity": "sha512-oiiS2sp6eMxkvjt13yetSYUJvnAxBZk60mIxz0Vf/2lDWa/4svCyMLHIDzYKbHahkISd0UYyqLS9dI7xDlUOCA==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"recordrtc": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/recordrtc/-/recordrtc-5.6.2.tgz",
|
||||
"integrity": "sha512-1QNKKNtl7+KcwD1lyOgP3ZlbiJ1d0HtXnypUy7yq49xEERxk31PHvE9RCciDrulPCY7WJ+oz0R9hpNxgsIurGQ=="
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||
|
|
@ -11371,6 +11789,11 @@
|
|||
"queue-microtask": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"rxjs-interop": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/rxjs-interop/-/rxjs-interop-2.0.0.tgz",
|
||||
"integrity": "sha512-ASEq9atUw7lualXB+knvgtvwkCEvGWV2gDD/8qnASzBkzEARZck9JAyxmY8OS6Nc1pCPEgDTKNcx+YqqYfzArw=="
|
||||
},
|
||||
"safe-regex-test": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
|
||||
|
|
@ -11461,6 +11884,16 @@
|
|||
"source-map": "^0.6.0"
|
||||
}
|
||||
},
|
||||
"standardized-audio-context": {
|
||||
"version": "25.3.43",
|
||||
"resolved": "https://registry.npmjs.org/standardized-audio-context/-/standardized-audio-context-25.3.43.tgz",
|
||||
"integrity": "sha512-Wh/6rZCScDh3ZAsRy0kgeGF+g3mGO4E6UiWj8k79uCHKJjqiBJOtbwEFS1MBFfVXMHN3L3U3kn1aVrkCHtlkvw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"automation-events": "^5.0.3",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"statuses": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
||||
|
|
@ -11572,6 +12005,16 @@
|
|||
"client-only": "0.0.1"
|
||||
}
|
||||
},
|
||||
"subscribable-things": {
|
||||
"version": "2.1.14",
|
||||
"resolved": "https://registry.npmjs.org/subscribable-things/-/subscribable-things-2.1.14.tgz",
|
||||
"integrity": "sha512-+0e6wGpFVa7snrwzY/xwiiQhlpBglvPAhsYK9EhFAcboP5z0eN1W3CQoROYyeY3psiCbwcleb9vaXasKAcvISw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"rxjs-interop": "^2.0.0",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"sucrase": {
|
||||
"version": "3.32.0",
|
||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz",
|
||||
|
|
@ -11939,6 +12382,17 @@
|
|||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
||||
"dev": true
|
||||
},
|
||||
"worker-factory": {
|
||||
"version": "6.0.76",
|
||||
"resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-6.0.76.tgz",
|
||||
"integrity": "sha512-W1iBNPmE9p0asU4aFmYJYCnMxhkvk4qlKc660GlHxWgmflY64NxxTbmKqipu4K5p9LiKKPjqXfcQme6153BZEQ==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"compilerr": "^10.0.2",
|
||||
"fast-unique-numbers": "^7.0.2",
|
||||
"tslib": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
"@trpc/next": "^10.18.0",
|
||||
"@trpc/react-query": "^10.18.0",
|
||||
"@trpc/server": "^10.18.0",
|
||||
"@types/recordrtc": "^5.6.11",
|
||||
"@upstash/qstash": "^0.3.6",
|
||||
"axios": "^1.3.5",
|
||||
"dayjs": "^1.11.7",
|
||||
|
|
@ -39,8 +40,10 @@
|
|||
"next-auth": "^4.21.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-media-recorder": "^1.6.6",
|
||||
"react-player": "^2.12.0",
|
||||
"react-popper": "^2.3.0",
|
||||
"recordrtc": "^5.6.2",
|
||||
"stripe": "^12.1.1",
|
||||
"superjson": "1.12.2",
|
||||
"zod": "^3.21.4"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,272 @@
|
|||
import React, { useState, useRef, Fragment, useEffect } from "react";
|
||||
import RecordRTC, { invokeSaveAsDialog } from "recordrtc";
|
||||
import { Listbox, Transition } from "@headlessui/react";
|
||||
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/react/20/solid";
|
||||
import { MicrophoneIcon, PauseIcon } from "@heroicons/react/24/outline";
|
||||
import { ResumeIcon, TrashIcon } from "@radix-ui/react-icons";
|
||||
import { StopIcon } from "@heroicons/react/24/solid";
|
||||
import StopTime from "~/components/StopTime";
|
||||
import axios from "axios";
|
||||
import dayjs from "dayjs";
|
||||
import { useRouter } from "next/router";
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
export default function Recorder() {
|
||||
const [steam, setStream] = useState<null | MediaStream>(null);
|
||||
const [blob, setBlob] = useState<null | Blob>(null);
|
||||
const refVideo = useRef<null | HTMLVideoElement>(null);
|
||||
const recorderRef = useRef<null | RecordRTC>(null);
|
||||
const [pause, setPause] = useState<boolean>(false);
|
||||
const [audioDevices, setAudioDevices] = useState<MediaDeviceInfo[]>([]);
|
||||
const [selectedDevice, setSelectedDevice] = useState<MediaDeviceInfo | null>(
|
||||
null
|
||||
);
|
||||
const [step, setStep] = useState<"pre" | "in" | "post">("pre");
|
||||
const router = useRouter();
|
||||
const [submitting, setSubmitting] = useState<boolean>(false);
|
||||
const apiUtils = api.useContext();
|
||||
const getSignedUrl = api.video.getUploadUrl.useMutation();
|
||||
|
||||
const handleRecording = async () => {
|
||||
const screenStream = await navigator.mediaDevices.getDisplayMedia({
|
||||
video: {
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
frameRate: 30,
|
||||
},
|
||||
audio: {
|
||||
echoCancellation: true,
|
||||
noiseSuppression: true,
|
||||
sampleRate: 44100,
|
||||
},
|
||||
});
|
||||
|
||||
const micStream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: { deviceId: selectedDevice?.deviceId },
|
||||
});
|
||||
|
||||
const mediaStream = new MediaStream();
|
||||
micStream.getAudioTracks().forEach((track) => mediaStream.addTrack(track));
|
||||
screenStream
|
||||
.getVideoTracks()
|
||||
.forEach((track) => mediaStream.addTrack(track));
|
||||
|
||||
setStream(mediaStream);
|
||||
recorderRef.current = new RecordRTC(mediaStream, { type: "video" });
|
||||
recorderRef.current.startRecording();
|
||||
|
||||
setStep("in");
|
||||
};
|
||||
|
||||
const handleStop = () => {
|
||||
if (recorderRef.current === null) return;
|
||||
recorderRef.current.stopRecording(() => {
|
||||
if (recorderRef.current) {
|
||||
setBlob(recorderRef.current.getBlob());
|
||||
steam?.getTracks().map((track) => track.stop());
|
||||
}
|
||||
});
|
||||
|
||||
setStep("post");
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
if (recorderRef.current === null) return;
|
||||
setBlob(null);
|
||||
recorderRef.current.stopRecording(() => {
|
||||
steam?.getTracks().map((track) => track.stop());
|
||||
});
|
||||
};
|
||||
|
||||
const handlePause = () => {
|
||||
if (recorderRef.current) {
|
||||
console.log(recorderRef.current?.state);
|
||||
if (pause) {
|
||||
recorderRef.current?.resumeRecording();
|
||||
} else {
|
||||
recorderRef.current.pauseRecording();
|
||||
}
|
||||
setPause(!pause);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function getAudioDevices() {
|
||||
try {
|
||||
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||
const audioDevices = devices.filter(
|
||||
(device) => device.kind === "audioinput"
|
||||
);
|
||||
setAudioDevices(audioDevices);
|
||||
if (audioDevices[0]) setSelectedDevice(audioDevices[0]);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
void getAudioDevices();
|
||||
}, []);
|
||||
|
||||
const handleSave = () => {
|
||||
if (blob) {
|
||||
const dateString =
|
||||
"Recording - " + dayjs().format("D MMM YYYY") + ".webm";
|
||||
invokeSaveAsDialog(blob, dateString);
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpload = async () => {
|
||||
if (!blob) return;
|
||||
const dateString = "Recording - " + dayjs().format("D MMM YYYY") + ".webm";
|
||||
setSubmitting(true);
|
||||
const { signedUrl, id } = await getSignedUrl.mutateAsync({
|
||||
key: dateString,
|
||||
});
|
||||
await axios
|
||||
.put(signedUrl, blob.slice(), {
|
||||
headers: { "Content-Type": "video/webm" },
|
||||
})
|
||||
.then(() => {
|
||||
void router.push("share/" + id);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
setSubmitting(false);
|
||||
void apiUtils.video.getAll.invalidate();
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{step === "pre" ? (
|
||||
<div className="w-full">
|
||||
<Listbox value={selectedDevice} onChange={setSelectedDevice}>
|
||||
<div className="relative mt-1">
|
||||
<Listbox.Button className="relative flex w-full cursor-default flex-row items-center justify-start rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 sm:text-sm">
|
||||
<MicrophoneIcon
|
||||
className="mr-2 h-5 w-5 text-gray-400"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span className="block truncate">
|
||||
{selectedDevice?.label ?? "No device selected"}
|
||||
</span>
|
||||
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
<ChevronUpDownIcon
|
||||
className="h-5 w-5 text-gray-400"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
</Listbox.Button>
|
||||
<Transition
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<Listbox.Options className="absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
|
||||
{audioDevices.map((audioDevice, i) => (
|
||||
<Listbox.Option
|
||||
key={i}
|
||||
className={({ active }) =>
|
||||
`relative cursor-default select-none py-2 pl-10 pr-4 text-gray-900 ${
|
||||
active ? "bg-gray-200" : ""
|
||||
}`
|
||||
}
|
||||
value={audioDevice}
|
||||
>
|
||||
{({ selected }) => (
|
||||
<>
|
||||
<span
|
||||
className={`block truncate ${
|
||||
selected ? "font-medium" : "font-normal"
|
||||
}`}
|
||||
>
|
||||
{audioDevice.label}
|
||||
</span>
|
||||
{selected ? (
|
||||
<span className="absolute inset-y-0 left-0 flex items-center pl-3 text-amber-600">
|
||||
<CheckIcon
|
||||
className="h-5 w-5"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</Listbox.Option>
|
||||
))}
|
||||
</Listbox.Options>
|
||||
</Transition>
|
||||
</div>
|
||||
</Listbox>
|
||||
<button
|
||||
type="button"
|
||||
className="mt-4 flex inline-flex w-full items-center items-center justify-center rounded-md bg-indigo-500 px-4 py-2 text-sm font-semibold leading-6 text-white shadow transition duration-150 ease-in-out hover:bg-indigo-400 disabled:cursor-not-allowed"
|
||||
onClick={() => void handleRecording()}
|
||||
>
|
||||
<span>Start recording</span>
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
{step === "in" ? (
|
||||
<div className="flex flex-row items-center justify-center">
|
||||
<div
|
||||
onClick={handleStop}
|
||||
className="flex cursor-pointer flex-row items-center justify-center rounded pr-2 text-lg hover:bg-gray-200"
|
||||
>
|
||||
<StopIcon className="h-8 w-8 text-[#ff623f]" aria-hidden="true" />
|
||||
<StopTime running={!pause} />
|
||||
</div>
|
||||
<div className="mx-2 h-6 w-px bg-[#E7E9EB]"></div>
|
||||
<div
|
||||
onClick={handlePause}
|
||||
className="cursor-pointer rounded p-1 hover:bg-gray-200"
|
||||
>
|
||||
{pause ? (
|
||||
<ResumeIcon
|
||||
className="h-6 w-6 text-gray-400"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
) : (
|
||||
<PauseIcon className="h-6 w-6 text-gray-400" aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
onClick={handleDelete}
|
||||
className="ml-1 cursor-pointer rounded p-1 hover:bg-gray-200"
|
||||
>
|
||||
<TrashIcon className="h-6 w-6 text-gray-400" aria-hidden="true" />
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{step === "post" ? (
|
||||
<div>
|
||||
{blob && (
|
||||
<video
|
||||
src={URL.createObjectURL(blob)}
|
||||
controls
|
||||
autoPlay
|
||||
ref={refVideo}
|
||||
style={{ width: "700px", margin: "1em" }}
|
||||
/>
|
||||
)}
|
||||
<button
|
||||
onClick={handleSave}
|
||||
className="mt-2 rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
|
||||
>
|
||||
Download
|
||||
</button>
|
||||
<button
|
||||
onClick={() => void handleUpload()}
|
||||
className="ml-2 mt-2 rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
|
||||
>
|
||||
Upload
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
39
src/components/StopTime.tsx
Normal file
39
src/components/StopTime.tsx
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
|
||||
export default function StopTime({ running }: { running?: boolean }) {
|
||||
const [secs, setSecs] = useState<number>(0);
|
||||
|
||||
const calculateTimeDuration = (secs: number): string => {
|
||||
const hr = Math.floor(secs / 3600).toString();
|
||||
let min = Math.floor((secs - parseInt(hr) * 3600) / 60).toString();
|
||||
let sec = Math.floor(
|
||||
secs - parseInt(hr) * 3600 - parseInt(min) * 60
|
||||
).toString();
|
||||
|
||||
if (parseInt(min) < 10) {
|
||||
min = "0" + min;
|
||||
}
|
||||
|
||||
if (parseInt(sec) < 10) {
|
||||
sec = "0" + sec;
|
||||
}
|
||||
|
||||
if (parseInt(hr) <= 0) {
|
||||
return min + ":" + sec;
|
||||
}
|
||||
|
||||
return hr + ":" + min + ":" + sec;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!running) return;
|
||||
const interval = setInterval(() => setSecs((sec) => sec + 1), 1000);
|
||||
return () => clearInterval(interval);
|
||||
}, [running]);
|
||||
|
||||
return (
|
||||
<div className="ml-1 flex w-10 items-center justify-center">
|
||||
<span className="text-sm">{calculateTimeDuration(secs)}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@ import { Dialog, Transition } from "@headlessui/react";
|
|||
import { api } from "~/utils/api";
|
||||
import axios from "axios";
|
||||
import { useRouter } from "next/router";
|
||||
const Recorder = dynamic(() => import("~/components/Recorder"), { ssr: false });
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
export default function VideoUploadModal() {
|
||||
const router = useRouter();
|
||||
|
|
@ -56,19 +58,11 @@ export default function VideoUploadModal() {
|
|||
</span>
|
||||
|
||||
<Transition appear show={isOpen} as={Fragment}>
|
||||
<Dialog as="div" className="relative z-10" onClose={closeModal}>
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div className="fixed inset-0 bg-black bg-opacity-25" />
|
||||
</Transition.Child>
|
||||
|
||||
<Dialog
|
||||
as="div"
|
||||
className="relative z-10"
|
||||
onClose={() => void closeModal}
|
||||
>
|
||||
<div className="fixed inset-0 overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center p-4 text-center">
|
||||
<Transition.Child
|
||||
|
|
@ -80,77 +74,81 @@ export default function VideoUploadModal() {
|
|||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
<Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-lg bg-white p-6 text-left align-middle shadow-xl transition-all">
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<label className="flex h-32 w-full min-w-[300px] cursor-pointer appearance-none justify-center rounded-md border-2 border-dashed border-gray-300 px-4 transition hover:border-gray-400 focus:outline-none">
|
||||
<span className="flex items-center space-x-2 text-[#292D34]">
|
||||
{file ? (
|
||||
<span className="font-medium">{file.name}</span>
|
||||
) : (
|
||||
<Dialog.Panel className="w-full max-w-md transform rounded-lg bg-white p-6 text-left align-middle shadow-xl transition-all">
|
||||
{1 + 1 === 2 ? (
|
||||
<Recorder />
|
||||
) : (
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<label className="flex h-32 w-full min-w-[300px] cursor-pointer appearance-none justify-center rounded-md border-2 border-dashed border-gray-300 px-4 transition hover:border-gray-400 focus:outline-none">
|
||||
<span className="flex items-center space-x-2 text-[#292D34]">
|
||||
{file ? (
|
||||
<span className="font-medium">{file.name}</span>
|
||||
) : (
|
||||
<>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
|
||||
/>
|
||||
</svg>
|
||||
<span className="font-medium">
|
||||
{"Drop files to Attach, or browse"}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
<input
|
||||
accept="video/mp4,video/webm"
|
||||
onChange={handleFileChange}
|
||||
type="file"
|
||||
name="file_upload"
|
||||
className="hidden"
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
className="mt-4 inline-flex items-center rounded-md bg-indigo-500 px-4 py-2 text-sm font-semibold leading-6 text-white shadow transition duration-150 ease-in-out hover:bg-indigo-400 disabled:cursor-not-allowed"
|
||||
disabled={submitting}
|
||||
onClick={() => void handleSubmit()}
|
||||
>
|
||||
{submitting ? (
|
||||
<>
|
||||
<svg
|
||||
className="-ml-1 mr-3 h-5 w-5 animate-spin text-white"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
strokeWidth="4"
|
||||
></circle>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
|
||||
/>
|
||||
className="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
></path>
|
||||
</svg>
|
||||
<span className="font-medium">
|
||||
{"Drop files to Attach, or browse"}
|
||||
</span>
|
||||
Uploading...
|
||||
</>
|
||||
) : (
|
||||
<>Upload</>
|
||||
)}
|
||||
</span>
|
||||
<input
|
||||
accept="video/mp4,video/webm"
|
||||
onChange={handleFileChange}
|
||||
type="file"
|
||||
name="file_upload"
|
||||
className="hidden"
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
className="mt-4 inline-flex items-center rounded-md bg-indigo-500 px-4 py-2 text-sm font-semibold leading-6 text-white shadow transition duration-150 ease-in-out hover:bg-indigo-400 disabled:cursor-not-allowed"
|
||||
disabled={submitting}
|
||||
onClick={() => void handleSubmit()}
|
||||
>
|
||||
{submitting ? (
|
||||
<>
|
||||
<svg
|
||||
className="-ml-1 mr-3 h-5 w-5 animate-spin text-white"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
strokeWidth="4"
|
||||
></circle>
|
||||
<path
|
||||
className="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
></path>
|
||||
</svg>
|
||||
Uploading...
|
||||
</>
|
||||
) : (
|
||||
<>Upload</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue