Move calculateColorLuminance, calculatePublishedDate and buildVTTFileLocally out of the store (#2692)

This commit is contained in:
absidue 2022-10-10 09:45:18 +02:00 committed by GitHub
parent 7ca6440a88
commit 22a5062334
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 125 additions and 152 deletions

View File

@ -11,6 +11,7 @@ import { MAIN_PROFILE_ID } from '../../../constants'
import fs from 'fs' import fs from 'fs'
import { opmlToJSON } from 'opml-to-json' import { opmlToJSON } from 'opml-to-json'
import ytch from 'yt-channel-info' import ytch from 'yt-channel-info'
import { calculateColorLuminance } from '../../helpers/utils'
// FIXME: Missing web logic branching // FIXME: Missing web logic branching
@ -1092,7 +1093,7 @@ export default Vue.extend({
let index = convertedData.findIndex(p => p.name === profile.value) let index = convertedData.findIndex(p => p.name === profile.value)
if (index === -1) { // profile doesn't exist yet if (index === -1) { // profile doesn't exist yet
const randomBgColor = await this.getRandomColor() const randomBgColor = await this.getRandomColor()
const contrastyTextColor = await this.calculateColorLuminance(randomBgColor) const contrastyTextColor = calculateColorLuminance(randomBgColor)
convertedData.push({ convertedData.push({
name: profile.value, name: profile.value,
bgColor: randomBgColor, bgColor: randomBgColor,
@ -1241,7 +1242,6 @@ export default Vue.extend({
'compactHistory', 'compactHistory',
'showToast', 'showToast',
'getRandomColor', 'getRandomColor',
'calculateColorLuminance',
'showOpenDialog', 'showOpenDialog',
'readFileFromDialog', 'readFileFromDialog',
'showSaveDialog', 'showSaveDialog',

View File

@ -6,6 +6,7 @@ import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
import FtInput from '../../components/ft-input/ft-input.vue' import FtInput from '../../components/ft-input/ft-input.vue'
import FtButton from '../../components/ft-button/ft-button.vue' import FtButton from '../../components/ft-button/ft-button.vue'
import { MAIN_PROFILE_ID } from '../../../constants' import { MAIN_PROFILE_ID } from '../../../constants'
import { calculateColorLuminance } from '../../helpers/utils'
export default Vue.extend({ export default Vue.extend({
name: 'FtProfileEdit', name: 'FtProfileEdit',
@ -70,8 +71,8 @@ export default Vue.extend({
} }
}, },
watch: { watch: {
profileBgColor: async function (val) { profileBgColor: function (val) {
this.profileTextColor = await this.calculateColorLuminance(val) this.profileTextColor = calculateColorLuminance(val)
} }
}, },
created: function () { created: function () {
@ -163,8 +164,7 @@ export default Vue.extend({
'updateProfile', 'updateProfile',
'removeProfile', 'removeProfile',
'updateDefaultProfile', 'updateDefaultProfile',
'updateActiveProfile', 'updateActiveProfile'
'calculateColorLuminance'
]) ])
} }
}) })

View File

@ -14,6 +14,7 @@ import 'videojs-http-source-selector'
import { IpcChannels } from '../../../constants' import { IpcChannels } from '../../../constants'
import { sponsorBlockSkipSegments } from '../../helpers/sponsorblock' import { sponsorBlockSkipSegments } from '../../helpers/sponsorblock'
import { calculateColorLuminance } from '../../helpers/utils'
export default Vue.extend({ export default Vue.extend({
name: 'FtVideoPlayer', name: 'FtVideoPlayer',
@ -1175,7 +1176,7 @@ export default Vue.extend({
videojs.registerComponent('loopButton', loopButton) videojs.registerComponent('loopButton', loopButton)
}, },
toggleVideoLoop: async function () { toggleVideoLoop: function () {
const loopButton = document.getElementById('loopButton') const loopButton = document.getElementById('loopButton')
if (!this.player.loop()) { if (!this.player.loop()) {
@ -1187,7 +1188,7 @@ export default Vue.extend({
return color === currentTheme return color === currentTheme
}) })
const themeTextColor = await this.calculateColorLuminance(colorValues[nameIndex]) const themeTextColor = calculateColorLuminance(colorValues[nameIndex])
loopButton.classList.add('vjs-icon-loop-active') loopButton.classList.add('vjs-icon-loop-active')
@ -1923,7 +1924,6 @@ export default Vue.extend({
}, },
...mapActions([ ...mapActions([
'calculateColorLuminance',
'updateDefaultCaptionSettings', 'updateDefaultCaptionSettings',
'showToast', 'showToast',
'parseScreenshotCustomFileName', 'parseScreenshotCustomFileName',

View File

@ -0,0 +1,103 @@
export function calculateColorLuminance(colorValue) {
const cutHex = colorValue.substring(1, 7)
const colorValueR = parseInt(cutHex.substring(0, 2), 16)
const colorValueG = parseInt(cutHex.substring(2, 4), 16)
const colorValueB = parseInt(cutHex.substring(4, 6), 16)
const luminance = (0.299 * colorValueR + 0.587 * colorValueG + 0.114 * colorValueB) / 255
if (luminance > 0.5) {
return '#000000'
} else {
return '#FFFFFF'
}
}
export function calculatePublishedDate(publishedText) {
const date = new Date()
if (publishedText === 'Live') {
return publishedText
}
const textSplit = publishedText.split(' ')
if (textSplit[0].toLowerCase() === 'streamed') {
textSplit.shift()
}
const timeFrame = textSplit[1]
const timeAmount = parseInt(textSplit[0])
let timeSpan = null
if (timeFrame.indexOf('second') > -1) {
timeSpan = timeAmount * 1000
} else if (timeFrame.indexOf('minute') > -1) {
timeSpan = timeAmount * 60000
} else if (timeFrame.indexOf('hour') > -1) {
timeSpan = timeAmount * 3600000
} else if (timeFrame.indexOf('day') > -1) {
timeSpan = timeAmount * 86400000
} else if (timeFrame.indexOf('week') > -1) {
timeSpan = timeAmount * 604800000
} else if (timeFrame.indexOf('month') > -1) {
timeSpan = timeAmount * 2592000000
} else if (timeFrame.indexOf('year') > -1) {
timeSpan = timeAmount * 31556952000
}
return date.getTime() - timeSpan
}
export function buildVTTFileLocally(storyboard) {
let vttString = 'WEBVTT\n\n'
// how many images are in one image
const numberOfSubImagesPerImage = storyboard.sWidth * storyboard.sHeight
// the number of storyboard images
const numberOfImages = Math.ceil(storyboard.count / numberOfSubImagesPerImage)
const intervalInSeconds = storyboard.interval / 1000
let currentUrl = storyboard.url
let startHours = 0
let startMinutes = 0
let startSeconds = 0
let endHours = 0
let endMinutes = 0
let endSeconds = intervalInSeconds
for (let i = 0; i < numberOfImages; i++) {
let xCoord = 0
let yCoord = 0
for (let j = 0; j < numberOfSubImagesPerImage; j++) {
// add the timestamp information
const paddedStartHours = startHours.toString().padStart(2, '0')
const paddedStartMinutes = startMinutes.toString().padStart(2, '0')
const paddedStartSeconds = startSeconds.toString().padStart(2, '0')
const paddedEndHours = endHours.toString().padStart(2, '0')
const paddedEndMinutes = endMinutes.toString().padStart(2, '0')
const paddedEndSeconds = endSeconds.toString().padStart(2, '0')
vttString += `${paddedStartHours}:${paddedStartMinutes}:${paddedStartSeconds}.000 --> ${paddedEndHours}:${paddedEndMinutes}:${paddedEndSeconds}.000\n`
// add the current image url as well as the x, y, width, height information
vttString += currentUrl + `#xywh=${xCoord},${yCoord},${storyboard.width},${storyboard.height}\n\n`
// update the variables
startHours = endHours
startMinutes = endMinutes
startSeconds = endSeconds
endSeconds += intervalInSeconds
if (endSeconds >= 60) {
endSeconds -= 60
endMinutes += 1
}
if (endMinutes >= 60) {
endMinutes -= 60
endHours += 1
}
// x coordinate can only be smaller than the width of one subimage * the number of subimages per row
xCoord = (xCoord + storyboard.width) % (storyboard.width * storyboard.sWidth)
// only if the x coordinate is , so in a new row, we have to update the y coordinate
if (xCoord === 0) {
yCoord += storyboard.height
}
}
// make sure that there is no value like M0 or M1 in the parameters that gets replaced
currentUrl = currentUrl.replace('M' + i.toString() + '.jpg', 'M' + (i + 1).toString() + '.jpg')
}
return vttString
}

View File

@ -1,5 +1,6 @@
import { MAIN_PROFILE_ID } from '../../../constants' import { MAIN_PROFILE_ID } from '../../../constants'
import { DBProfileHandlers } from '../../../datastores/handlers/index' import { DBProfileHandlers } from '../../../datastores/handlers/index'
import { calculateColorLuminance } from '../../helpers/utils'
const state = { const state = {
profileList: [{ profileList: [{
@ -53,7 +54,7 @@ const actions = {
if (profiles.length === 0) { if (profiles.length === 0) {
// Create a default profile and persist it // Create a default profile and persist it
const randomColor = await dispatch('getRandomColor') const randomColor = await dispatch('getRandomColor')
const textColor = await dispatch('calculateColorLuminance', randomColor) const textColor = calculateColorLuminance(randomColor)
const defaultProfile = { const defaultProfile = {
_id: MAIN_PROFILE_ID, _id: MAIN_PROFILE_ID,
name: defaultName, name: defaultName,

View File

@ -563,57 +563,6 @@ const actions = {
commit('setRegionValues', regionValues) commit('setRegionValues', regionValues)
}, },
calculateColorLuminance (_, colorValue) {
const cutHex = colorValue.substring(1, 7)
const colorValueR = parseInt(cutHex.substring(0, 2), 16)
const colorValueG = parseInt(cutHex.substring(2, 4), 16)
const colorValueB = parseInt(cutHex.substring(4, 6), 16)
const luminance = (0.299 * colorValueR + 0.587 * colorValueG + 0.114 * colorValueB) / 255
if (luminance > 0.5) {
return '#000000'
} else {
return '#FFFFFF'
}
},
calculatePublishedDate(_, publishedText) {
const date = new Date()
if (publishedText === 'Live') {
return publishedText
}
const textSplit = publishedText.split(' ')
if (textSplit[0].toLowerCase() === 'streamed') {
textSplit.shift()
}
const timeFrame = textSplit[1]
const timeAmount = parseInt(textSplit[0])
let timeSpan = null
if (timeFrame.indexOf('second') > -1) {
timeSpan = timeAmount * 1000
} else if (timeFrame.indexOf('minute') > -1) {
timeSpan = timeAmount * 60000
} else if (timeFrame.indexOf('hour') > -1) {
timeSpan = timeAmount * 3600000
} else if (timeFrame.indexOf('day') > -1) {
timeSpan = timeAmount * 86400000
} else if (timeFrame.indexOf('week') > -1) {
timeSpan = timeAmount * 604800000
} else if (timeFrame.indexOf('month') > -1) {
timeSpan = timeAmount * 2592000000
} else if (timeFrame.indexOf('year') > -1) {
timeSpan = timeAmount * 31556952000
}
return date.getTime() - timeSpan
},
getVideoParamsFromUrl (_, url) { getVideoParamsFromUrl (_, url) {
/** @type {URL} */ /** @type {URL} */
let urlObject let urlObject
@ -855,86 +804,6 @@ const actions = {
} }
}, },
padNumberWithLeadingZeros(_, payload) {
let numberString = payload.number.toString()
while (numberString.length < payload.length) {
numberString = '0' + numberString
}
return numberString
},
async buildVTTFileLocally ({ dispatch }, Storyboard) {
let vttString = 'WEBVTT\n\n'
// how many images are in one image
const numberOfSubImagesPerImage = Storyboard.sWidth * Storyboard.sHeight
// the number of storyboard images
const numberOfImages = Math.ceil(Storyboard.count / numberOfSubImagesPerImage)
const intervalInSeconds = Storyboard.interval / 1000
let currentUrl = Storyboard.url
let startHours = 0
let startMinutes = 0
let startSeconds = 0
let endHours = 0
let endMinutes = 0
let endSeconds = intervalInSeconds
for (let i = 0; i < numberOfImages; i++) {
let xCoord = 0
let yCoord = 0
for (let j = 0; j < numberOfSubImagesPerImage; j++) {
// add the timestamp information
const paddedStartHours = await dispatch('padNumberWithLeadingZeros', {
number: startHours,
length: 2
})
const paddedStartMinutes = await dispatch('padNumberWithLeadingZeros', {
number: startMinutes,
length: 2
})
const paddedStartSeconds = await dispatch('padNumberWithLeadingZeros', {
number: startSeconds,
length: 2
})
const paddedEndHours = await dispatch('padNumberWithLeadingZeros', {
number: endHours,
length: 2
})
const paddedEndMinutes = await dispatch('padNumberWithLeadingZeros', {
number: endMinutes,
length: 2
})
const paddedEndSeconds = await dispatch('padNumberWithLeadingZeros', {
number: endSeconds,
length: 2
})
vttString += `${paddedStartHours}:${paddedStartMinutes}:${paddedStartSeconds}.000 --> ${paddedEndHours}:${paddedEndMinutes}:${paddedEndSeconds}.000\n`
// add the current image url as well as the x, y, width, height information
vttString += currentUrl + `#xywh=${xCoord},${yCoord},${Storyboard.width},${Storyboard.height}\n\n`
// update the variables
startHours = endHours
startMinutes = endMinutes
startSeconds = endSeconds
endSeconds += intervalInSeconds
if (endSeconds >= 60) {
endSeconds -= 60
endMinutes += 1
}
if (endMinutes >= 60) {
endMinutes -= 60
endHours += 1
}
// x coordinate can only be smaller than the width of one subimage * the number of subimages per row
xCoord = (xCoord + Storyboard.width) % (Storyboard.width * Storyboard.sWidth)
// only if the x coordinate is , so in a new row, we have to update the y coordinate
if (xCoord === 0) {
yCoord += Storyboard.height
}
}
// make sure that there is no value like M0 or M1 in the parameters that gets replaced
currentUrl = currentUrl.replace('M' + i.toString() + '.jpg', 'M' + (i + 1).toString() + '.jpg')
}
return vttString
},
toLocalePublicationString ({ dispatch }, payload) { toLocalePublicationString ({ dispatch }, payload) {
if (payload.isLive) { if (payload.isLive) {
return '0' + payload.liveStreamString return '0' + payload.liveStreamString

View File

@ -5,6 +5,7 @@ import FtProfileEdit from '../../components/ft-profile-edit/ft-profile-edit.vue'
import FtProfileChannelList from '../../components/ft-profile-channel-list/ft-profile-channel-list.vue' import FtProfileChannelList from '../../components/ft-profile-channel-list/ft-profile-channel-list.vue'
import FtProfileFilterChannelsList from '../../components/ft-profile-filter-channels-list/ft-profile-filter-channels-list.vue' import FtProfileFilterChannelsList from '../../components/ft-profile-filter-channels-list/ft-profile-filter-channels-list.vue'
import { MAIN_PROFILE_ID } from '../../../constants' import { MAIN_PROFILE_ID } from '../../../constants'
import { calculateColorLuminance } from '../../helpers/utils'
export default Vue.extend({ export default Vue.extend({
name: 'ProfileEdit', name: 'ProfileEdit',
@ -60,7 +61,7 @@ export default Vue.extend({
if (profileType === 'newProfile') { if (profileType === 'newProfile') {
this.isNew = true this.isNew = true
const bgColor = await this.getRandomColor() const bgColor = await this.getRandomColor()
const textColor = await this.calculateColorLuminance(bgColor) const textColor = calculateColorLuminance(bgColor)
this.profile = { this.profile = {
name: '', name: '',
bgColor: bgColor, bgColor: bgColor,
@ -88,8 +89,7 @@ export default Vue.extend({
methods: { methods: {
...mapActions([ ...mapActions([
'showToast', 'showToast',
'getRandomColor', 'getRandomColor'
'calculateColorLuminance'
]) ])
} }
}) })

View File

@ -11,6 +11,7 @@ import FtChannelBubble from '../../components/ft-channel-bubble/ft-channel-bubbl
import ytch from 'yt-channel-info' import ytch from 'yt-channel-info'
import Parser from 'rss-parser' import Parser from 'rss-parser'
import { MAIN_PROFILE_ID } from '../../../constants' import { MAIN_PROFILE_ID } from '../../../constants'
import { calculatePublishedDate } from '../../helpers/utils'
export default Vue.extend({ export default Vue.extend({
name: 'Subscriptions', name: 'Subscriptions',
@ -254,20 +255,20 @@ export default Vue.extend({
getChannelVideosLocalScraper: function (channel, failedAttempts = 0) { getChannelVideosLocalScraper: function (channel, failedAttempts = 0) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
ytch.getChannelVideos({ channelId: channel.id, sortBy: 'latest' }).then(async (response) => { ytch.getChannelVideos({ channelId: channel.id, sortBy: 'latest' }).then((response) => {
if (response.alertMessage) { if (response.alertMessage) {
this.errorChannels.push(channel) this.errorChannels.push(channel)
resolve([]) resolve([])
return return
} }
const videos = await Promise.all(response.items.map(async (video) => { const videos = response.items.map((video) => {
if (video.liveNow) { if (video.liveNow) {
video.publishedDate = new Date().getTime() video.publishedDate = new Date().getTime()
} else { } else {
video.publishedDate = await this.calculatePublishedDate(video.publishedText) video.publishedDate = calculatePublishedDate(video.publishedText)
} }
return video return video
})) })
resolve(videos) resolve(videos)
}).catch((err) => { }).catch((err) => {
@ -497,7 +498,6 @@ export default Vue.extend({
'updateShowProgressBar', 'updateShowProgressBar',
'updateProfileSubscriptions', 'updateProfileSubscriptions',
'updateAllSubscriptionsList', 'updateAllSubscriptionsList',
'calculatePublishedDate',
'copyToClipboard' 'copyToClipboard'
]), ]),

View File

@ -15,6 +15,7 @@ import WatchVideoPlaylist from '../../components/watch-video-playlist/watch-vide
import WatchVideoRecommendations from '../../components/watch-video-recommendations/watch-video-recommendations.vue' import WatchVideoRecommendations from '../../components/watch-video-recommendations/watch-video-recommendations.vue'
import FtAgeRestricted from '../../components/ft-age-restricted/ft-age-restricted.vue' import FtAgeRestricted from '../../components/ft-age-restricted/ft-age-restricted.vue'
import i18n from '../../i18n/index' import i18n from '../../i18n/index'
import { buildVTTFileLocally } from '../../helpers/utils'
const isDev = process.env.NODE_ENV === 'development' const isDev = process.env.NODE_ENV === 'development'
@ -1347,8 +1348,8 @@ export default Vue.extend({
}) })
}) })
// TODO: MAKE A VARIABLE WHICH CAN CHOOSE BETWEEN STORYBOARD ARRAY ELEMENTS // TODO: MAKE A VARIABLE WHICH CAN CHOOSE BETWEEN STORYBOARD ARRAY ELEMENTS
this.buildVTTFileLocally(storyboardArray[1]).then(async (results) => { const results = buildVTTFileLocally(storyboardArray[1])
const userData = await this.getUserDataPath() this.getUserDataPath().then((userData) => {
let fileLocation let fileLocation
let uriSchema let uriSchema
@ -1536,7 +1537,6 @@ export default Vue.extend({
...mapActions([ ...mapActions([
'showToast', 'showToast',
'buildVTTFileLocally',
'updateHistory', 'updateHistory',
'updateWatchProgress', 'updateWatchProgress',
'getUserDataPath', 'getUserDataPath',