diff options
Diffstat (limited to 'apps/Youtube')
-rw-r--r-- | apps/Youtube/components/App.js | 126 | ||||
-rw-r--r-- | apps/Youtube/index.js | 3 | ||||
-rw-r--r-- | apps/Youtube/styles/Youtube.module.scss | 1 | ||||
-rw-r--r-- | apps/Youtube/styles/_results.scss | 68 |
4 files changed, 198 insertions, 0 deletions
diff --git a/apps/Youtube/components/App.js b/apps/Youtube/components/App.js new file mode 100644 index 0000000..d902346 --- /dev/null +++ b/apps/Youtube/components/App.js @@ -0,0 +1,126 @@ +import styles from '../styles/Youtube.module.scss' +import { useState } from 'react' +import fetchJson from 'helpers/fetchJson' +import useApps from 'hooks/useApps' +import useSettings from 'hooks/useSettings' +import { open } from 'helpers/windowActions' +import appList from 'configs/appList' +import Splash from 'components/Splash' + +const time = t => new Date(t * 1000).toISOString().substr(11, 8) + +const App = () => { + const { apps, setApps } = useApps() + const [results, setResults] = useState() + const [searching, setSearching] = useState(false) + const [sending, setSending] = useState(false) + const [enqueue, setEnqueue] = useState(false) + const [type, setType] = useState('youtube_videos') + const { t } = useSettings() + + const handleSearch = async e => { + e.preventDefault() + e.stopPropagation() + setSearching(true) + const quote = e.currentTarget.quote.value + + const results = await fetchJson('/api/youtube/search', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ quote }) + }) + + results?.videos && setResults(results.videos) + setSearching(false) + } + + const handlePlay = async url => { + setSending(true) + const data = await fetchJson('/api/youtube/player', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ url }) + }) + + const list = { + items: [{ + id: data.videoDetails.videoId, + title: data.videoDetails.title, + type: 'youtube-video', + sources: data.formats.filter(v => v.hasAudio).sort((a, b) => a.bitrate > b.bitrate) + }], + enqueue + } + + apps && apps.length > 0 && apps.some(a => a && a.name === 'Player') + ? setApps(prev => prev.map(a => a.name === 'Player' ? { ...a, props: { list } } : a)) + : open({ appName: 'Player', ...appList.Player }, setApps, { list }) + + setSending(false) + } + + return ( + <> + <div className='window__submenu'> + <div> + {[ + 'youtube_videos', + 'youtube_music', + 'youtube_live', + 'youtube_channels', + 'youtube_playlists' + ].map(y => ( + <div + className={y === type ? 'active' : ''} + onClick={() => { setType(y); setResults() }} + key={y} + > + {t(y)} + </div> + ))} + <span /> + <div + className={enqueue ? '' : 'off'} + onClick={() => { setEnqueue(e => !e) }} + > + {t('youtube_enqueue')} + </div> + </div> + </div> + <div className={styles.results}> + <form onSubmit={handleSearch}> + <input type='text' name='quote' /> + <input type='submit' className='window__button' value={t('search')} /> + </form> + <div className='window__scroll'> + { + searching + ? ( + <Splash /> + ) + : ( + <ul> + { + results && results.length > 0 && results.map(r => ( + <li key={r.id} onClick={() => handlePlay(r.link)}> + <img loading='lazy' src={r.thumbnail} width={96} height={72} /> + <p>{time(r.duration)}</p> + <div> + <p>{r.title}</p> + <p>Views: {r.views}, uploaded: {r.uploaded || '-'}</p> + <p>{r.channel?.name}</p> + </div> + </li> + )) + } + {sending && <Splash fixed />} + </ul> + ) + } + </div> + </div> + </> + ) +} + +export default App diff --git a/apps/Youtube/index.js b/apps/Youtube/index.js new file mode 100644 index 0000000..8c4906c --- /dev/null +++ b/apps/Youtube/index.js @@ -0,0 +1,3 @@ +import Youtube from './components/App' + +export default Youtube diff --git a/apps/Youtube/styles/Youtube.module.scss b/apps/Youtube/styles/Youtube.module.scss new file mode 100644 index 0000000..eeeaea9 --- /dev/null +++ b/apps/Youtube/styles/Youtube.module.scss @@ -0,0 +1 @@ +@import "results"; diff --git a/apps/Youtube/styles/_results.scss b/apps/Youtube/styles/_results.scss new file mode 100644 index 0000000..854d1e5 --- /dev/null +++ b/apps/Youtube/styles/_results.scss @@ -0,0 +1,68 @@ +.results { + height: 100%; + + form { + padding: .5em; + justify-content: center; + align-items: center; + display: flex; + + input[type=text] { + background-color: var(--color-window-content); + color: var(--color-text-alt); + margin: 1em .5em 0; + height: 2.5rem; + border: none; + border-radius: .5em; + padding: 0.5rem; + font-size: 1rem; + border: 1px dashed var(--color-window-buttons); + flex-shrink: 1; + flex-grow: 1; + + &:placeholder { + font: inherit; + } + } + } + + ul { + display: block; + + & > li { + padding: .5em; + display: flex; + position: relative; + + @media(hover: hover) { + &:hover { + background-color: var(--color-button-alt); + } + } + + & > p { + position: absolute; + font-size: .8em; + background-color: #000; + color: #fff; + border-radius: .5em; + padding: .25em; + bottom: 0.25em; + left: 2em; + } + + & > div { + margin-left: 1em; + display: flex; + flex-direction: column; + // justify-content: space-between; + + & > p:nth-of-type(2) { + margin: .25em 0 .5em; + font-size: .8em; + color: var(--color-decor); + } + } + } + } +} |