Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a586c5f
Add local api support for viewing community posts
ChunkyProgrammer Dec 31, 2024
7008967
Allow comments to be sorted when using local api
ChunkyProgrammer Dec 31, 2024
f4e3c9f
add 'local' to function name to get post comments, update innertube m…
ChunkyProgrammer Dec 31, 2024
ce27df8
remove unused translation strings
ChunkyProgrammer Jan 27, 2025
9a7f279
use array index instead of `first()`
ChunkyProgrammer Jan 27, 2025
7be30a5
remove new translations
ChunkyProgrammer Feb 2, 2025
27ef07f
remove new translations
ChunkyProgrammer Feb 10, 2025
d6b715f
remove unused resource from locale file
ChunkyProgrammer Feb 26, 2025
8867d23
fix: getting channel id from post url
ChunkyProgrammer Mar 18, 2025
554949f
Merge branch 'development' into add-local-api-support-for-viewing-com…
ChunkyProgrammer Apr 24, 2025
9886b77
use default sort by for community comments
ChunkyProgrammer Apr 24, 2025
c01ff26
Merge branch 'development' into add-local-api-support-for-viewing-com…
ChunkyProgrammer Jun 3, 2025
49ffb12
Merge branch 'development' into add-local-api-support-for-viewing-com…
ChunkyProgrammer Jun 17, 2025
a18ec33
remove key from locales that recently(-ish) added it
ChunkyProgrammer Jun 17, 2025
58887ec
Merge branch 'development' into add-local-api-support-for-viewing-com…
ChunkyProgrammer Jun 26, 2025
925862a
Merge branch 'development' into add-local-api-support-for-viewing-com…
ChunkyProgrammer Jul 13, 2025
6ba3fe3
Merge branch 'development' into add-local-api-support-for-viewing-com…
ChunkyProgrammer Jul 19, 2025
7a31728
fix going to posts without the channel id in the url
ChunkyProgrammer Jul 22, 2025
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 (if this gets updated, we should look into using a protobuf library instead)
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 @@ -1814,3 +1823,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)
}
77 changes: 58 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,54 @@ 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
if (!process.env.SUPPORTS_LOCAL_API || backendPreference.value === 'invidious') {
await loadDataInvidiousAsync()
} else {
await loadDataLocalAsync()
}
})
</script>
2 changes: 0 additions & 2 deletions static/locales/af.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -833,8 +833,6 @@ Channel:
Hide Answers: 'Versteek antwoorde'
Video hidden by FreeTube: 'Video is deur FreeTube versteek'
View Full Post: Bekyk volle plasing
Viewing Posts Only Supported By Invidious: Bekyk van plasings word slegs vir Invidious
ondersteun. Gaan na ’n kanaal se gemeenskapsblad om inhoud te sien sonder Invidious.
Home:
Home: Tuis
View Playlist: Bekyk afspeellys
Expand Down
1 change: 0 additions & 1 deletion static/locales/ar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,6 @@ Channel:
votes: '{votes} أصوات'
Reveal Answers: كشف الإجابات
Video hidden by FreeTube: تم إخفاء الفيديو بواسطة FreeTube
Viewing Posts Only Supported By Invidious: عرض المنشورات مدعوم فقط من قبل Invidious. توجه إلى علامة التبويب مجتمع القناة لعرض المحتوى هناك دون Invidious.
View Full Post: عرض المنشور كاملا
Live:
Live: مباشر
Expand Down
1 change: 0 additions & 1 deletion static/locales/awa.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,6 @@ Channel:
Reveal Answers: ''
Hide Answers: ''
Video hidden by FreeTube: ''
Viewing Posts Only Supported By Invidious: ''
Video:
IP block: ''
MembersOnly: ''
Expand Down
1 change: 0 additions & 1 deletion static/locales/be.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,6 @@ Channel:
Hide Answers: 'Схаваць адказы'
Video hidden by FreeTube: Відэа схавана FreeTube'ам
View Full Post: Глядзець поўны пост
Viewing Posts Only Supported By Invidious: Прагляд паведамленняў падтрымліваецца толькі ў Invidious. Перайдзіце на ўкладку супольнасці канала, каб праглядзець там змесціва без Invidious.
Home:
Home: Галоўная старонка
View Playlist: Праглядзець плэй-ліст
Expand Down
3 changes: 0 additions & 3 deletions static/locales/bg.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -833,9 +833,6 @@ Channel:
Reveal Answers: Разкриване на отговорите
Hide Answers: Скриване на отговорите
Video hidden by FreeTube: Видео, скрито от FreeTube
Viewing Posts Only Supported By Invidious: Преглеждането на публикации се поддържа
само от Invidious. Отидете в раздела на общността на канала, за да видите съдържанието
там без Invidious.
View Full Post: Преглед на цялата публикация
This channel does not exist: Каналът не съществува
This channel does not allow searching: Каналът не позволява търсене
Expand Down
1 change: 0 additions & 1 deletion static/locales/br.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,6 @@ Channel:
Reveal Answers: 'Diskouez ar respontoù'
Hide Answers: 'Kuzhat ar respontoù'
Video hidden by FreeTube: 'Video kuzhet gant FreeTube'
Viewing Posts Only Supported By Invidious: 'Posupl eo gwelet ar pennadoù gant Invidious hepken. Kit war ivinell kumuniezh ur chadenn evit gwelet he fennadoù hep Invidious.'
Home:
Home: Degemer
View Playlist: Diskouez ar roll-videoioù
Expand Down
1 change: 0 additions & 1 deletion static/locales/cs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,6 @@ Channel:
Reveal Answers: Odhalit odpovědi
Video hidden by FreeTube: Video skryté programem FreeTube
View Full Post: Zobrazit celý příspěvek
Viewing Posts Only Supported By Invidious: Zobrazení příspěvků je podporováno pouze službou Invidious. Přejděte do karty komunity kanálu pro zobrazení jejího obsahu bez Invidious.
Live:
Live: Živě
This channel does not currently have any live streams: Tento kanál v současné době nemá žádné živé přenosy
Expand Down
1 change: 0 additions & 1 deletion static/locales/cy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,6 @@ Channel:
Hide Answers: 'Cuddio Atebion'
Video hidden by FreeTube: Fideo wedi'i guddio gan FreeTube
View Full Post: Gweld Post Llawn
Viewing Posts Only Supported By Invidious: Dim ond Invidious sy'n cefnogi Gweld Postiadau. Ewch i dab cymunedol sianel i weld cynnwys yno heb Invidious.
Home:
Home: Cartref
View Playlist: Gweld Rhestr Chwarae
Expand Down
2 changes: 0 additions & 2 deletions static/locales/da.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -817,8 +817,6 @@ Channel:
votes: '{votes} stemmer'
Reveal Answers: Vis svar
View Full Post: Se hele opslaget
Viewing Posts Only Supported By Invidious: Visning af opslag understøttes kun
af Invidious. Gå til en kanals fællesskabsfane for at se indholdet uden Invidious.
This channel does not allow searching: Denne kanal tillader ikke søgning
This channel is age-restricted and currently cannot be viewed in FreeTube.: Denne
kanal er aldersbegrænset og kan i øjeblikket ikke ses på FreeTube.
Expand Down
1 change: 0 additions & 1 deletion static/locales/de-DE.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,6 @@ Channel:
Hide Answers: Antworten verbergen
Video hidden by FreeTube: Video versteckt von FreeTube
View Full Post: Vollständigen Beitrag anzeigen
Viewing Posts Only Supported By Invidious: Das Anzeigen von Beiträgen wird nur von Invidious unterstützt. Gehe zum Tab „Beiträge“ eines Kanals, um dort Inhalte ohne Invidious anzuzeigen.
Live:
Live: Live
This channel does not currently have any live streams: Dieser Kanal hat derzeit keine Livestreams
Expand Down
3 changes: 0 additions & 3 deletions static/locales/el.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -859,9 +859,6 @@ Channel:
votes: '{votes} ψήφοι'
View Full Post: Προβολή πλήρους δημοσίευσης
Video hidden by FreeTube: Βίντεο κρυμμένο από FreeTube
Viewing Posts Only Supported By Invidious: Η προβολή αναρτήσεων υποστηρίζεται
μόνο από το Invidious. Μεταβείτε στην καρτέλα της κοινότητας ενός καναλιού για
να δείτε το περιεχόμενο εκεί χωρίς το Invidious.
Live:
Live: Ζωντανά
This channel does not currently have any live streams: Αυτό το κανάλι δεν έχει
Expand Down
1 change: 0 additions & 1 deletion static/locales/en-GB.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,6 @@ Channel:
votes: '{votes} votes'
Video hidden by FreeTube: Video hidden by FreeTube
View Full Post: View Full Post
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.
Live:
This channel does not currently have any live streams: This channel does not currently have any live streams
Live: Live
Expand Down
Loading
Loading