mirror of
https://github.com/mediacms-io/mediacms.git
synced 2024-11-25 09:44:32 +01:00
Timestamp (#430)
* Test
Messing around to figure out docker and whatnot
* Revert "Test"
This reverts commit 43b76932c5
.
* Update docker dev yaml
Update the docker to the environement with the latest version of selenium (and their new arguments), and to be on firefox
* Timestamp on play
Adds the a one time event that jumps to a timestamp if there is a t parameter in the URL
* Timestamp when sharing DRAFT
First draft to show the timestamp when sharing. Missing checkbox and appending the get param to shown link
* Checkbox and update share url
Checkbox show a clean timestamp and the media URL updates with the correct timestamp upon selection
* Cleaning before PR
removing un-necessary modified files
* Clean up before PR - remove statics
* Timestamp in comments
Parse the comments to wrap timestamps with an appropriate anchor
* Forgotten comments and console.logs
* Last touch for PR
- Cleaning media.js for PR
- Using MediaPageStore instead of window.location when wrapping the timestamp in comments
* Screenshot
Adding the screenshot for the user_docs
* PR amends
Amending VideoPlayer componnent to take check if the Get param 't' is a number, and to keep it within the duration of the video.
Required to change the listener from 'play' to 'loadedmetadata' to have access to the video duration (otherwise it was too early)
Also changed the User_doc file to inform users of the timestamp function
This commit is contained in:
parent
fb0f3ee739
commit
e7ae2833d9
BIN
docs/images/Demo1.png
Normal file
BIN
docs/images/Demo1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 350 KiB |
BIN
docs/images/Demo2.png
Normal file
BIN
docs/images/Demo2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
BIN
docs/images/Demo3.png
Normal file
BIN
docs/images/Demo3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
@ -5,6 +5,7 @@
|
|||||||
- [Downloading media](#downloading-media)
|
- [Downloading media](#downloading-media)
|
||||||
- [Adding captions/subtitles](#adding-captionssubtitles)
|
- [Adding captions/subtitles](#adding-captionssubtitles)
|
||||||
- [Search media](#search-media)
|
- [Search media](#search-media)
|
||||||
|
- [Using Timestamps for sharing](#-using-timestamp)
|
||||||
- [Share media](#share-media)
|
- [Share media](#share-media)
|
||||||
- [Embed media](#embed-media)
|
- [Embed media](#embed-media)
|
||||||
- [Customize my profile options](#customize-my-profile-options)
|
- [Customize my profile options](#customize-my-profile-options)
|
||||||
@ -195,6 +196,30 @@ You can now watch the captions/subtitles play back in the video player - and tog
|
|||||||
<img src="./images/CC-display.png"/>
|
<img src="./images/CC-display.png"/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
## Using Timestamps for sharing
|
||||||
|
|
||||||
|
### Using Timestamp in the URL
|
||||||
|
|
||||||
|
An additionnal Get parameter 't' can be added in video URL's to start the video at the given time. The starting time has to be given in seconds.
|
||||||
|
|
||||||
|
<p align="left">
|
||||||
|
<img src="./images/Demo1.png"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Additionnally the share button has an option to generate the URL with the timestamp at current second the video is.
|
||||||
|
|
||||||
|
<p align="left">
|
||||||
|
<img src="./images/Demo2.png"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
### Using Timestamp in the comments
|
||||||
|
|
||||||
|
Comments can also include timestamps. They are automatically detected upon posting the comment, and will be in the form of an hyperlink link in the comment. The timestamps in the comments have to follow the format HH:MM:SS or MM:SS
|
||||||
|
|
||||||
|
<p align="left">
|
||||||
|
<img src="./images/Demo3.png"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
## Search media
|
## Search media
|
||||||
How search can be used
|
How search can be used
|
||||||
|
|
||||||
|
@ -368,8 +368,36 @@ export default function CommentsList(props) {
|
|||||||
const [displayComments, setDisplayComments] = useState(false);
|
const [displayComments, setDisplayComments] = useState(false);
|
||||||
|
|
||||||
function onCommentsLoad() {
|
function onCommentsLoad() {
|
||||||
|
const retrievedComments = [...MediaPageStore.get('media-comments')];
|
||||||
|
|
||||||
|
retrievedComments.forEach(comment => {
|
||||||
|
comment.text = setTimestampAnchors(comment.text);
|
||||||
|
});
|
||||||
|
|
||||||
displayCommentsRelatedAlert();
|
displayCommentsRelatedAlert();
|
||||||
setComments([...MediaPageStore.get('media-comments')]);
|
setComments(retrievedComments);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTimestampAnchors(text)
|
||||||
|
{
|
||||||
|
function wrapTimestampWithAnchor(match, string)
|
||||||
|
{
|
||||||
|
let split = match.split(':'), s = 0, m = 1;
|
||||||
|
let searchParameters = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
|
while (split.length > 0)
|
||||||
|
{
|
||||||
|
s += m * parseInt(split.pop(), 10);
|
||||||
|
m *= 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchParameters.set('t', s)
|
||||||
|
const wrapped = "<a href=\"" + MediaPageStore.get('media-url').split('?')[0] + "?" + searchParameters + "\">" + match + "</a>";
|
||||||
|
return wrapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeRegex = new RegExp('((\\d)?\\d:)?(\\d)?\\d:\\d\\d', 'g');
|
||||||
|
return text.replace(timeRegex , wrapTimestampWithAnchor);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCommentSubmit(commentId) {
|
function onCommentSubmit(commentId) {
|
||||||
|
@ -182,9 +182,27 @@ function updateDimensions() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTimestamp() {
|
||||||
|
const videoPlayer = document.getElementsByTagName("video");
|
||||||
|
return videoPlayer[0]?.currentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ToHHMMSS (timeInt) {
|
||||||
|
let sec_num = parseInt(timeInt, 10);
|
||||||
|
let hours = Math.floor(sec_num / 3600);
|
||||||
|
let minutes = Math.floor((sec_num - (hours * 3600)) / 60);
|
||||||
|
let seconds = sec_num - (hours * 3600) - (minutes * 60);
|
||||||
|
|
||||||
|
if (hours < 10) {hours = "0"+hours;}
|
||||||
|
if (minutes < 10) {minutes = "0"+minutes;}
|
||||||
|
if (seconds < 10) {seconds = "0"+seconds;}
|
||||||
|
return hours >= 1 ? hours + ':' + minutes + ':' + seconds : minutes + ':' + seconds;
|
||||||
|
}
|
||||||
|
|
||||||
export function MediaShareOptions(props) {
|
export function MediaShareOptions(props) {
|
||||||
const containerRef = useRef(null);
|
const containerRef = useRef(null);
|
||||||
const shareOptionsInnerRef = useRef(null);
|
const shareOptionsInnerRef = useRef(null);
|
||||||
|
const mediaUrl = MediaPageStore.get('media-url');
|
||||||
|
|
||||||
const [inlineSlider, setInlineSlider] = useState(null);
|
const [inlineSlider, setInlineSlider] = useState(null);
|
||||||
const [sliderButtonsVisible, setSliderButtonsVisible] = useState({ prev: false, next: false });
|
const [sliderButtonsVisible, setSliderButtonsVisible] = useState({ prev: false, next: false });
|
||||||
@ -192,6 +210,12 @@ export function MediaShareOptions(props) {
|
|||||||
const [dimensions, setDimensions] = useState(updateDimensions());
|
const [dimensions, setDimensions] = useState(updateDimensions());
|
||||||
const [shareOptions] = useState(ShareOptions());
|
const [shareOptions] = useState(ShareOptions());
|
||||||
|
|
||||||
|
const [timestamp, setTimestamp] = useState(0);
|
||||||
|
const [formattedTimestamp, setFormattedTimestamp] = useState(0);
|
||||||
|
const [startAtSelected, setStartAtSelected] = useState(false);
|
||||||
|
|
||||||
|
const [shareMediaLink, setShareMediaLink] = useState(mediaUrl);
|
||||||
|
|
||||||
function onWindowResize() {
|
function onWindowResize() {
|
||||||
setDimensions(updateDimensions());
|
setDimensions(updateDimensions());
|
||||||
}
|
}
|
||||||
@ -219,6 +243,17 @@ export function MediaShareOptions(props) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateStartAtCheckbox() {
|
||||||
|
setStartAtSelected(!startAtSelected);
|
||||||
|
updateShareMediaLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateShareMediaLink()
|
||||||
|
{
|
||||||
|
const newLink = startAtSelected ? mediaUrl : mediaUrl + "&t=" + Math.trunc(timestamp);
|
||||||
|
setShareMediaLink(newLink);
|
||||||
|
}
|
||||||
|
|
||||||
function nextSlide() {
|
function nextSlide() {
|
||||||
inlineSlider.nextSlide();
|
inlineSlider.nextSlide();
|
||||||
updateSlider();
|
updateSlider();
|
||||||
@ -244,6 +279,10 @@ export function MediaShareOptions(props) {
|
|||||||
PageStore.on('window_resize', onWindowResize);
|
PageStore.on('window_resize', onWindowResize);
|
||||||
MediaPageStore.on('copied_media_link', onCompleteCopyMediaLink);
|
MediaPageStore.on('copied_media_link', onCompleteCopyMediaLink);
|
||||||
|
|
||||||
|
const localTimestamp = getTimestamp();
|
||||||
|
setTimestamp(localTimestamp);
|
||||||
|
setFormattedTimestamp(ToHHMMSS(localTimestamp));
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
PageStore.removeListener('window_resize', onWindowResize);
|
PageStore.removeListener('window_resize', onWindowResize);
|
||||||
MediaPageStore.removeListener('copied_media_link', onCompleteCopyMediaLink);
|
MediaPageStore.removeListener('copied_media_link', onCompleteCopyMediaLink);
|
||||||
@ -273,10 +312,22 @@ export function MediaShareOptions(props) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="copy-field">
|
<div className="copy-field">
|
||||||
<div>
|
<div>
|
||||||
<input type="text" readOnly value={MediaPageStore.get('media-url')} />
|
<input type="text" readOnly value={shareMediaLink} />
|
||||||
<button onClick={onClickCopyMediaLink}>COPY</button>
|
<button onClick={onClickCopyMediaLink}>COPY</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="start-at">
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="start-at-checkbox"
|
||||||
|
id="id-start-at-checkbox"
|
||||||
|
checked={startAtSelected}
|
||||||
|
onChange={updateStartAtCheckbox}
|
||||||
|
/>
|
||||||
|
Start at {formattedTimestamp}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -192,6 +192,13 @@ export function VideoPlayer(props) {
|
|||||||
document.addEventListener('visibilitychange', initPlayer);
|
document.addEventListener('visibilitychange', initPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
player.player.one('loadedmetadata', () => {
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const paramT = Number(urlParams.get('t'));
|
||||||
|
const timestamp = !isNaN(paramT) ? paramT : 0;
|
||||||
|
player.player.currentTime(timestamp);
|
||||||
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unsetPlayer();
|
unsetPlayer();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user