Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,33 @@ in an embedded media element. You've seen it in the Youtube descriptions, now ge
To create a link, either:

* Use our [skipto] shortcode which takes a "time" (or "timestamp" or "ts") argument and uses that to create a link.
Eg, "Just wait until...or...hold on, you can [skipto time=4:30]skip to[/skipto] this part of the video!"
* Check the "Replace Timestamps Automatically" checkbox in the Settings > Skip to Timestamp, and watch as all your
timestamps in the form "4:30" or "1:23:45" are automatically converted into links.
Eg, "Just wait until...or...hold on, you can ```[skipto time=4:30]skip to[/skipto]``` this part of the video!"
* Check the "Replace Timestamps Automatically" checkbox in the Settings > Skip to Timestamp, and watch as all your timestamps in the form "4:30" or "1:23:45" are automatically converted into links.
* If many media (audio, video, YouTube) exist in the same page, you can select among them:
```[skipto time=4:30 media-id=2]skip to[/skipto]```
For the 2nd media in the page (it is equivalent to the order in the page: 1st, 2nd...).
* If the page contains a mix of media of different kind: audio, video or YouTube, you can select among them:
```[skipto time=2:37 media-type="video"]2:37[/skipto]```
```[skipto time=5:56 media-id=2 media-type="audio"]5:56[/skipto]```
```[skipto time=13:05 media-id=4 media-type="video"]13:05[/skipto]```
```[skipto time=29:14 media-id=3 media-type="youtube"]29:14[/skipto]```

* A more convenient way to select a media is to refer to it using its URL. Media order is not robust to changes (adding or moving a media).
```[skipto time=5:56 url-media-contains="https://www.domain.com/path/myAudioFile.mp3" media-type="audio"]5:56[/skipto]```
```[skipto time=13:05 url-media-contains="https://www.domain.com/path/myVideoFile.mp3" media-type="video"]13:05[/skipto]```

"url-media-contains" and "media-id" are not usable together. It is not necessary to give the whole URL:
```[skipto time=5:56 url-media-contains="myAudioFile.mp3" media-type="audio"]5:56[/skipto]```
```[skipto time=13:05 url-media-contains="myVideoFile.mp3" media-type="video"]13:05[/skipto]```

Only a part of the URL may be enough, give the minimum necessary:
```[skipto time=5:56 url-media-contains="path1/myAudioFile.mp3" media-type="audio"]5:56[/skipto]```
```[skipto time=5:56 url-media-contains="path2/myAudioFile.mp3" media-type="audio"]5:56[/skipto]```

* For the YouTube case, you may have some trouble with the following:
```[skipto time=4:14 url-media-contains="https://www.youtube.com/watch?v=9ptyprXFPX0" media-type="youtube"]4:14[/skipto]```
Instead prefer:
```[skipto time=4:14 url-media-contains="9ptyprXFPX0" media-type="youtube"]4:14[/skipto]```

The links search for and skip to a time in:

Expand Down
229 changes: 162 additions & 67 deletions js/skiptotimestamp.js
Original file line number Diff line number Diff line change
@@ -1,85 +1,180 @@
var STT = {
settings: STTSettings,
media: undefined,
skipTo: undefined,
isHTML5: false,
isYoutube: false,
settings: STTSettings,
media: undefined,
skipTo: undefined,
isHTML5: false,
isYoutube: false,
youtubeFrames: [],

doHTML5Skip: function() {
STT.media.removeEventListener('canplaythrough', STT.doHTML5Skip);
STT.media.currentTime = STT.skipTo;
STT.media.play();
},
doHTML5Skip: function() {
STT.doHTML5Clear();
STT.media.currentTime = STT.skipTo;
STT.media.play();
},

doYoutubeSkip: function() {
STT.media.seekTo(STT.skipTo);
STT.media.playVideo();
}
doYoutubeSkip: function() {
STT.doYoutubeClear();
STT.media.seekTo(STT.skipTo);
STT.media.playVideo();
},

doHTML5Clear: function() {
STT.media.removeEventListener("canplaythrough", STT.doHTML5Skip);
},

doYoutubeClear: function() {
}
};

STTSkipTo = function(time) {
var audio = document.getElementsByTagName('audio'),
video = document.getElementsByTagName('video'),
iframe = document.getElementsByTagName('iframe'),
timeArray = time.split(':').reverse(),
seconds = parseInt(timeArray[0]),
minutes = timeArray.length > 1 ? parseInt(timeArray[1]) : 0,
hours = timeArray.length > 2 ? parseInt(timeArray[2]) : 0;
STTSkipTo = function(time, mediaId, mediaType, urlMediaUsed, urlMediaContains) {
var audio = document.getElementsByTagName("audio"),
video = document.getElementsByTagName("video"),
iframe = document.getElementsByTagName("iframe"),
timeArray = time.split(":").reverse(),
seconds = parseInt(timeArray[0]),
minutes = timeArray.length > 1 ? parseInt(timeArray[1]) : 0,
hours = timeArray.length > 2 ? parseInt(timeArray[2]) : 0;

STT.skipTo = seconds + (minutes * 60) + (hours * 3600);
STT.skipTo = seconds + (minutes * 60) + (hours * 3600);

if (STT.media) {
STT.doSkip();
return;
}
if (STT.media) {
STT.doClear();
}

const doAudio = (mediaType !== "video" && mediaType !== "youtube") && (parseInt(STT.settings.link_audio) && audio.length);
const doVideo = (mediaType !== "audio" && mediaType !== "youtube") && (parseInt(STT.settings.link_video) && video.length);
const doYoutube = (mediaType !== "audio" && mediaType !== "video") && (parseInt(STT.settings.link_youtube && iframe.length));

if ((parseInt(STT.settings.link_audio) && audio.length) ||
(parseInt(STT.settings.link_video) && video.length))
{
STT.doSkip = STT.doHTML5Skip;
if (doAudio || doVideo)
{
STT.doClear = STT.doHTML5Clear;

if (parseInt(STT.settings.link_audio) && audio.length) {
STT.media = audio[0];
} else {
STT.media = video[0];
}
if (doAudio) {
if (mediaId > audio.length) {
mediaId = audio.length;
}
if (urlMediaUsed) {
for (var i_a = 0; i_a < audio.length; i_a++) {
var audioURL = audio[i_a].currentSrc;
if (audioURL.includes(urlMediaContains)) {
mediaId = i_a + 1;
break;
}
}
}
STT.media = audio[mediaId - 1];
} else {
if (mediaId > video.length) {
mediaId = video.length;
}
if (urlMediaUsed) {
for (var i_v = 0; i_v < video.length; i_v++) {
var videoURL = video[i_v].currentSrc;
if (videoURL.includes(urlMediaContains)) {
mediaId = i_v + 1;
break;
}
}
}
STT.media = video[mediaId - 1];
}

var playbackRate = STT.media.playbackRate;
STT.media.addEventListener('canplaythrough', STT.doHTML5Skip);
STT.media.load();
STT.media.playbackRate = playbackRate;
STT.media.play();
return;
} else if (parseInt(STT.settings.link_youtube && iframe.length)) {
// Inspect the iframes, looking for a src with youtube in the URI
for (var i = 0; i < iframe.length; i++) {
if (iframe[i].src.search('youtube') !== -1) {
// Set up the JS interface
STT.doSkip = STT.doYoutubeSkip;
var playbackRate = STT.media.playbackRate;
STT.media.addEventListener("canplaythrough", STT.doHTML5Skip);
STT.media.load();
STT.media.playbackRate = playbackRate;
STT.media.play();
return;
} else if (doYoutube) {
// Search last youtube frame
var lastYoutubeFrameIndex = 1;
for (var j = 0; j < iframe.length; j++) {
if (iframe[j].src.search("youtube") !== -1) {
lastYoutubeFrameIndex = j + 1;
}
}
if (mediaId > lastYoutubeFrameIndex) {
mediaId = lastYoutubeFrameIndex;
}
var foundYoutubeIndex = 0;
if (urlMediaUsed) {
for (var i_y = 0; i_y < iframe.length; i_y++) {
if (iframe[i_y].src.search("youtube") !== -1) {
foundYoutubeIndex++;
if (iframe[i_y].src.includes(urlMediaContains)) {
mediaId = foundYoutubeIndex;
break;
}
}
}
}
// Inspect the iframes, looking for a src with youtube in the URI
foundYoutubeIndex = 0;
for (var i = 0; i < iframe.length; i++) {
if (iframe[i].src.search("youtube") !== -1) {
foundYoutubeIndex++;
if (mediaId !== foundYoutubeIndex) {
continue;
}

// Set up the JS interface
STT.doClear = STT.doYoutubeClear;

iframe[0].id = 'stt-youtube-player';
STT.media = new YT.Player('stt-youtube-player', {
events: {
onReady: STT.doYoutubeSkip
}
});
return;
}
}
}
var frameId = "stt-youtube-player_".concat(i.toString());
if (iframe[i].id) {
STT.media = STT.youtubeFrames[i];
STT.doYoutubeSkip();
} else {
iframe[i].id = frameId;
STT.media = new YT.Player(frameId, {
events: {
onReady: STT.doYoutubeSkip
}
});
STT.youtubeFrames[i] = STT.media;
}
return;
}
}
}

console.log('Skip to Timestamp: No media player found!');
return;
}
console.log("Skip to Timestamp: No media player found!");
return;
};

// Listen to all clicks on the document
document.addEventListener('click', function (event) {
document.addEventListener("click", function (event) {
var elem = event.target;
// If the event target doesn't match bail
if (!elem.hasAttribute('data-stt-time')) {
return;
// If the event target doesn't match bail
if (!elem.hasAttribute("data-stt-time")) {
return;
}
const mediaIdAttribute = "media-id";
var media_id = 1;
if (elem.hasAttribute(mediaIdAttribute)) {
const mediaIdAttr = elem.getAttribute(mediaIdAttribute);
var parsed = parseInt(mediaIdAttr, 10);
if (!isNaN(parsed)) {
if (parsed > 0) {
media_id = parsed;
}
}
}
const urlMediaContainsAttribute = "url-media-contains";
var urlMediaContains = "";
var urlMediaUsed = false;
if (elem.hasAttribute(urlMediaContainsAttribute)) {
urlMediaContains = elem.getAttribute(urlMediaContainsAttribute);
urlMediaUsed = true;
}
const mediaTypeAttribute = "media-type";
var mediaType = "unset";
if (elem.hasAttribute(mediaTypeAttribute)) {
const mediaTypeAttr = elem.getAttribute(mediaTypeAttribute);
if (mediaTypeAttr === "audio" || mediaTypeAttr === "video" || mediaTypeAttr === "youtube") {
mediaType = mediaTypeAttr;
}
}
var time = elem.getAttribute('data-stt-time');
STTSkipTo(time);
var time = elem.getAttribute("data-stt-time");
STTSkipTo(time, media_id, mediaType, urlMediaUsed, urlMediaContains);
}, false);
40 changes: 38 additions & 2 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ Contributors: doytch
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=mark%2edeutsch%40utoronto%2eca&lc=US&item_name=Coffee%20Donation%20%3d%29&amount=10%2e00&currency_code=USD&button_subtype=services&bn=PP%2dBuyNowBF%3abtn_buynowCC_LG%2egif%3aNonHosted
Tags: audio, embed, html5, media, plugin, shortcode, video, youtube
Requires at least: 3.0.1
Tested up to: 4.9.4
Stable tag: 1.4.4
Tested up to: 4.9.13
Stable tag: 1.6.0
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html

Expand All @@ -22,6 +22,33 @@ Eg, "Just wait until...or...hold on, you can [skipto time=4:30]skip to[/skipto]
* Check the "Replace Timestamps Automatically" checkbox in the Settings > Skip to Timestamp, and watch as all your
timestamps in the form "4:30" or "1:23:45" are automatically converted into links.

If many media (audio, video, YouTube) exist in the same page, you can select among them:
[skipto time=4:30 media-id=2]skip to[/skipto]
For the 2nd media in the page (it is equivalent to the order in the page: 1st, 2nd...).

If the page contains a mix of media of different kind: audio, video or YouTube, you can select among them:
[skipto time=2:37 media-type="video"]2:37[/skipto]
[skipto time=5:56 media-id=2 media-type="audio"]5:56[/skipto]
[skipto time=13:05 media-id=4 media-type="video"]13:05[/skipto]
[skipto time=29:14 media-id=3 media-type="youtube"]29:14[/skipto]

A more convenient way to select a media is to refer to it using its URL. Media order is not robust to
changes (adding or moving a media).
[skipto time=5:56 url-media-contains="https://www.domain.com/path/myAudioFile.mp3" media-type="audio"]5:56[/skipto]
[skipto time=13:05 url-media-contains="https://www.domain.com/path/myVideoFile.mp3" media-type="video"]13:05[/skipto]
"url-media-contains" and "media-id" are not usable together.
It is not necessary to give the whole URL:
[skipto time=5:56 url-media-contains="myAudioFile.mp3" media-type="audio"]5:56[/skipto]
[skipto time=13:05 url-media-contains="myVideoFile.mp3" media-type="video"]13:05[/skipto]
Only a part of the URL may be enough, give the minimum necessary:
[skipto time=5:56 url-media-contains="path1/myAudioFile.mp3" media-type="audio"]5:56[/skipto]
[skipto time=5:56 url-media-contains="path2/myAudioFile.mp3" media-type="audio"]5:56[/skipto]

For the YouTube case, you may have some trouble with the following:
[skipto time=4:14 url-media-contains="https://www.youtube.com/watch?v=9ptyprXFPX0" media-type="youtube"]4:14[/skipto]
Instead prefer:
[skipto time=4:14 url-media-contains="9ptyprXFPX0" media-type="youtube"]4:14[/skipto]

The links search for and skip to a time in:

* Youtube videos embedded using Wordpress embeds. Make sure you're just pasting in the Youtube video link into your post editor and let WordPress embed things for you to ensure that the correct player is inserted into your post.
Expand Down Expand Up @@ -59,6 +86,15 @@ browser and operating system you're running. If it's a bug, I'll get right to wo

== Changelog ==

= 1.6.0 =
* Add media selection using URL
* Bug fix: Unable to skip into another YouTube video once done in a given one.

= 1.5.0 =
* Add possibility to select a media when many of them of a given type (audio, video or YouTube) exist on the same page
* Add possibility to select among every existing media type in page (audio, video or YouTube)
* Fix bug with YouTube frame

= 1.4.4 =
* Fixed bug with autolinks on timestamps.

Expand Down
Loading