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:
parent
1452e361a1
commit
7eda649293
|
@ -284,10 +284,11 @@ export default Vue.extend({
|
||||||
const v = this
|
const v = this
|
||||||
electron.ipcRenderer.on('openUrl', function (event, url) {
|
electron.ipcRenderer.on('openUrl', function (event, url) {
|
||||||
if (url) {
|
if (url) {
|
||||||
v.$store.dispatch('getVideoIdFromUrl', url).then((result) => {
|
v.$store.dispatch('getVideoParamsFromUrl', url).then(({ videoId, timestamp }) => {
|
||||||
if (result) {
|
if (videoId) {
|
||||||
v.$router.push({
|
v.$router.push({
|
||||||
path: `/watch/${result}`
|
path: `/watch/${videoId}`,
|
||||||
|
query: timestamp ? { timestamp } : {}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -89,14 +89,15 @@ export default Vue.extend({
|
||||||
searchInput.blur()
|
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)
|
const playlistId = await this.$store.dispatch('getPlaylistIdFromUrl', query)
|
||||||
|
|
||||||
console.log(playlistId)
|
console.log(playlistId)
|
||||||
|
|
||||||
if (videoId) {
|
if (videoId) {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
path: `/watch/${videoId}`
|
path: `/watch/${videoId}`,
|
||||||
|
query: timestamp ? { timestamp } : {}
|
||||||
})
|
})
|
||||||
} else if (playlistId) {
|
} else if (playlistId) {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
|
|
|
@ -190,43 +190,53 @@ const actions = {
|
||||||
return date.getTime() - timeSpan
|
return date.getTime() - timeSpan
|
||||||
},
|
},
|
||||||
|
|
||||||
getVideoIdFromUrl (_, url) {
|
getVideoParamsFromUrl (_, url) {
|
||||||
/** @type {URL} */
|
/** @type {URL} */
|
||||||
let urlObject
|
let urlObject
|
||||||
|
const paramsObject = { videoId: null, timestamp: null }
|
||||||
try {
|
try {
|
||||||
urlObject = new URL(url)
|
urlObject = new URL(url)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false
|
return paramsObject
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractParams(videoId) {
|
||||||
|
paramsObject.videoId = videoId
|
||||||
|
paramsObject.timestamp = urlObject.searchParams.get('t')
|
||||||
}
|
}
|
||||||
|
|
||||||
const extractors = [
|
const extractors = [
|
||||||
// anything with /watch?v=
|
// anything with /watch?v=
|
||||||
function() {
|
function() {
|
||||||
if (urlObject.pathname === '/watch' && urlObject.searchParams.has('v')) {
|
if (urlObject.pathname === '/watch' && urlObject.searchParams.has('v')) {
|
||||||
return urlObject.searchParams.get('v')
|
extractParams(urlObject.searchParams.get('v'))
|
||||||
|
return paramsObject
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// youtu.be
|
// youtu.be
|
||||||
function() {
|
function() {
|
||||||
if (urlObject.host === 'youtu.be' && urlObject.pathname.match(/^\/[A-Za-z0-9_-]+$/)) {
|
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
|
// youtube.com/embed
|
||||||
function() {
|
function() {
|
||||||
if (urlObject.pathname.match(/^\/embed\/[A-Za-z0-9_-]+$/)) {
|
if (urlObject.pathname.match(/^\/embed\/[A-Za-z0-9_-]+$/)) {
|
||||||
return urlObject.pathname.replace('/embed/', '')
|
extractParams(urlObject.pathname.replace('/embed/', ''))
|
||||||
|
return paramsObject
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// cloudtube
|
// cloudtube
|
||||||
function() {
|
function() {
|
||||||
if (urlObject.host.match(/^cadence\.(gq|moe)$/) && urlObject.pathname.match(/^\/cloudtube\/video\/[A-Za-z0-9_-]+$/)) {
|
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) {
|
getPlaylistIdFromUrl (_, url) {
|
||||||
|
|
|
@ -74,6 +74,7 @@ export default Vue.extend({
|
||||||
downloadLinks: [],
|
downloadLinks: [],
|
||||||
watchingPlaylist: false,
|
watchingPlaylist: false,
|
||||||
playlistId: '',
|
playlistId: '',
|
||||||
|
timestamp: null,
|
||||||
playNextTimeout: null
|
playNextTimeout: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -156,6 +157,7 @@ export default Vue.extend({
|
||||||
this.downloadLinks = []
|
this.downloadLinks = []
|
||||||
|
|
||||||
this.checkIfPlaylist()
|
this.checkIfPlaylist()
|
||||||
|
this.checkIfTimestamp()
|
||||||
|
|
||||||
switch (this.backendPreference) {
|
switch (this.backendPreference) {
|
||||||
case 'local':
|
case 'local':
|
||||||
|
@ -177,6 +179,7 @@ export default Vue.extend({
|
||||||
this.useTheatreMode = this.defaultTheatreMode
|
this.useTheatreMode = this.defaultTheatreMode
|
||||||
|
|
||||||
this.checkIfPlaylist()
|
this.checkIfPlaylist()
|
||||||
|
this.checkIfTimestamp()
|
||||||
|
|
||||||
if (!this.usingElectron) {
|
if (!this.usingElectron) {
|
||||||
this.getVideoInformationInvidious()
|
this.getVideoInformationInvidious()
|
||||||
|
@ -682,18 +685,32 @@ export default Vue.extend({
|
||||||
|
|
||||||
console.log(historyIndex)
|
console.log(historyIndex)
|
||||||
|
|
||||||
if (historyIndex !== -1 && !this.isLive) {
|
if (!this.isLive) {
|
||||||
const watchProgress = this.historyCache[historyIndex].watchProgress
|
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)) {
|
if (watchProgress < (this.videoLengthSeconds - 10)) {
|
||||||
this.$refs.videoPlayer.player.currentTime(watchProgress)
|
this.$refs.videoPlayer.player.currentTime(watchProgress)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.rememberHistory && historyIndex !== -1) {
|
if (this.rememberHistory) {
|
||||||
this.addToHistory(this.historyCache[historyIndex].watchProgress)
|
if (this.timestamp) {
|
||||||
} else if (this.rememberHistory) {
|
this.addToHistory(this.timestamp)
|
||||||
this.addToHistory(0)
|
} else if (historyIndex !== -1) {
|
||||||
|
this.addToHistory(this.historyCache[historyIndex].watchProgress)
|
||||||
|
} else {
|
||||||
|
this.addToHistory(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -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 () {
|
getLegacyFormats: function () {
|
||||||
this.$store
|
this.$store
|
||||||
.dispatch('ytGetVideoInformation', this.videoId)
|
.dispatch('ytGetVideoInformation', this.videoId)
|
||||||
|
|
Loading…
Reference in New Issue