Support for the 't' parameter in links (#1090)

This allows users to specify the timestamp of a video (in seconds)
- by inputting a link into the search bar
- by making use of the protocol link (freetube://), p.e in a browser
This commit is contained in:
Svallinn 2021-03-06 19:03:40 +00:00 committed by GitHub
parent 1452e361a1
commit 7eda649293
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 20 deletions

View File

@ -284,10 +284,11 @@ export default Vue.extend({
const v = this
electron.ipcRenderer.on('openUrl', function (event, url) {
if (url) {
v.$store.dispatch('getVideoIdFromUrl', url).then((result) => {
if (result) {
v.$store.dispatch('getVideoParamsFromUrl', url).then(({ videoId, timestamp }) => {
if (videoId) {
v.$router.push({
path: `/watch/${result}`
path: `/watch/${videoId}`,
query: timestamp ? { timestamp } : {}
})
}
})

View File

@ -89,14 +89,15 @@ export default Vue.extend({
searchInput.blur()
}
const videoId = await this.$store.dispatch('getVideoIdFromUrl', query)
const { videoId, timestamp } = await this.$store.dispatch('getVideoParamsFromUrl', query)
const playlistId = await this.$store.dispatch('getPlaylistIdFromUrl', query)
console.log(playlistId)
if (videoId) {
this.$router.push({
path: `/watch/${videoId}`
path: `/watch/${videoId}`,
query: timestamp ? { timestamp } : {}
})
} else if (playlistId) {
this.$router.push({

View File

@ -190,43 +190,53 @@ const actions = {
return date.getTime() - timeSpan
},
getVideoIdFromUrl (_, url) {
getVideoParamsFromUrl (_, url) {
/** @type {URL} */
let urlObject
const paramsObject = { videoId: null, timestamp: null }
try {
urlObject = new URL(url)
} catch (e) {
return false
return paramsObject
}
function extractParams(videoId) {
paramsObject.videoId = videoId
paramsObject.timestamp = urlObject.searchParams.get('t')
}
const extractors = [
// anything with /watch?v=
function() {
if (urlObject.pathname === '/watch' && urlObject.searchParams.has('v')) {
return urlObject.searchParams.get('v')
extractParams(urlObject.searchParams.get('v'))
return paramsObject
}
},
// youtu.be
function() {
if (urlObject.host === 'youtu.be' && urlObject.pathname.match(/^\/[A-Za-z0-9_-]+$/)) {
return urlObject.pathname.slice(1)
extractParams(urlObject.pathname.slice(1))
return paramsObject
}
},
// youtube.com/embed
function() {
if (urlObject.pathname.match(/^\/embed\/[A-Za-z0-9_-]+$/)) {
return urlObject.pathname.replace('/embed/', '')
extractParams(urlObject.pathname.replace('/embed/', ''))
return paramsObject
}
},
// cloudtube
function() {
if (urlObject.host.match(/^cadence\.(gq|moe)$/) && urlObject.pathname.match(/^\/cloudtube\/video\/[A-Za-z0-9_-]+$/)) {
return urlObject.pathname.slice('/cloudtube/video/'.length)
extractParams(urlObject.pathname.slice('/cloudtube/video/'.length))
return paramsObject
}
}
]
return extractors.reduce((a, c) => a || c(), null) || false
return extractors.reduce((a, c) => a || c(), null) || paramsObject
},
getPlaylistIdFromUrl (_, url) {

View File

@ -74,6 +74,7 @@ export default Vue.extend({
downloadLinks: [],
watchingPlaylist: false,
playlistId: '',
timestamp: null,
playNextTimeout: null
}
},
@ -156,6 +157,7 @@ export default Vue.extend({
this.downloadLinks = []
this.checkIfPlaylist()
this.checkIfTimestamp()
switch (this.backendPreference) {
case 'local':
@ -177,6 +179,7 @@ export default Vue.extend({
this.useTheatreMode = this.defaultTheatreMode
this.checkIfPlaylist()
this.checkIfTimestamp()
if (!this.usingElectron) {
this.getVideoInformationInvidious()
@ -682,19 +685,33 @@ export default Vue.extend({
console.log(historyIndex)
if (historyIndex !== -1 && !this.isLive) {
if (!this.isLive) {
if (this.timestamp) {
if (this.timestamp < 0) {
this.$refs.videoPlayer.player.currentTime(0)
} else if (this.timestamp > (this.videoLengthSeconds - 10)) {
this.$refs.videoPlayer.player.currentTime(this.videoLengthSeconds - 10)
} else {
this.$refs.videoPlayer.player.currentTime(this.timestamp)
}
} else if (historyIndex !== -1) {
const watchProgress = this.historyCache[historyIndex].watchProgress
if (watchProgress < (this.videoLengthSeconds - 10)) {
this.$refs.videoPlayer.player.currentTime(watchProgress)
}
}
}
if (this.rememberHistory && historyIndex !== -1) {
if (this.rememberHistory) {
if (this.timestamp) {
this.addToHistory(this.timestamp)
} else if (historyIndex !== -1) {
this.addToHistory(this.historyCache[historyIndex].watchProgress)
} else if (this.rememberHistory) {
} else {
this.addToHistory(0)
}
}
},
checkIfPlaylist: function () {
@ -711,6 +728,16 @@ export default Vue.extend({
}
},
checkIfTimestamp: function () {
if (typeof (this.$route.query) !== 'undefined') {
try {
this.timestamp = parseInt(this.$route.query.timestamp)
} catch {
this.timestamp = null
}
}
},
getLegacyFormats: function () {
this.$store
.dispatch('ytGetVideoInformation', this.videoId)