diff --git a/src/features/posts/Post.css b/src/features/posts/Post.css index 3395be0..ac7f8d5 100644 --- a/src/features/posts/Post.css +++ b/src/features/posts/Post.css @@ -64,6 +64,19 @@ img, video { color: rgb(97, 49, 95); } +.gallery-statement { + color: rgb(228, 180, 226); +} + +.gallery-statement a { + color: white; + text-decoration: none; +} + +.gallery-statement a:active { + color:rgb(97, 49, 95); +} + .num-comments { display: inline-flex; background-color: #7196be; @@ -80,6 +93,20 @@ img, video { color:rgb(228, 180, 226); } +/* Video player */ + +.video-player { + display: inline-flex; + flex-direction: column; + align-items: center; +} + +#post-audio { + position: relative; + height: 3.5rem; + width: 60%; +} + /* Handles comment styles on toggle */ .comments-visible { diff --git a/src/features/posts/Post.js b/src/features/posts/Post.js index 3882398..f8cb10f 100644 --- a/src/features/posts/Post.js +++ b/src/features/posts/Post.js @@ -1,6 +1,6 @@ import React, { useState, useEffect } from "react"; -// import { useDispatch } from "react-redux"; import Discussion from "../discussion/Discussion"; +import VideoPlayer from "../video/VideoPlayer"; import './Post.css'; export default function Post({data, key}) { @@ -14,11 +14,6 @@ export default function Post({data, key}) { let media = data.post_hint === 'image' && data.url; let permalink = data.permalink; let selftext = data.selftext; - let video = data.is_video ? `${data.url}/DASH_1080.mp4` : null; // to do: handle media edge cases, especially video - - // fallback_url: "https://v.redd.it/0rditq5l49g81/DASH_1080.mp4?source=fallback" - // url: "https://v.redd.it/0rditq5l49g81" - // id: "sm2wym" const limit = 300; const [body, setBody] = useState(selftext); @@ -75,7 +70,7 @@ export default function Post({data, key}) { if (data.crosspost_parent_list[0].is_video) { return ( <> - +

Crosspost from {data.crosspost_parent_list[0].subreddit_name_prefixed}

); @@ -90,6 +85,10 @@ export default function Post({data, key}) { return; } } + + // Render function below: + // Each is preceded by a conditional so the program does not throw an error + // before the fetch requests' promises are fulfilled. return ( <> @@ -99,23 +98,17 @@ export default function Post({data, key}) { {title} :

[untitled]

} - {media ? {title} : ''} - {data.crosspost_parent_list ? handleCrosspost() : ''} + {media ? {title} : null} + + {data.crosspost_parent_list ? handleCrosspost() : null} {data.gallery_data ? -

View the gallery of photos corresponding to this post here.

+

View the gallery of photos corresponding to this post here.

: null} - {video ? - - : ''} + {data.is_video ? + + : null} {body ?

{body}

diff --git a/src/features/video/VideoPlayer.js b/src/features/video/VideoPlayer.js new file mode 100644 index 0000000..634c7d5 --- /dev/null +++ b/src/features/video/VideoPlayer.js @@ -0,0 +1,90 @@ +import { useState, useEffect, useRef } from 'react'; + +export default function VideoPlayer({data, src}) { + const vidControls = useRef(); + const vid = useRef(); + const aud = useRef(); // identifies location of video/audio in DOM + + const [playing, setPlaying] = useState(false); // handles play/pause logic + const [audio, setAudio] = useState(null); + + const crossPostSrc = src; + + let url; // contains video source, routed accordingly by logic below + + if (crossPostSrc) { + url = crossPostSrc; // ... for crossposts + } else if (data.url) { + url = data.url; // ... for local posts, where the url + } else { // can be accessed at data.url + url = null; // otherwise, is null + } + + useEffect(() => { // checks the endpoint where audio may be found + let checking = true; // if the fetch request throws an error, audio is set to null; + const checkForAudio = async() => { // otherwise, audio is set to the endpoint, which is evaluated + try { // below as truthy, and rendered in the page + await fetch(`${url}/DASH_audio.mp4`) + .then((response) => { + let status = response.status; + if (status > 400) { + setAudio(null); + } else { + setAudio(`${url}/DASH_audio.mp4`); + } + }); + } catch(e) { + console.log(e); + } + } + + if (checking) { + checkForAudio(); + checking = false; + } + + return () => { + checking = false; + } + }, [url, audio]); + + useEffect(() => { // this section handles simultaneous playback of audio and video + if (!audio) { + return; + } + + if (playing) { + vid.current.play(); // synchronizes play/pause between two components + vid.current.currentTime = aud.current.currentTime; // according to section of state + } else if (!playing) { + vid.current.pause(); + } + }, [playing, audio, aud, vid]); + + return ( +
+ + { + !audio ? + + <> + + + + : + + <> + + + + + } +
+ ); +} \ No newline at end of file