Add some missing jsdoc comments, add jsdoc eslint plugin (#6048)

* Add some missing jsdoc comments, add jsdoc eslint plugin

* remove left over addition

Co-authored-by: absidue <48293849+absidue@users.noreply.github.com>

* move jsdoc eslint rule configuration

* use dash for list instead

* Enable some additional rules

* Apply suggestions from code review

Co-authored-by: PikachuEXE <git@pikachuexe.net>

---------

Co-authored-by: absidue <48293849+absidue@users.noreply.github.com>
Co-authored-by: PikachuEXE <git@pikachuexe.net>
This commit is contained in:
ChunkyProgrammer
2024-11-02 06:38:07 -04:00
committed by GitHub
parent a2df91f1dc
commit a28bb3f0f5
28 changed files with 248 additions and 56 deletions

View File

@@ -20,6 +20,7 @@ updates:
- "@eslint/*"
- "yaml-eslint-parser"
- "vue-eslint-parser"
- "neostandard"
stylelint:
patterns:
- "stylelint"

View File

@@ -26,11 +26,11 @@ class ProcessLocalesPlugin {
}
this.outputDir = options.outputDir
/** @type {Map<str, any>} */
/** @type {Map<string, any>} */
this.locales = new Map()
this.localeNames = []
/** @type {Map<str, any>} */
/** @type {Map<string, any>} */
this.cache = new Map()
this.filePaths = []

View File

@@ -32,7 +32,7 @@ function getMappings(shakaLocales, freeTubeLocales) {
* @type {[string, string][]}
* Using this structure as it gets passed to `new Map()` in the player component
* The first element is the FreeTube locale, the second one is the shaka-player one
**/
*/
const mappings = []
for (const locale of freeTubeLocales) {

View File

@@ -10,6 +10,7 @@ import eslintPluginJsonc from 'eslint-plugin-jsonc'
import eslintPluginYml from 'eslint-plugin-yml'
import yamlEslintParser from 'yaml-eslint-parser'
import neostandard from 'neostandard'
import jsdoc from 'eslint-plugin-jsdoc'
import activeLocales from './static/locales/activeLocales.json' with { type: 'json' }
@@ -40,6 +41,7 @@ export default [
],
plugins: {
unicorn: eslintPluginUnicorn,
jsdoc,
},
languageOptions: {
@@ -115,6 +117,15 @@ export default [
'@intlify/vue-i18n/no-deprecated-tc': 'off',
'vue/require-explicit-emits': 'error',
'vue/no-unused-emit-declarations': 'error',
'jsdoc/check-alignment': 'error',
'jsdoc/check-property-names': 'error',
'jsdoc/check-param-names': 'error',
'jsdoc/check-syntax': 'error',
'jsdoc/check-template-names': 'error',
'jsdoc/check-types': 'error',
'jsdoc/no-bad-blocks': 'error',
'jsdoc/no-multi-asterisks': 'error',
},
},

View File

@@ -91,6 +91,7 @@
"electron-builder": "^25.1.8",
"eslint": "^9.11.1",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsdoc": "^50.4.3",
"eslint-plugin-jsonc": "^2.16.0",
"eslint-plugin-unicorn": "^56.0.0",
"eslint-plugin-vue": "^9.30.0",

View File

@@ -280,14 +280,17 @@ const props = defineProps({
const emit = defineEmits(['change-tab', 'search', 'subscribed'])
/** @type {import('vue').ComputedRef<boolean>} */
const hideChannelSubscriptions = computed(() => {
return store.getters.getHideChannelSubscriptions
})
/** @type {import('vue').ComputedRef<boolean>} */
const hideSharingActions = computed(() => {
return store.getters.getHideSharingActions
})
/** @type {import('vue').ComputedRef<boolean>} */
const hideUnsubscribeButton = computed(() => {
return store.getters.getHideUnsubscribeButton
})

View File

@@ -198,10 +198,12 @@ const props = defineProps({
},
})
/** @type {import('vue').ComputedRef<'grid' | 'list'>} */
const listType = computed(() => {
return store.getters.getListType
})
/** @type {import('vue').ComputedRef<string[]>} */
const forbiddenTitles = computed(() => {
if (!props.hideForbiddenTitles) { return [] }
return JSON.parse(store.getters.getForbiddenTitles)
@@ -211,10 +213,12 @@ const hideVideo = computed(() => {
return forbiddenTitles.value.some((text) => props.data.postContent.content.title?.toLowerCase().includes(text.toLowerCase()))
})
/** @type {import('vue').ComputedRef<'local' | 'invidious'>} */
const backendPreference = computed(() => {
return store.getters.getBackendPreference
})
/** @type {import('vue').ComputedRef<boolean>} */
const backendFallback = computed(() => {
return store.getters.getBackendFallback
})
@@ -226,11 +230,13 @@ const isInvidiousAllowed = computed(() => {
let postType = ''
let postText = ''
let postId = ''
/** @type {string[]?} */
let authorThumbnails = null
let postContent = ''
let author = ''
let authorId = ''
let voteCount = 0
/** @type {number?} */
let commentCount = null
parseCommunityData()

View File

@@ -104,10 +104,12 @@ const props = defineProps({
const emit = defineEmits(['move-video-down', 'move-video-up', 'remove-from-playlist'])
/** @type {import('vue').ComputedRef<'grid' | 'list'>} */
const listType = computed(() => {
return store.getters.getListType
})
/** @type {import('vue').ComputedRef<'grid' | 'list'>} */
const displayValue = computed(() => {
return props.display === '' ? listType.value : props.display
})

View File

@@ -91,14 +91,17 @@ const props = defineProps({
}
})
/** @type {import('vue').ComputedRef<string>} */
const currentInvidiousInstanceUrl = computed(() => {
return store.getters.getCurrentInvidiousInstanceUrl
})
/** @type {import('vue').ComputedRef<'grid' | 'list'>} */
const listType = computed(() => {
return store.getters.getListType
})
/** @type {import('vue').ComputedRef<boolean>} */
const hideChannelSubscriptions = computed(() => {
return store.getters.getHideChannelSubscriptions
})
@@ -106,8 +109,11 @@ const hideChannelSubscriptions = computed(() => {
let id = ''
let thumbnail = ''
let name = ''
/** @type {number?} */
let subscriberCount = null
/** @type {number?} */
let videoCount = null
/** @type {string?} */
let handle = null
let description = ''
@@ -155,6 +161,7 @@ function parseLocalData() {
function parseInvidiousData() {
// Can be prefixed with `https://` or `//` (protocol relative)
/** @type {string} */
const thumbnailUrl = props.data.authorThumbnails[2].url
thumbnail = youtubeImageUrlToInvidious(thumbnailUrl, currentInvidiousInstanceUrl.value)

View File

@@ -67,13 +67,18 @@ const props = defineProps({
}
})
/** @type {import('vue').ComputedRef<'list'| 'grid'>} */
const listType = computed(() => {
return store.getters.getListType
})
/** @type {string} */
const title = props.data.title
/** @type {number} */
const channelCount = props.data.channelCount
/** @type {number} */
const videoCount = props.data.videoCount
/** @type {string} */
const url = `/hashtag/${encodeURIComponent(title.substring(1))}`
const formattedChannelCount = computed(() => {

View File

@@ -141,18 +141,22 @@ const props = defineProps({
const emit = defineEmits(['move-video-down', 'move-video-up', 'remove-from-playlist'])
/** @type {import('vue').ComputedRef<'video' | 'shortVideo' | 'channel' | 'playlist' | 'community'>} */
const finalDataType = computed(() => {
return props.data.type ?? props.dataType
})
/** @type {import('vue').ComputedRef<boolean>} */
const hideLiveStreams = computed(() => {
return store.getters.getHideLiveStreams
})
/** @type {import('vue').ComputedRef<boolean>} */
const hideUpcomingPremieres = computed(() => {
return store.getters.getHideUpcomingPremieres
})
/** @type {import('vue').ComputedRef<{name : string, preferredName: string, icon: string}[]>} */
const channelsHidden = computed(() => {
// Some component users like channel view will have this disabled
if (!props.useChannelsHiddenPreference) { return [] }
@@ -166,6 +170,7 @@ const channelsHidden = computed(() => {
})
})
/** @type {string[]} */
const forbiddenTitles = computed(() => {
if (!props.hideForbiddenTitles) { return [] }
return JSON.parse(store.getters.getForbiddenTitles)

View File

@@ -106,10 +106,12 @@ const currentChapter = computed(() => {
return props.chapters[currentIndex.value]
})
/** @type {import('vue').ComputedRef<string>} */
const currentTitle = computed(() => {
return currentChapter.value.title
})
/** @type {import('vue').ComputedRef<boolean>} */
const compact = computed(() => {
return !props.chapters[0].thumbnail
})

View File

@@ -60,6 +60,7 @@ function onTimestamp(timestamp) {
/**
* @param {string} descriptionText
* @returns {string}
*/
function parseDescriptionHtml(descriptionText) {
return descriptionText

View File

@@ -46,6 +46,7 @@ defineProps({
}
})
/** @type {import('vue').ComputedRef<boolean>} */
const playNextVideo = computed(() => {
return store.getters.getPlayNextVideo
})

View File

@@ -355,7 +355,7 @@ export default defineComponent({
* color: string,
* skip: 'autoSkip' | 'promptToSkip' | 'showInSeekBar' | 'doNothing'
* }
* }} */
}} */
const categoryData = {}
sponsorCategories.forEach(x => {
@@ -537,7 +537,7 @@ export default defineComponent({
* @param {'dash'|'audio'|'legacy'} format
* @param {boolean} useAutoQuality
* @returns {shaka.extern.PlayerConfiguration}
**/
*/
function getPlayerConfig(format, useAutoQuality = false) {
return {
// YouTube uses these values and they seem to work well in FreeTube too,
@@ -1872,7 +1872,7 @@ export default defineComponent({
/**
* @param {WheelEvent} event
* */
*/
function mouseScrollVolume(event) {
if (!event.ctrlKey && !event.metaKey) {
event.preventDefault()
@@ -2150,7 +2150,7 @@ export default defineComponent({
/**
* @param {shaka.util.Error} error
* @param {string} context
* @param {object=} details
* @param {object?} details
*/
function handleError(error, context, details) {
logShakaError(error, context, props.videoId, details)

View File

@@ -42,7 +42,7 @@ export class AudioTrackSelection extends shaka.ui.SettingsMenu {
/**
* @private
* @param {shaka.extern.TrackList=} tracks
* @param {shaka.extern.TrackList?} tracks
*/
updateAudioTracks_(tracks) {
if (!tracks) {

View File

@@ -19,7 +19,7 @@ export default defineComponent({
* Allows to render the dropdown conditionally
* 'Channel' will exclude embed links
* 'Video' (default) keeps the original behaviour
**/
*/
type: String,
default: 'Video'
},

View File

@@ -1,3 +1,7 @@
/**
* @param {string} attribute
* @returns {string}
*/
export function sanitizeForHtmlId(attribute) {
return attribute.replaceAll(/\s+/g, '')
}

View File

@@ -142,6 +142,11 @@ export async function invidiousGetCommentReplies({ id, replyToken }) {
return { commentData: parseInvidiousCommentData(response), continuation: response.continuation ?? null }
}
/**
* @param {string} url
* @param {string?} currentInstance
* @returns {string}
*/
export function youtubeImageUrlToInvidious(url, currentInstance = null) {
if (url == null) {
return null

View File

@@ -550,15 +550,15 @@ export async function getLocalArtistTopicChannelReleasesContinuation(channel, co
* @param {boolean} onlyIdNameThumbnail
*/
export function parseLocalChannelHeader(channel, onlyIdNameThumbnail = false) {
/** @type {string=} */
/** @type {string?} */
let id
/** @type {string} */
let name
/** @type {string=} */
/** @type {string?} */
let thumbnailUrl
/** @type {string=} */
/** @type {string?} */
let bannerUrl
/** @type {string=} */
/** @type {string?} */
let subscriberText
/** @type {string[]} */
const tags = []
@@ -766,7 +766,7 @@ export function parseLocalChannelShorts(shorts, channelId, channelName) {
/**
* @param {import('youtubei.js').YTNodes.Playlist|import('youtubei.js').YTNodes.GridPlaylist|import('youtubei.js').YTNodes.LockupView} playlist
* @param {string} channelId
* @param {string} chanelName
* @param {string} channelName
*/
export function parseLocalListPlaylist(playlist, channelId = undefined, channelName = undefined) {
if (playlist.type === 'LockupView') {

View File

@@ -4,11 +4,11 @@ import { getLocalChannel, parseLocalChannelHeader } from './api/local'
/**
* @param {string} id
* @param {{
* preference: string,
* fallback: boolean,
* invalid: boolean,
* }} backendOptions
*/
* preference: string,
* fallback: boolean,
* invalid: boolean,
* }} backendOptions
*/
async function findChannelById(id, backendOptions) {
try {
if (!process.env.SUPPORTS_LOCAL_API || backendOptions.preference === 'invidious') {
@@ -37,11 +37,11 @@ async function findChannelById(id, backendOptions) {
/**
* @param {string} id
* @param {{
* preference: string,
* fallback: boolean,
* }} backendOptions
* @returns {Promise<{icon: string, iconHref: string, preferredName: string} | { invalidId: boolean }>}
*/
* preference: string,
* fallback: boolean,
* }} backendOptions
* @returns {Promise<{icon: string, iconHref: string, preferredName: string} | { invalidId: boolean }>}
*/
export async function findChannelTagInfo(id, backendOptions) {
if (!checkYoutubeChannelId(id)) return { invalidId: true }
try {

View File

@@ -9,7 +9,7 @@ import { sponsorBlockSkipSegments } from '../sponsorblock'
* @param {shaka.util.Error} error
* @param {string} context
* @param {string} videoId
* @param {object=} details
* @param {object?} details
*/
export function logShakaError(error, context, videoId, details) {
const { Severity, Category, Code } = shaka.util.Error
@@ -189,13 +189,13 @@ export function sortCaptions(captions) {
* This function cleans it up, so that we can use it.
*
* Here is a list of things this function does:
* * Removes bogus roles and labels
* * Extracts the languages from the audio URLs if available and adds it to the adapation sets
* * Adds roles and labels when possible to add support for multiple audio tracks
* - Removes bogus roles and labels
* - Extracts the languages from the audio URLs if available and adds it to the adapation sets
* - Adds roles and labels when possible to add support for multiple audio tracks
*
* Things this function does not do:
* * Separate DRC (Stable Volume) from their original counterparts
* * Tag HDR video streams (Invidious puts all video streams in the same adaptation set,
* - Separate DRC (Stable Volume) from their original counterparts
* - Tag HDR video streams (Invidious puts all video streams in the same adaptation set,
* to tag HDR and SDR streams we would have to separate them out into multiple adaptation sets)
* @param {shaka.extern.xml.Node[]} periods
*/

View File

@@ -26,6 +26,9 @@ export function isKeyboardEventKeyPrintableChar(eventKey) {
return false
}
/**
* @param {string} title
*/
export function translateWindowTitle(title) {
switch (title) {
case 'Subscriptions':

View File

@@ -65,7 +65,7 @@ export function updateVideoListAfterProcessing(videos) {
/**
* @param {string} rssString
* @param {string} channelId
*/
*/
export async function parseYouTubeRSSFeed(rssString, channelId) {
// doesn't need to be asynchronous, but doing it allows us to do the relatively slow DOM querying in parallel
try {

View File

@@ -12,6 +12,10 @@ export const CHANNEL_HANDLE_REGEX = /^@[\w.-]{3,30}$/
const PUBLISHED_TEXT_REGEX = /(\d+)\s?([a-z]+)/i
/**
* @param {string} sortPreference
* @returns {string[]}
*/
export function getIconForSortPreference(sortPreference) {
switch (sortPreference) {
case 'name_descending':
@@ -192,6 +196,11 @@ export function toLocalePublicationString ({ publishText, isLive = false, isUpco
return i18n.t('Video.Publicationtemplate', { number: match[1], unit })
}
/**
* @param {import('youtubei.js/dist/src/parser/classes/PlayerStoryboardSpec').StoryboardData} storyboard
* @param {number} videoLengthSeconds
* @returns {string}
*/
export function buildVTTFileLocally(storyboard, videoLengthSeconds) {
let vttString = 'WEBVTT\n\n'
// how many images are in one image
@@ -249,6 +258,11 @@ export function buildVTTFileLocally(storyboard, videoLengthSeconds) {
return vttString
}
/**
* @param {string} message
* @param {number} time
* @param {Function} action
*/
export function showToast(message, time = null, action = null) {
FtToastEvents.dispatchEvent(new CustomEvent('toast-open', {
detail: {
@@ -260,13 +274,14 @@ export function showToast(message, time = null, action = null) {
}
/**
* This writes to the clipboard. If an error occurs during the copy,
* a toast with the error is shown. If the copy is successful and
* there is a success message, a toast with that message is shown.
* @param {string} content the content to be copied to the clipboard
* @param {null|string} messageOnSuccess the message to be displayed as a toast when the copy succeeds (optional)
* @param {null|string} messageOnError the message to be displayed as a toast when the copy fails (optional)
*/
* This writes to the clipboard. If an error occurs during the copy,
* a toast with the error is shown. If the copy is successful and
* there is a success message, a toast with that message is shown.
* @param {string} content the content to be copied to the clipboard
* @param {object} [options] - Optional settings for the copy operation.
* @param {null|string} options.messageOnSuccess the message to be displayed as a toast when the copy succeeds (optional)
* @param {null|string} options.messageOnError the message to be displayed as a toast when the copy fails (optional)
*/
export async function copyToClipboard(content, { messageOnSuccess = null, messageOnError = null } = {}) {
if (navigator.clipboard !== undefined && window.isSecureContext) {
try {
@@ -370,7 +385,7 @@ export async function showOpenDialog (options) {
/**
* @param {object} response the response from `showOpenDialog`
* @param {number} index which file to read (defaults to the first in the response)
* @returns the text contents of the selected file
* @returns {string} the text contents of the selected file
*/
export function readFileFromDialog(response, index = 0) {
return new Promise((resolve, reject) => {
@@ -396,6 +411,10 @@ export function readFileFromDialog(response, index = 0) {
})
}
/**
* @param {{defaultPath: string, filters: {name: string, extensions: string[]}[]}} options
* @returns { Promise<import('electron').SaveDialogReturnValue> | {canceled: boolean?, filePath: string } | { canceled: boolean?, handle?: Promise<FileSystemFileHandle> }}
*/
export async function showSaveDialog (options) {
if (process.env.IS_ELECTRON) {
const { ipcRenderer } = require('electron')
@@ -423,10 +442,10 @@ export async function showSaveDialog (options) {
}
/**
* Write to a file picked out from the `showSaveDialog` picker
* @param {object} response the response from `showSaveDialog`
* @param {string} content the content to be written to the file selected by the dialog
*/
* Write to a file picked out from the `showSaveDialog` picker
* @param {object} response the response from `showSaveDialog`
* @param {string} content the content to be written to the file selected by the dialog
*/
export async function writeFileFromDialog (response, content) {
if (process.env.IS_ELECTRON) {
const { filePath } = response
@@ -475,7 +494,11 @@ export function createWebURL(path) {
return `${origin}${windowPath}/${path}`
}
// strip html tags but keep <br>, <b>, </b> <s>, </s>, <i>, </i>
/**
* strip html tags but keep <br>, <b>, </b> <s>, </s>, <i>, </i>
* @param {string} value
* @returns {string}
*/
export function stripHTML(value) {
return value.replaceAll(/(<(?!br|\/?[abis]|img>)([^>]+)>)/gi, '')
}
@@ -522,6 +545,11 @@ export function formatDurationAsTimestamp(lengthSeconds) {
return timestamp
}
/**
* @param {{sortBy? : string, time?: string, duration?: string, features: string[]}?} filtersA
* @param {{sortBy? : string, time?: string, duration?: string, features: string[]}?} filtersB
* @returns {boolean}
*/
export function searchFiltersMatch(filtersA, filtersB) {
return filtersA?.sortBy === filtersB?.sortBy &&
filtersA?.time === filtersB?.time &&
@@ -530,6 +558,10 @@ export function searchFiltersMatch(filtersA, filtersB) {
filtersA?.features?.length === filtersB?.features?.length && filtersA?.features?.every((val, index) => val === filtersB?.features[index])
}
/**
* @param {string} filenameOriginal
* @returns {string}
*/
export function replaceFilenameForbiddenChars(filenameOriginal) {
let filenameNew = filenameOriginal
let forbiddenChars = {}
@@ -563,6 +595,9 @@ export function replaceFilenameForbiddenChars(filenameOriginal) {
return filenameNew
}
/**
* @returns {Promise<string>}
*/
export async function getSystemLocale() {
let locale
if (process.env.IS_ELECTRON) {
@@ -715,6 +750,11 @@ export function toDistractionFreeTitle(title, minUpperCase = 3) {
.replace(reg, x => capitalizedWord(x.toLowerCase()))
}
/**
* @param {number} number
* @param {Intl.NumberFormatOptions?} options
* @returns {string}
*/
export function formatNumber(number, options = undefined) {
return Intl.NumberFormat([i18n.locale, 'en'], options).format(number)
}
@@ -730,6 +770,13 @@ export function getTodayDateStrLocalTimezone() {
return timeNowStr.split('T')[0]
}
/**
*
* @param {number} date
* @param {boolean} hideSeconds
* @param {boolean} useThirtyDayMonths
* @returns {string}
*/
export function getRelativeTimeFromDate(date, hideSeconds = false, useThirtyDayMonths = true) {
if (!date) {
return ''
@@ -800,8 +847,9 @@ export function escapeHTML(untrusted) {
/**
* Performs a deep copy of a javascript object
* @param {Object} obj
* @returns {Object}
* @template T
* @param {T} obj
* @returns {T}
*/
export function deepCopy(obj) {
return JSON.parse(JSON.stringify(obj))
@@ -811,7 +859,8 @@ export function deepCopy(obj) {
* Check if the `name` of the error is `TimeoutError` to know if the error was caused by a timeout or something else.
* @param {number} timeoutMs
* @param {RequestInfo|URL} input
* @param {RequestInit=} init
* @param {RequestInit?} init
* @returns {Promise<Response>}
*/
export async function fetchWithTimeout(timeoutMs, input, init) {
const timeoutSignal = AbortSignal.timeout(timeoutMs)
@@ -839,6 +888,10 @@ export async function fetchWithTimeout(timeoutMs, input, init) {
}
}
/**
* @param {KeyboardEvent} event
* @param {HTMLInputElement} inputElement
*/
export function ctrlFHandler(event, inputElement) {
switch (event.key) {
case 'F':
@@ -879,11 +932,13 @@ export function base64EncodeUtf8(text) {
* @param {string} channelId
* @param {'all'} type
* @returns {string}
*
*
* @param {string} channelId
* @param {'all' | 'videos' | 'live' | 'shorts'} type
* @param {'newest' | 'popular'} sortBy
* @param {('newest' | 'popular')?} [sortBy]
* @returns {string}
*/
export function getChannelPlaylistId(channelId, type, sortBy) {
switch (type) {
case 'videos':

View File

@@ -712,7 +712,7 @@ export default defineComponent({
try {
/**
* @type {import('youtubei.js').YT.Channel}
*/
*/
const channel = this.channelInstance
const about = await channel.getAbout()
@@ -784,7 +784,7 @@ export default defineComponent({
} else {
/**
* @type {import('youtubei.js').YT.Channel}
*/
*/
const channel = this.channelInstance
let videosTab = await channel.getVideos()
@@ -934,7 +934,7 @@ export default defineComponent({
try {
/**
* @type {import('youtubei.js').YT.Channel}
*/
*/
const channel = this.channelInstance
let liveTab = await channel.getLiveStreams()
@@ -1426,7 +1426,7 @@ export default defineComponent({
try {
/**
* @type {import('youtubei.js').YT.Channel}
*/
*/
const channel = this.channelInstance
if (this.isArtistTopicChannel) {
@@ -1561,7 +1561,7 @@ export default defineComponent({
try {
/**
* @type {import('youtubei.js').YT.Channel}
*/
*/
const channel = this.channelInstance
const podcastTab = await channel.getPodcasts()

View File

@@ -722,7 +722,8 @@ export default defineComponent({
}
if (result.storyboards?.type === 'PlayerStoryboardSpec') {
let source = result.storyboards.boards
/** @type {import('youtubei.js/dist/src/parser/classes/PlayerStoryboardSpec').StoryboardData[]} */
let source = result.storyboardSpec.boards
if (window.innerWidth < 500) {
source = source.filter((board) => board.thumbnail_height <= 90)
}
@@ -1485,6 +1486,10 @@ export default defineComponent({
return result.adaptiveFormats
},
/**
* @param {import('youtubei.js/dist/src/parser/classes/PlayerStoryboardSpec').StoryboardData} storyboardInfo
* @returns {string}
*/
createLocalStoryboardUrls: function (storyboardInfo) {
const results = buildVTTFileLocally(storyboardInfo, this.videoLengthSeconds)

View File

@@ -978,6 +978,15 @@
minimatch "^9.0.3"
plist "^3.1.0"
"@es-joy/jsdoccomment@~0.49.0":
version "0.49.0"
resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.49.0.tgz#e5ec1eda837c802eca67d3b29e577197f14ba1db"
integrity sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==
dependencies:
comment-parser "1.4.1"
esquery "^1.6.0"
jsdoc-type-pratt-parser "~4.1.0"
"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
@@ -2277,6 +2286,11 @@ app-builder-lib@25.1.8:
resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc"
integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==
are-docs-informative@^0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/are-docs-informative/-/are-docs-informative-0.0.2.tgz#387f0e93f5d45280373d387a59d34c96db321963"
integrity sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==
are-we-there-yet@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd"
@@ -2996,6 +3010,11 @@ commander@^8.3.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
comment-parser@1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.4.1.tgz#bdafead37961ac079be11eb7ec65c4d021eaf9cc"
integrity sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==
common-path-prefix@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0"
@@ -3330,7 +3349,7 @@ debug@2.6.9:
dependencies:
ms "2.0.0"
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.7:
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.6, debug@^4.3.7:
version "4.3.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52"
integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==
@@ -3988,6 +4007,11 @@ es-module-lexer@^1.2.1:
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.2.1.tgz#ba303831f63e6a394983fde2f97ad77b22324527"
integrity sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==
es-module-lexer@^1.5.3:
version "1.5.4"
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78"
integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==
es-object-atoms@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941"
@@ -4138,6 +4162,23 @@ eslint-plugin-import@^2.31.0:
string.prototype.trimend "^1.0.8"
tsconfig-paths "^3.15.0"
eslint-plugin-jsdoc@^50.4.3:
version "50.4.3"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.4.3.tgz#38adf595555933775943771e906422b25cdfc780"
integrity sha512-uWtwFxGRv6B8sU63HZM5dAGDhgsatb+LONwmILZJhdRALLOkCX2HFZhdL/Kw2ls8SQMAVEfK+LmnEfxInRN8HA==
dependencies:
"@es-joy/jsdoccomment" "~0.49.0"
are-docs-informative "^0.0.2"
comment-parser "1.4.1"
debug "^4.3.6"
escape-string-regexp "^4.0.0"
espree "^10.1.0"
esquery "^1.6.0"
parse-imports "^2.1.1"
semver "^7.6.3"
spdx-expression-parse "^4.0.0"
synckit "^0.9.1"
eslint-plugin-jsonc@^2.16.0:
version "2.16.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsonc/-/eslint-plugin-jsonc-2.16.0.tgz#e90eca15aa2e172f5aca52a77fc8c819f52862d7"
@@ -5964,6 +6005,11 @@ jsbn@1.1.0:
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040"
integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==
jsdoc-type-pratt-parser@~4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz#ff6b4a3f339c34a6c188cbf50a16087858d22113"
integrity sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==
jsesc@^3.0.2, jsesc@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e"
@@ -7036,6 +7082,14 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
parse-imports@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/parse-imports/-/parse-imports-2.2.1.tgz#0a6e8b5316beb5c9905f50eb2bbb8c64a4805642"
integrity sha512-OL/zLggRp8mFhKL0rNORUTR4yBYujK/uU+xZL+/0Rgm2QE4nLO9v8PzEweSJEbMGKmDRjJE4R3IMJlL2di4JeQ==
dependencies:
es-module-lexer "^1.5.3"
slashes "^3.0.12"
parse-json@^5.0.0, parse-json@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
@@ -8341,6 +8395,11 @@ slash@^5.1.0:
resolved "https://registry.yarnpkg.com/slash/-/slash-5.1.0.tgz#be3adddcdf09ac38eebe8dcdc7b1a57a75b095ce"
integrity sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==
slashes@^3.0.12:
version "3.0.12"
resolved "https://registry.yarnpkg.com/slashes/-/slashes-3.0.12.tgz#3d664c877ad542dc1509eaf2c50f38d483a6435a"
integrity sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==
slice-ansi@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787"
@@ -8451,6 +8510,14 @@ spdx-expression-parse@^3.0.0:
spdx-exceptions "^2.1.0"
spdx-license-ids "^3.0.0"
spdx-expression-parse@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz#a23af9f3132115465dac215c099303e4ceac5794"
integrity sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==
dependencies:
spdx-exceptions "^2.1.0"
spdx-license-ids "^3.0.0"
spdx-license-ids@^3.0.0:
version "3.0.11"
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95"
@@ -8853,6 +8920,14 @@ synckit@^0.9.0:
"@pkgr/core" "^0.1.0"
tslib "^2.6.2"
synckit@^0.9.1:
version "0.9.2"
resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.2.tgz#a3a935eca7922d48b9e7d6c61822ee6c3ae4ec62"
integrity sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==
dependencies:
"@pkgr/core" "^0.1.0"
tslib "^2.6.2"
table@^6.8.2:
version "6.8.2"
resolved "https://registry.yarnpkg.com/table/-/table-6.8.2.tgz#c5504ccf201213fa227248bdc8c5569716ac6c58"