Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ updates:
- "@eslint/*"
- "yaml-eslint-parser"
- "vue-eslint-parser"
- "neostandard"
stylelint:
patterns:
- "stylelint"
Expand Down
4 changes: 2 additions & 2 deletions _scripts/ProcessLocalesPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down
2 changes: 1 addition & 1 deletion _scripts/getShakaLocales.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
11 changes: 11 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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' }

Expand Down Expand Up @@ -40,6 +41,7 @@ export default [
],
plugins: {
unicorn: eslintPluginUnicorn,
jsdoc,
},

languageOptions: {
Expand Down Expand Up @@ -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',
},
},

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
3 changes: 3 additions & 0 deletions src/renderer/components/ChannelDetails/ChannelDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
Expand Down
6 changes: 6 additions & 0 deletions src/renderer/components/FtCommunityPost/FtCommunityPost.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
})
Expand All @@ -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()
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/components/FtElementList/FtElementList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
Expand Down
7 changes: 7 additions & 0 deletions src/renderer/components/FtListChannel/FtListChannel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -91,23 +91,29 @@ 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
})

let id = ''
let thumbnail = ''
let name = ''
/** @type {number?} */
let subscriberCount = null
/** @type {number?} */
let videoCount = null
/** @type {string?} */
let handle = null
let description = ''

Expand Down Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions src/renderer/components/FtListHashtag/FtListHashtag.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 [] }
Expand All @@ -166,6 +170,7 @@ const channelsHidden = computed(() => {
})
})

/** @type {string[]} */
const forbiddenTitles = computed(() => {
if (!props.hideForbiddenTitles) { return [] }
return JSON.parse(store.getters.getForbiddenTitles)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ function onTimestamp(timestamp) {

/**
* @param {string} descriptionText
* @returns {string}
*/
function parseDescriptionHtml(descriptionText) {
return descriptionText
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ defineProps({
}
})

/** @type {import('vue').ComputedRef<boolean>} */
const playNextVideo = computed(() => {
return store.getters.getPlayNextVideo
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ export default defineComponent({
* color: string,
* skip: 'autoSkip' | 'promptToSkip' | 'showInSeekBar' | 'doNothing'
* }
* }} */
}} */
const categoryData = {}

sponsorCategories.forEach(x => {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -1870,7 +1870,7 @@ export default defineComponent({

/**
* @param {WheelEvent} event
* */
*/
function mouseScrollVolume(event) {
if (!event.ctrlKey && !event.metaKey) {
event.preventDefault()
Expand Down Expand Up @@ -2145,7 +2145,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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/components/ft-share-button/ft-share-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
},
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/helpers/accessibility.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/**
* @param {string} attribute
* @returns {string}
*/
export function sanitizeForHtmlId(attribute) {
return attribute.replaceAll(/\s+/g, '')
}
5 changes: 5 additions & 0 deletions src/renderer/helpers/api/invidious.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 5 additions & 5 deletions src/renderer/helpers/api/local.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down Expand Up @@ -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') {
Expand Down
20 changes: 10 additions & 10 deletions src/renderer/helpers/channels.js
Original file line number Diff line number Diff line change
Expand Up @@ -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') {
Expand Down Expand Up @@ -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 {
Expand Down
Loading