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:
absidue 2022-11-04 08:19:51 +01:00 committed by GitHub
parent 27992e47b0
commit e228182d8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 111 additions and 143 deletions

View File

@ -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) {

View File

@ -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

View File

@ -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([

View File

@ -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
}

View File

@ -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
}
)

View File

@ -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',