mirror of https://github.com/FreeTubeApp/FreeTube
Move openInternalPath and formatDurationAsTimestamp to utils (#2794)
* Move openInternalPath and formatDurationAsTimestamp to utils * Make openInternalPath take an object parameter again * Fix small mistake
This commit is contained in:
parent
27992e47b0
commit
e228182d8a
|
@ -12,7 +12,7 @@ import FtProgressBar from './components/ft-progress-bar/ft-progress-bar.vue'
|
|||
import { marked } from 'marked'
|
||||
import { IpcChannels } from '../constants'
|
||||
import packageDetails from '../../package.json'
|
||||
import { openExternalLink, showToast } from './helpers/utils'
|
||||
import { openExternalLink, openInternalPath, showToast } from './helpers/utils'
|
||||
|
||||
let ipcRenderer = null
|
||||
|
||||
|
@ -381,9 +381,9 @@ export default Vue.extend({
|
|||
if (playlistId && playlistId.length > 0) {
|
||||
query.playlistId = playlistId
|
||||
}
|
||||
const path = `/watch/${videoId}`
|
||||
this.openInternalPath({
|
||||
path,
|
||||
|
||||
openInternalPath({
|
||||
path: `/watch/${videoId}`,
|
||||
query,
|
||||
doCreateNewWindow
|
||||
})
|
||||
|
@ -393,9 +393,8 @@ export default Vue.extend({
|
|||
case 'playlist': {
|
||||
const { playlistId, query } = result
|
||||
|
||||
const path = `/playlist/${playlistId}`
|
||||
this.openInternalPath({
|
||||
path,
|
||||
openInternalPath({
|
||||
path: `/playlist/${playlistId}`,
|
||||
query,
|
||||
doCreateNewWindow
|
||||
})
|
||||
|
@ -405,9 +404,8 @@ export default Vue.extend({
|
|||
case 'search': {
|
||||
const { searchQuery, query } = result
|
||||
|
||||
const path = `/search/${encodeURIComponent(searchQuery)}`
|
||||
this.openInternalPath({
|
||||
path,
|
||||
openInternalPath({
|
||||
path: `/search/${encodeURIComponent(searchQuery)}`,
|
||||
query,
|
||||
doCreateNewWindow,
|
||||
searchQueryText: searchQuery
|
||||
|
@ -429,9 +427,8 @@ export default Vue.extend({
|
|||
case 'channel': {
|
||||
const { channelId, subPath } = result
|
||||
|
||||
const path = `/channel/${channelId}/${subPath}`
|
||||
this.openInternalPath({
|
||||
path,
|
||||
openInternalPath({
|
||||
path: `/channel/${channelId}/${subPath}`,
|
||||
doCreateNewWindow
|
||||
})
|
||||
break
|
||||
|
@ -465,28 +462,6 @@ export default Vue.extend({
|
|||
})
|
||||
},
|
||||
|
||||
openInternalPath: function({ path, doCreateNewWindow, query = {}, searchQueryText = null }) {
|
||||
if (process.env.IS_ELECTRON && doCreateNewWindow) {
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
// Combine current document path and new "hash" as new window startup URL
|
||||
const newWindowStartupURL = [
|
||||
window.location.href.split('#')[0],
|
||||
`#${path}?${(new URLSearchParams(query)).toString()}`
|
||||
].join('')
|
||||
ipcRenderer.send(IpcChannels.CREATE_NEW_WINDOW, {
|
||||
windowStartupUrl: newWindowStartupURL,
|
||||
searchQueryText
|
||||
})
|
||||
} else {
|
||||
// Web
|
||||
this.$router.push({
|
||||
path,
|
||||
query
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
enableSetSearchQueryText: function () {
|
||||
ipcRenderer.on('updateSearchInputText', (event, searchQueryText) => {
|
||||
if (searchQueryText) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import { mapActions } from 'vuex'
|
|||
import i18n from '../../i18n/index'
|
||||
import {
|
||||
copyToClipboard,
|
||||
formatDurationAsTimestamp,
|
||||
openExternalLink,
|
||||
showToast,
|
||||
toLocalePublicationString
|
||||
|
@ -337,44 +338,6 @@ export default Vue.extend({
|
|||
}
|
||||
},
|
||||
|
||||
// For Invidious data, as duration is sent in seconds
|
||||
calculateVideoDuration: function (lengthSeconds) {
|
||||
if (typeof lengthSeconds === 'string') {
|
||||
return lengthSeconds
|
||||
}
|
||||
|
||||
if (typeof lengthSeconds === 'undefined') {
|
||||
return '0:00'
|
||||
}
|
||||
let durationText = ''
|
||||
let time = lengthSeconds
|
||||
let hours = 0
|
||||
|
||||
if (time >= 3600) {
|
||||
hours = Math.floor(time / 3600)
|
||||
time = time - hours * 3600
|
||||
}
|
||||
|
||||
let minutes = Math.floor(time / 60)
|
||||
let seconds = time - minutes * 60
|
||||
|
||||
if (seconds < 10) {
|
||||
seconds = '0' + seconds
|
||||
}
|
||||
|
||||
if (minutes < 10 && hours > 0) {
|
||||
minutes = '0' + minutes
|
||||
}
|
||||
|
||||
if (hours > 0) {
|
||||
durationText = hours + ':' + minutes + ':' + seconds
|
||||
} else {
|
||||
durationText = minutes + ':' + seconds
|
||||
}
|
||||
|
||||
return durationText
|
||||
},
|
||||
|
||||
parseVideoData: function () {
|
||||
this.id = this.data.videoId
|
||||
this.title = this.data.title
|
||||
|
@ -382,7 +345,7 @@ export default Vue.extend({
|
|||
|
||||
this.channelName = this.data.author
|
||||
this.channelId = this.data.authorId
|
||||
this.duration = this.calculateVideoDuration(this.data.lengthSeconds)
|
||||
this.duration = formatDurationAsTimestamp(this.data.lengthSeconds)
|
||||
this.description = this.data.description
|
||||
this.isLive = this.data.liveNow || this.data.lengthSeconds === 'undefined'
|
||||
this.isUpcoming = this.data.isUpcoming || this.data.premiere
|
||||
|
|
|
@ -7,7 +7,7 @@ import debounce from 'lodash.debounce'
|
|||
import ytSuggest from 'youtube-suggest'
|
||||
|
||||
import { IpcChannels } from '../../../constants'
|
||||
import { showToast } from '../../helpers/utils'
|
||||
import { openInternalPath, showToast } from '../../helpers/utils'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'TopNav',
|
||||
|
@ -123,7 +123,8 @@ export default Vue.extend({
|
|||
if (playlistId && playlistId.length > 0) {
|
||||
query.playlistId = playlistId
|
||||
}
|
||||
this.openInternalPath({
|
||||
|
||||
openInternalPath({
|
||||
path: `/watch/${videoId}`,
|
||||
query,
|
||||
doCreateNewWindow
|
||||
|
@ -134,9 +135,10 @@ export default Vue.extend({
|
|||
case 'playlist': {
|
||||
const { playlistId, query } = result
|
||||
|
||||
this.$router.push({
|
||||
openInternalPath({
|
||||
path: `/playlist/${playlistId}`,
|
||||
query
|
||||
query,
|
||||
doCreateNewWindow
|
||||
})
|
||||
break
|
||||
}
|
||||
|
@ -144,7 +146,7 @@ export default Vue.extend({
|
|||
case 'search': {
|
||||
const { searchQuery, query } = result
|
||||
|
||||
this.openInternalPath({
|
||||
openInternalPath({
|
||||
path: `/search/${encodeURIComponent(searchQuery)}`,
|
||||
query,
|
||||
doCreateNewWindow,
|
||||
|
@ -167,7 +169,7 @@ export default Vue.extend({
|
|||
case 'channel': {
|
||||
const { channelId, idType, subPath } = result
|
||||
|
||||
this.openInternalPath({
|
||||
openInternalPath({
|
||||
path: `/channel/${channelId}/${subPath}`,
|
||||
query: { idType },
|
||||
doCreateNewWindow
|
||||
|
@ -177,7 +179,7 @@ export default Vue.extend({
|
|||
|
||||
case 'invalid_url':
|
||||
default: {
|
||||
this.openInternalPath({
|
||||
openInternalPath({
|
||||
path: `/search/${encodeURIComponent(query)}`,
|
||||
query: {
|
||||
sortBy: this.searchSettings.sortBy,
|
||||
|
@ -262,11 +264,11 @@ export default Vue.extend({
|
|||
this.showFilters = false
|
||||
},
|
||||
|
||||
handleSearchFilterValueChanged: function(filterValueChanged) {
|
||||
handleSearchFilterValueChanged: function (filterValueChanged) {
|
||||
this.searchFilterValueChanged = filterValueChanged
|
||||
},
|
||||
|
||||
navigateHistory: function() {
|
||||
navigateHistory: function () {
|
||||
if (!this.isForwardOrBack) {
|
||||
this.historyIndex = window.history.length
|
||||
this.$refs.historyArrowBack.classList.remove('fa-arrow-left')
|
||||
|
@ -307,28 +309,6 @@ export default Vue.extend({
|
|||
this.$store.commit('toggleSideNav')
|
||||
},
|
||||
|
||||
openInternalPath: function({ path, doCreateNewWindow, query = {}, searchQueryText = null }) {
|
||||
if (process.env.IS_ELECTRON && doCreateNewWindow) {
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
// Combine current document path and new "hash" as new window startup URL
|
||||
const newWindowStartupURL = [
|
||||
window.location.href.split('#')[0],
|
||||
`#${path}?${(new URLSearchParams(query)).toString()}`
|
||||
].join('')
|
||||
ipcRenderer.send(IpcChannels.CREATE_NEW_WINDOW, {
|
||||
windowStartupUrl: newWindowStartupURL,
|
||||
searchQueryText
|
||||
})
|
||||
} else {
|
||||
// Web
|
||||
this.$router.push({
|
||||
path,
|
||||
query
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
createNewWindow: function () {
|
||||
if (process.env.IS_ELECTRON) {
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
@ -343,7 +323,7 @@ export default Vue.extend({
|
|||
hideFilters: function () {
|
||||
this.showFilters = false
|
||||
},
|
||||
updateSearchInputText: function(text) {
|
||||
updateSearchInputText: function (text) {
|
||||
this.$refs.searchInput.updateInputData(text)
|
||||
},
|
||||
...mapActions([
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import fs from 'fs'
|
||||
|
||||
import { IpcChannels } from '../../constants'
|
||||
import FtToastEvents from '../components/ft-toast/ft-toast-events'
|
||||
import i18n from '../i18n/index'
|
||||
import fs from 'fs'
|
||||
import router from '../router/index'
|
||||
|
||||
export const colors = [
|
||||
{ name: 'Red', value: '#d50000' },
|
||||
|
@ -238,6 +240,10 @@ export async function copyToClipboard(content, { messageOnSuccess = null, messag
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a link in the default web browser or a new tab in the web builds
|
||||
* @param {string} url the URL to open
|
||||
*/
|
||||
export function openExternalLink(url) {
|
||||
if (process.env.IS_ELECTRON) {
|
||||
const ipcRenderer = require('electron').ipcRenderer
|
||||
|
@ -247,6 +253,35 @@ export function openExternalLink(url) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens an internal path in the same or a new window.
|
||||
* Optionally with query params and setting the contents of the search bar in the new window.
|
||||
* @param {object} params
|
||||
* @param {string} params.path the internal path to open
|
||||
* @param {boolean} params.doCreateNewWindow set to true to open a new window
|
||||
* @param {object} params.query the query params to use (optional)
|
||||
* @param {string} params.searchQueryText the text to show in the search bar in the new window (optional)
|
||||
*/
|
||||
export function openInternalPath({ path, query = {}, doCreateNewWindow, searchQueryText = null }) {
|
||||
if (process.env.IS_ELECTRON && doCreateNewWindow) {
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
// Combine current document path and new "hash" as new window startup URL
|
||||
const newWindowStartupURL = new URL(window.location.href)
|
||||
newWindowStartupURL.hash = `${path}?${(new URLSearchParams(query)).toString()}`
|
||||
|
||||
ipcRenderer.send(IpcChannels.CREATE_NEW_WINDOW, {
|
||||
windowStartupUrl: newWindowStartupURL.toString(),
|
||||
searchQueryText
|
||||
})
|
||||
} else {
|
||||
router.push({
|
||||
path,
|
||||
query
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export async function showOpenDialog (options) {
|
||||
if (process.env.IS_ELECTRON) {
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
@ -403,3 +438,45 @@ export function createWebURL(path) {
|
|||
export function stripHTML(value) {
|
||||
return value.replace(/(<(?!br|\/?(?:b|s|i)>)([^>]+)>)/ig, '')
|
||||
}
|
||||
|
||||
/**
|
||||
* This formats the duration of a video in seconds into a user friendly timestamp.
|
||||
* It will return strings like LIVE or UPCOMING, without making any changes
|
||||
* @param {string|number} lengthSeconds the video duration in seconds or the strings LIVE or UPCOMING
|
||||
* @returns {string} timestamp or LIVE or UPCOMING
|
||||
*/
|
||||
export function formatDurationAsTimestamp(lengthSeconds) {
|
||||
if (typeof lengthSeconds === 'string') {
|
||||
return lengthSeconds
|
||||
}
|
||||
|
||||
if (lengthSeconds === 0) {
|
||||
return '0:00'
|
||||
}
|
||||
|
||||
let hours = 0
|
||||
|
||||
if (lengthSeconds >= 3600) {
|
||||
hours = Math.floor(lengthSeconds / 3600)
|
||||
lengthSeconds = lengthSeconds - hours * 3600
|
||||
}
|
||||
|
||||
let minutes = Math.floor(lengthSeconds / 60)
|
||||
if (minutes < 10 && hours > 0) {
|
||||
minutes = '0' + minutes
|
||||
}
|
||||
|
||||
let seconds = lengthSeconds - minutes * 60
|
||||
if (seconds < 10) {
|
||||
seconds = '0' + seconds
|
||||
}
|
||||
|
||||
let timestamp = ''
|
||||
if (hours > 0) {
|
||||
timestamp = hours + ':' + minutes + ':' + seconds
|
||||
} else {
|
||||
timestamp = minutes + ':' + seconds
|
||||
}
|
||||
|
||||
return timestamp
|
||||
}
|
||||
|
|
|
@ -150,7 +150,7 @@ export default Vue.extend({
|
|||
const publishDate = video.uploadedAt
|
||||
let videoDuration = video.duration
|
||||
const videoId = video.id
|
||||
if (videoDuration !== null && videoDuration !== '' && videoDuration !== 'LIVE') {
|
||||
if (videoDuration !== null && videoDuration !== '' && videoDuration !== 'LIVE' && videoDuration !== 'UPCOMING') {
|
||||
videoDuration = calculateLengthInSeconds(video.duration)
|
||||
}
|
||||
dataToShow.push(
|
||||
|
@ -170,7 +170,7 @@ export default Vue.extend({
|
|||
liveNow: video.isLive || videoDuration === 'LIVE',
|
||||
paid: false,
|
||||
premium: false,
|
||||
isUpcoming: false,
|
||||
isUpcoming: videoDuration === 'UPCOMING',
|
||||
timeText: videoDuration
|
||||
}
|
||||
)
|
||||
|
|
|
@ -13,7 +13,12 @@ import WatchVideoPlaylist from '../../components/watch-video-playlist/watch-vide
|
|||
import WatchVideoRecommendations from '../../components/watch-video-recommendations/watch-video-recommendations.vue'
|
||||
import FtAgeRestricted from '../../components/ft-age-restricted/ft-age-restricted.vue'
|
||||
import i18n from '../../i18n/index'
|
||||
import { buildVTTFileLocally, copyToClipboard, showToast } from '../../helpers/utils'
|
||||
import {
|
||||
buildVTTFileLocally,
|
||||
copyToClipboard,
|
||||
formatDurationAsTimestamp,
|
||||
showToast
|
||||
} from '../../helpers/utils'
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
|
||||
|
@ -382,7 +387,7 @@ export default Vue.extend({
|
|||
|
||||
chapters.push({
|
||||
title: chapterRenderer.title.simpleText,
|
||||
timestamp: this.formatSecondsAsTimestamp(start),
|
||||
timestamp: formatDurationAsTimestamp(start),
|
||||
startSeconds: start,
|
||||
endSeconds: 0,
|
||||
thumbnail: chapterRenderer.thumbnail.thumbnails[0].url
|
||||
|
@ -1470,38 +1475,6 @@ export default Vue.extend({
|
|||
document.title = `${this.videoTitle} - FreeTube`
|
||||
},
|
||||
|
||||
formatSecondsAsTimestamp(time) {
|
||||
if (time === 0) {
|
||||
return '0:00'
|
||||
}
|
||||
|
||||
let hours = 0
|
||||
|
||||
if (time >= 3600) {
|
||||
hours = Math.floor(time / 3600)
|
||||
time = time - hours * 3600
|
||||
}
|
||||
|
||||
let minutes = Math.floor(time / 60)
|
||||
if (minutes < 10 && hours > 0) {
|
||||
minutes = '0' + minutes
|
||||
}
|
||||
|
||||
let seconds = time - minutes * 60
|
||||
if (seconds < 10) {
|
||||
seconds = '0' + seconds
|
||||
}
|
||||
|
||||
let timestamp = ''
|
||||
if (hours > 0) {
|
||||
timestamp = hours + ':' + minutes + ':' + seconds
|
||||
} else {
|
||||
timestamp = minutes + ':' + seconds
|
||||
}
|
||||
|
||||
return timestamp
|
||||
},
|
||||
|
||||
...mapActions([
|
||||
'updateHistory',
|
||||
'updateWatchProgress',
|
||||
|
|
Loading…
Reference in New Issue