diff --git a/components/previews/AudioPreview.tsx b/components/previews/AudioPreview.tsx
index 9757c4a..65bf3f6 100644
--- a/components/previews/AudioPreview.tsx
+++ b/components/previews/AudioPreview.tsx
@@ -1,11 +1,12 @@
import type { OdFileObject } from '../../types'
import { FC, useState } from 'react'
-import ReactPlayer from 'react-player'
+import ReactAudioPlayer from 'react-audio-player'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import DownloadButtonGroup from '../DownloadBtnGtoup'
import { DownloadBtnContainer, PreviewContainer } from './Containers'
+import { LoadingIcon } from '../Loading'
enum PlayerState {
Loading,
@@ -23,21 +24,7 @@ const AudioPreview: FC<{ file: OdFileObject }> = ({ file }) => {
{playerStatus === PlayerState.Loading ? (
-
+
) : (
= ({ file }) => {
timeStyle: 'short',
})}
-
{
- setPlayerStatus(PlayerState.Ready)
- }}
- onPlay={() => {
- setPlayerStatus(PlayerState.Playing)
- }}
- onPause={() => {
- setPlayerStatus(PlayerState.Paused)
- }}
+ onCanPlay={() => setPlayerStatus(PlayerState.Ready)}
+ onPlay={() => setPlayerStatus(PlayerState.Playing)}
+ onPause={() => setPlayerStatus(PlayerState.Paused)}
onError={() => setPlayerStatus(PlayerState.Paused)}
onEnded={() => setPlayerStatus(PlayerState.Paused)}
/>
diff --git a/components/previews/VideoPreview.tsx b/components/previews/VideoPreview.tsx
index fe0e6af..2c30b09 100644
--- a/components/previews/VideoPreview.tsx
+++ b/components/previews/VideoPreview.tsx
@@ -1,7 +1,7 @@
import type { OdFileObject } from '../../types'
-import ReactPlayer from 'react-player'
import { useRouter } from 'next/router'
import { useClipboard } from 'use-clipboard-copy'
+import DPlayer from 'react-dplayer'
import toast from 'react-hot-toast'
import { getBaseUrl } from '../../utils/getBaseUrl'
@@ -12,16 +12,19 @@ const VideoPreview: React.FC<{ file: OdFileObject }> = ({ file }) => {
const { asPath } = useRouter()
const clipboard = useClipboard()
+ // OneDrive generates thumbnails for its video files, we pick the thumbnail with the highest resolution
+ const thumbnail = file.thumbnails && file.thumbnails.length > 0 ? file.thumbnails[0].large.url : ''
+
return (
<>
-
diff --git a/package.json b/package.json
index 0633330..19546ae 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,6 @@
"axios": "^0.25.0",
"cors": "^2.8.5",
"crypto-js": "^4.1.1",
- "csstype": "^3.0.10",
"emoji-regex": "^10.0.0",
"ioredis": "^4.28.2",
"jszip": "^3.7.1",
@@ -29,12 +28,13 @@
"prismjs": "^1.23.0",
"react": "^17.0.2",
"react-async-hook": "^4.0.0",
+ "react-audio-player": "^0.17.0",
"react-copy-to-clipboard": "^5.0.3",
"react-dom": "^17.0.2",
+ "react-dplayer": "^0.4.2",
"react-hot-toast": "^2.0.0",
"react-hotkeys-hook": "^3.4.4",
"react-markdown": "^8.0.0",
- "react-player": "^2.9.0",
"react-reader": "^0.20.4",
"react-viewer": "^3.2.2",
"rehype-katex": "^6.0.2",
diff --git a/pages/api/index.ts b/pages/api/index.ts
index e59aab8..5addae6 100644
--- a/pages/api/index.ts
+++ b/pages/api/index.ts
@@ -210,6 +210,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
headers: { Authorization: `Bearer ${accessToken}` },
params: {
select: '@microsoft.graph.downloadUrl,name,size,id,lastModifiedDateTime,folder,file,video,image',
+ $expand: 'thumbnails',
},
})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c058c63..c678e7c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -21,7 +21,6 @@ specifiers:
axios: ^0.25.0
cors: ^2.8.5
crypto-js: ^4.1.1
- csstype: ^3.0.10
emoji-regex: ^10.0.0
eslint: 8.8.0
eslint-config-next: 12.0.10
@@ -34,12 +33,13 @@ specifiers:
prismjs: ^1.23.0
react: ^17.0.2
react-async-hook: ^4.0.0
+ react-audio-player: ^0.17.0
react-copy-to-clipboard: ^5.0.3
react-dom: ^17.0.2
+ react-dplayer: ^0.4.2
react-hot-toast: ^2.0.0
react-hotkeys-hook: ^3.4.4
react-markdown: ^8.0.0
- react-player: ^2.9.0
react-reader: ^0.20.4
react-viewer: ^3.2.2
rehype-katex: ^6.0.2
@@ -63,7 +63,6 @@ dependencies:
axios: 0.25.0
cors: 2.8.5
crypto-js: 4.1.1
- csstype: 3.0.10
emoji-regex: 10.0.0
ioredis: 4.28.3
jszip: 3.7.1
@@ -73,12 +72,13 @@ dependencies:
prismjs: 1.26.0
react: 17.0.2
react-async-hook: 4.0.0_react@17.0.2
+ react-audio-player: 0.17.0_react-dom@17.0.2+react@17.0.2
react-copy-to-clipboard: 5.0.4_react@17.0.2
react-dom: 17.0.2_react@17.0.2
- react-hot-toast: 2.2.0_cf9e547307deef37c34d2702bfa94a69
+ react-dplayer: 0.4.2_react@17.0.2
+ react-hot-toast: 2.2.0_react-dom@17.0.2+react@17.0.2
react-hotkeys-hook: 3.4.4_react-dom@17.0.2+react@17.0.2
react-markdown: 8.0.0_b08e3c15324cbe90a6ff8fcd416c932c
- react-player: 2.9.0_react@17.0.2
react-reader: 0.20.5_react@17.0.2
react-viewer: 3.2.2
rehype-katex: 6.0.2
@@ -388,6 +388,10 @@ packages:
'@types/ms': 0.7.31
dev: false
+ /@types/dplayer/1.25.2:
+ resolution: {integrity: sha512-bkTVZkK3Vi7N7eX2FUBnqKhCjTaeRLkhvY8H6zolatbSTtjPPdxyUzhE3C29sIBYRRq1kQHSduFgCHKg5VF3Jw==}
+ dev: false
+
/@types/hast/2.3.4:
resolution: {integrity: sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==}
dependencies:
@@ -725,6 +729,13 @@ packages:
engines: {node: '>=4'}
dev: true
+ /axios/0.19.2:
+ resolution: {integrity: sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==}
+ deprecated: Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410
+ dependencies:
+ follow-redirects: 1.5.10
+ dev: false
+
/axios/0.25.0:
resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==}
dependencies:
@@ -745,6 +756,10 @@ packages:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
+ /balloon-css/1.2.0:
+ resolution: {integrity: sha512-urXwkHgwp6GsXVF+it01485Z2Cj4pnW02ICnM0TemOlkKmCNnDLmyy+ZZiRXBpwldUXO+aRNr7Hdia4CBvXJ5A==}
+ dev: false
+
/binary-extensions/2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
@@ -844,6 +859,11 @@ packages:
resolution: {integrity: sha512-vooFaGFL6ulEP1liiaWFBmmfuPm3cY3y7T9eB83ZTnYc/oFeAKsq3NcDrOkBC8XaauEE8zHQwI7k0+JSYiVQSQ==}
dev: false
+ /clsx/1.1.1:
+ resolution: {integrity: sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==}
+ engines: {node: '>=6'}
+ dev: false
+
/cluster-key-slot/1.1.0:
resolution: {integrity: sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==}
engines: {node: '>=0.10.0'}
@@ -943,6 +963,7 @@ packages:
/csstype/3.0.10:
resolution: {integrity: sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==}
+ dev: true
/d/1.0.1:
resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==}
@@ -965,6 +986,12 @@ packages:
ms: 2.0.0
dev: true
+ /debug/3.1.0:
+ resolution: {integrity: sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==}
+ dependencies:
+ ms: 2.0.0
+ dev: false
+
/debug/3.2.7:
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
dependencies:
@@ -992,11 +1019,6 @@ packages:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true
- /deepmerge/4.2.2:
- resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==}
- engines: {node: '>=0.10.0'}
- dev: false
-
/define-properties/1.1.3:
resolution: {integrity: sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==}
engines: {node: '>= 0.4'}
@@ -1062,6 +1084,14 @@ packages:
esutils: 2.0.3
dev: true
+ /dplayer/1.26.0:
+ resolution: {integrity: sha512-uOE0w/WdlX7N9d0ppIEcAYrcnUjY52TMX+MBL4lj9Mj+JMljVuaEc5w88HkZp5Q11VqvN/jxnM8ktx2Dr7/MgA==}
+ dependencies:
+ axios: 0.19.2
+ balloon-css: 1.2.0
+ promise-polyfill: 8.1.3
+ dev: false
+
/electron-to-chromium/1.4.61:
resolution: {integrity: sha512-kpzCOOFlx63C9qKRyIDEsKIUgzoe98ump7T4gU+/OLzj8gYkkWf2SIyBjhTSE0keAjMAp3i7C262YtkQOMYrGw==}
dev: true
@@ -1500,6 +1530,13 @@ packages:
optional: true
dev: false
+ /follow-redirects/1.5.10:
+ resolution: {integrity: sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==}
+ engines: {node: '>=4.0'}
+ dependencies:
+ debug: 3.1.0
+ dev: false
+
/fraction.js/4.1.2:
resolution: {integrity: sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==}
dev: true
@@ -1595,12 +1632,10 @@ packages:
slash: 3.0.0
dev: true
- /goober/2.1.7_csstype@3.0.10:
+ /goober/2.1.7:
resolution: {integrity: sha512-aCR8u3A/tTgSrZAHfJObhYC0xgdKoYm4GvE/UFmxmzgvj3TSF+3oFYWtmJ459WBewjOIoEsoOG81sDs1rn+W5w==}
peerDependencies:
csstype: ^2.6.2
- dependencies:
- csstype: 3.0.10
dev: false
/has-bigints/1.0.1:
@@ -2026,10 +2061,6 @@ packages:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
dev: true
- /load-script/1.0.0:
- resolution: {integrity: sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ=}
- dev: false
-
/localforage/1.10.0:
resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==}
dependencies:
@@ -2215,10 +2246,6 @@ packages:
resolution: {integrity: sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=}
dev: false
- /memoize-one/5.2.1:
- resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==}
- dev: false
-
/merge2/1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@@ -2509,7 +2536,6 @@ packages:
/ms/2.0.0:
resolution: {integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=}
- dev: true
/ms/2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
@@ -2665,6 +2691,10 @@ packages:
es-abstract: 1.19.1
dev: true
+ /omit.js/2.0.2:
+ resolution: {integrity: sha512-hJmu9D+bNB40YpL9jYebQl4lsTW6yEHRTroJzNLqQJYHm7c+NQnJGfZmIWh8S3q3KoaxV1aLhV6B3+0N0/kyJg==}
+ dev: false
+
/once/1.4.0:
resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=}
dependencies:
@@ -2863,6 +2893,10 @@ packages:
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
dev: false
+ /promise-polyfill/8.1.3:
+ resolution: {integrity: sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g==}
+ dev: false
+
/prop-types/15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
dependencies:
@@ -2897,6 +2931,17 @@ packages:
react: 17.0.2
dev: false
+ /react-audio-player/0.17.0_react-dom@17.0.2+react@17.0.2:
+ resolution: {integrity: sha512-aCZgusPxA9HK7rLZcTdhTbBH9l6do9vn3NorgoDZRxRxJlOy9uZWzPaKjd7QdcuP2vXpxGA/61JMnnOEY7NXeA==}
+ peerDependencies:
+ react: '>=16'
+ react-dom: '>=16'
+ dependencies:
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ dev: false
+
/react-copy-to-clipboard/5.0.4_react@17.0.2:
resolution: {integrity: sha512-IeVAiNVKjSPeGax/Gmkqfa/+PuMTBhutEvFUaMQLwE2tS0EXrAdgOpWDX26bWTXF3HrioorR7lr08NqeYUWQCQ==}
peerDependencies:
@@ -2918,18 +2963,26 @@ packages:
scheduler: 0.20.2
dev: false
- /react-fast-compare/3.2.0:
- resolution: {integrity: sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==}
+ /react-dplayer/0.4.2_react@17.0.2:
+ resolution: {integrity: sha512-UnI6KaAsnGtP6MSz79lGCAEZko+j0DcKgwfNATtQJL/T/zRs1t3ZJDT/ymbCquuU1e3fADn0Cww1gpNJ3K2TiQ==}
+ peerDependencies:
+ react: ^16.x
+ dependencies:
+ '@types/dplayer': 1.25.2
+ clsx: 1.1.1
+ dplayer: 1.26.0
+ omit.js: 2.0.2
+ react: 17.0.2
dev: false
- /react-hot-toast/2.2.0_cf9e547307deef37c34d2702bfa94a69:
+ /react-hot-toast/2.2.0_react-dom@17.0.2+react@17.0.2:
resolution: {integrity: sha512-248rXw13uhf/6TNDVzagX+y7R8J183rp7MwUMNkcrBRyHj/jWOggfXTGlM8zAOuh701WyVW+eUaWG2LeSufX9g==}
engines: {node: '>=10'}
peerDependencies:
react: '>=16'
react-dom: '>=16'
dependencies:
- goober: 2.1.7_csstype@3.0.10
+ goober: 2.1.7
react: 17.0.2
react-dom: 17.0.2_react@17.0.2
transitivePeerDependencies:
@@ -2980,19 +3033,6 @@ packages:
- supports-color
dev: false
- /react-player/2.9.0_react@17.0.2:
- resolution: {integrity: sha512-jNUkTfMmUhwPPAktAdIqiBcVUKsFKrVGH6Ocutj6535CNfM91yrvWxHg6fvIX8Y/fjYUPoejddwh7qboNV9vGA==}
- peerDependencies:
- react: '>=16.6.0'
- dependencies:
- deepmerge: 4.2.2
- load-script: 1.0.0
- memoize-one: 5.2.1
- prop-types: 15.8.1
- react: 17.0.2
- react-fast-compare: 3.2.0
- dev: false
-
/react-reader/0.20.5_react@17.0.2:
resolution: {integrity: sha512-mg49s+RTm1qDLEMgvQeqh1aMm2T6wLqwevkxcIlPx1/dAP/Q0q9HIXl1N/bAifZQTQIoJt8UMAAyXp8eBzmCag==}
peerDependencies:
diff --git a/types/index.d.ts b/types/index.d.ts
index 91eac21..1872f2f 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -1,9 +1,9 @@
// API response object for /api?path=, this may return either a file or a folder.
// Pagination is also declared here with the 'next' parameter.
-export declare type OdAPIResponse = { file?: OdFileObject; folder?: OdFolderObject; next?: string }
+export type OdAPIResponse = { file?: OdFileObject; folder?: OdFolderObject; next?: string }
// A folder object returned from the OneDrive API. This contains the parameter 'value', which is an array of items
// inside the folder. The items may also be either files or folders.
-export declare type OdFolderObject = {
+export type OdFolderObject = {
'@odata.count': number
'@odata.context': string
'@odata.nextLink'?: string
@@ -20,7 +20,7 @@ export declare type OdFolderObject = {
}>
}
// A file object returned from the OneDrive API. This object may contain 'video' if the file is a video.
-export declare type OdFileObject = {
+export type OdFileObject = {
'@microsoft.graph.downloadUrl': string
'@odata.context': string
name: string
@@ -30,14 +30,16 @@ export declare type OdFileObject = {
file: { mimeType: string; hashes: { quickXorHash: string; sha1Hash?: string; sha256Hash?: string } }
image?: OdImageFile
video?: OdVideoFile
+ 'thumbnails@odata.context'?: string
+ thumbnails?: Array
}
// A representation of a OneDrive image file. Some images do not return a width and height, so types are optional.
-export declare type OdImageFile = {
+export type OdImageFile = {
width?: number
height?: number
}
// A representation of a OneDrive video file. All fields are declared here, but we mainly use 'width' and 'height'.
-export declare type OdVideoFile = {
+export type OdVideoFile = {
width: number
height: number
duration: number
@@ -48,8 +50,14 @@ export declare type OdVideoFile = {
audioFormat: string
audioSamplesPerSecond: number
}
+export type OdThumbnail = {
+ id: string
+ large: { height: number; width: number; url: string }
+ medium: { height: number; width: number; url: string }
+ small: { height: number; width: number; url: string }
+}
// API response object for /api/search?q=. Likewise, this array of items may also contain either files or folders.
-export declare type OdSearchResult = Array<{
+export type OdSearchResult = Array<{
id: string
name: string
file?: OdFileObject