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
34 changes: 25 additions & 9 deletions src/renderer/components/CommentSection/CommentSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ import FtTimestampCatcher from '../FtTimestampCatcher.vue'
import store from '../../store/index'

import { copyToClipboard, showToast } from '../../helpers/utils'
import { getLocalComments, parseLocalComment } from '../../helpers/api/local'
import { getLocalCommunityPostComments, getLocalComments, parseLocalComment } from '../../helpers/api/local'
import {
getInvidiousCommunityPostCommentReplies,
getInvidiousCommunityPostComments,
Expand Down Expand Up @@ -476,7 +476,7 @@ function isSubscribedToChannel(channelId) {
function getCommentData() {
isLoading.value = true

if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious' || props.isPostComments) {
if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {
if (!props.isPostComments) {
getCommentDataInvidious()
} else {
Expand All @@ -491,7 +491,7 @@ function getMoreComments() {
if (commentData.value.length === 0 || nextPageToken.value == null) {
showToast(t('Comments.There are no more comments for this video'))
} else {
if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious' || props.isPostComments) {
if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {
if (!props.isPostComments) {
getCommentDataInvidious()
} else {
Expand All @@ -518,7 +518,7 @@ function toggleCommentReplies(index) {
* @param {number} index
*/
function getCommentReplies(index) {
if (!process.env.SUPPORTS_LOCAL_API || commentData.value[index].dataType === 'invidious' || props.isPostComments) {
if (!process.env.SUPPORTS_LOCAL_API || commentData.value[index].dataType === 'invidious') {
if (!props.isPostComments) {
getCommentRepliesInvidious(index)
} else {
Expand All @@ -545,9 +545,15 @@ async function getCommentDataLocal(more = false) {
comments = await localCommentsInstance.applySort(sortNewest.value ? 'NEWEST_FIRST' : 'TOP_COMMENTS')
localCommentsInstance = comments
} else {
comments = await getLocalComments(props.id)
sortNewest.value = comments.header?.sort_menu?.sub_menu_items?.[1].selected ?? false
localCommentsInstance = comments
if (props.isPostComments) {
comments = await getLocalCommunityPostComments(props.id, props.postAuthorId)
sortNewest.value = comments.header?.sort_menu?.sub_menu_items?.[1].selected ?? false
localCommentsInstance = comments
} else {
comments = await getLocalComments(props.id)
sortNewest.value = comments.header?.sort_menu?.sub_menu_items?.[1].selected ?? false
localCommentsInstance = comments
}
}

const parsedComments = comments.contents
Expand Down Expand Up @@ -596,7 +602,11 @@ async function getCommentDataLocal(more = false) {
if (backendFallback.value && backendPreference.value === 'local') {
localCommentsInstance = undefined
showToast(t('Falling back to Invidious API'))
getCommentDataInvidious()
if (props.isPostComments) {
getPostCommentsInvidious()
} else {
getCommentDataInvidious()
}
} else {
isLoading.value = false
}
Expand Down Expand Up @@ -763,7 +773,13 @@ function getPostCommentsInvidious() {
showToast(`${errorMessage}: ${err}`, 10000, () => {
copyToClipboard(err)
})
isLoading.value = false

if (process.env.SUPPORTS_LOCAL_API && backendFallback.value && backendPreference.value === 'invidious') {
showToast(t('Falling back to Local API'))
getCommentDataLocal()
} else {
isLoading.value = false
}
})
}

Expand Down
11 changes: 1 addition & 10 deletions src/renderer/components/FtCommunityPost/FtCommunityPost.vue
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
aria-hidden="true"
/> {{ formattedVoteCount }}</span>
<router-link
v-if="isInvidiousAllowed && !singlePost"
v-if="!singlePost"
:to="{
path: `/post/${postId}`,
query: authorId ? { authorId } : undefined
Expand Down Expand Up @@ -218,15 +218,6 @@ const backendPreference = computed(() => {
return store.getters.getBackendPreference
})

/** @type {import('vue').ComputedRef<boolean>} */
const backendFallback = computed(() => {
return store.getters.getBackendFallback
})

const isInvidiousAllowed = computed(() => {
return backendPreference.value === 'invidious' || backendFallback.value
})

let postType = ''
let postText = ''
let postId = ''
Expand Down
37 changes: 33 additions & 4 deletions src/renderer/helpers/api/local.js
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,11 @@ function decipherFormats(formats, player) {
}
}

export async function getLocalChannelId(url) {
/**
* @param {string} url
* @param {boolean} doLogError
*/
export async function getLocalChannelId(url, doLogError = false) {
try {
const innertube = await createInnertube()

Expand All @@ -368,11 +372,16 @@ export async function getLocalChannelId(url) {
} else if (navigationEndpoint.metadata.page_type === 'WEB_PAGE_TYPE_UNKNOWN' && navigationEndpoint.payload.url?.startsWith('https://www.youtube.com/')) {
// handle redirects like https://www.youtube.com/@wanderbots, which resolves to https://www.youtube.com/Wanderbots, which we need to resolve again
url = navigationEndpoint.payload.url
} else {
return null
} else if (navigationEndpoint.payload.browseId === 'FEpost_detail') {
// convert base64 params to string and get the channelid
return atob(navigationEndpoint.payload.params).replaceAll(/[^\d\sA-Za-z-]/g, ' ').trim().split(' ').at(-1)
}
}
} catch { }
} catch (e) {
if (doLogError) {
console.error(e)
}
}

return null
}
Expand Down Expand Up @@ -1816,3 +1825,23 @@ export async function getHashtagLocal(hashtag) {
const innertube = await createInnertube()
return await innertube.getHashtag(hashtag)
}

export async function getLocalCommunityPost(postId, channelId) {
const innertube = await createInnertube()
if (channelId == null) {
channelId = await getLocalChannelId('https://www.youtube.com/post/' + postId, true)
}

const postPage = await innertube.getPost(postId, channelId)
return parseLocalCommunityPost(postPage.posts[0])
}

/**
* @param {string} postId
* @param {string} channelId
*/
export async function getLocalCommunityPostComments(postId, channelId) {
const innertube = await createInnertube()

return await innertube.getPostComments(postId, channelId)
}
79 changes: 60 additions & 19 deletions src/renderer/views/Post.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
<template>
<div>
<div v-if="!isInvidiousAllowed">
{{ $t('Channel.Posts.Viewing Posts Only Supported By Invidious') }}
</div>
<FtLoader v-else-if="isLoading" />
<FtLoader v-if="isLoading" />
<template
v-else
>
Expand All @@ -22,7 +19,7 @@
:force-state="null"
:is-post-comments="true"
:channel-thumbnail="post.authorThumbnails[0].url"
:show-sort-by="false"
:show-sort-by="backendPreference == 'local'"
/>
</template>
</div>
Expand All @@ -32,6 +29,7 @@
import { computed, onMounted, ref, shallowRef, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router/composables'
import packageDetails from '../../../package.json'
import { useI18n } from '../composables/use-i18n-polyfill'

import FtCard from '../components/ft-card/ft-card.vue'
import FtCommunityPost from '../components/FtCommunityPost/FtCommunityPost.vue'
Expand All @@ -41,6 +39,10 @@ import CommentSection from '../components/CommentSection/CommentSection.vue'
import store from '../store/index'

import { getInvidiousCommunityPost } from '../helpers/api/invidious'
import { getLocalCommunityPost } from '../helpers/api/local'
import { copyToClipboard, showToast } from '../helpers/utils'

const { t } = useI18n()

const router = useRouter()
const route = useRoute()
Expand All @@ -60,22 +62,18 @@ const backendFallback = computed(() => {
return store.getters.getBackendFallback
})

const isInvidiousAllowed = computed(() => {
return backendPreference.value === 'invidious' || backendFallback.value
})

onMounted(async () => {
if (isInvidiousAllowed.value) {
id.value = route.params.id
authorId.value = route.query.authorId
id.value = route.params.id
authorId.value = route.query.authorId

if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {
await loadDataInvidiousAsync()
} else {
await loadDataLocalAsync()
}
})

async function loadDataInvidiousAsync() {
post.value = await getInvidiousCommunityPost(id.value, authorId.value)
authorId.value = post.value.authorId

function updateTitleAndRoute() {
store.commit('setAppTitle', `${post.value.author} - ${packageDetails.productName}`)
isLoading.value = false

Expand All @@ -92,13 +90,56 @@ async function loadDataInvidiousAsync() {
}
}

async function loadDataLocalAsync() {
try {
post.value = await getLocalCommunityPost(id.value, authorId.value)
authorId.value = post.value.authorId
updateTitleAndRoute()
} catch (error) {
console.error(error)
const errorMessage = t('Local API Error (Click to copy)')
showToast(`${errorMessage}: ${error}`, 10000, () => {
copyToClipboard(error)
})
if (backendPreference.value === 'local' && backendFallback.value) {
showToast(t('Falling back to Invidious API'))
await loadDataInvidiousAsync()
} else {
isLoading.value = false
}
}
}

async function loadDataInvidiousAsync() {
try {
post.value = await getInvidiousCommunityPost(id.value, authorId.value)
authorId.value = post.value.authorId
updateTitleAndRoute()
} catch (error) {
console.error(error)
const errorMessage = t('Invidious API Error (Click to copy)')
showToast(`${errorMessage}: ${error}`, 10000, () => {
copyToClipboard(error)
})

if (process.env.SUPPORTS_LOCAL_API && backendPreference.value === 'invidious' && backendFallback.value) {
showToast(t('Falling back to Local API'))
await loadDataLocalAsync()
} else {
isLoading.value = false
}
}
}

watch(() => route.params.id, async () => {
// react to route changes...
isLoading.value = true
if (isInvidiousAllowed.value) {
id.value = route.params.id
authorId.value = route.query.authorId
id.value = route.params.id
authorId.value = route.query.authorId
if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {
await loadDataInvidiousAsync()
} else {
await loadDataLocalAsync()
}
})
</script>
1 change: 0 additions & 1 deletion static/locales/en-US.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,6 @@ Channel:
Reveal Answers: Reveal Answers
Hide Answers: Hide Answers
Video hidden by FreeTube: Video hidden by FreeTube
Viewing Posts Only Supported By Invidious: Viewing Posts is only supported by Invidious. Head to a channel's community tab to view content there without Invidious.
Video:
IP block: 'YouTube has blocked your IP address from watching videos. Please try switching to a different VPN or proxy.'
MembersOnly: Members-only videos cannot be watched with FreeTube as they require Google login and paid membership to the uploader's channel.
Expand Down