Skip to content

Commit

Permalink
✨ Add continuation for search results (#2838)
Browse files Browse the repository at this point in the history
  • Loading branch information
moisout committed Jun 15, 2024
1 parent 9b615a5 commit 1708c03
Show file tree
Hide file tree
Showing 20 changed files with 165 additions and 230 deletions.
6 changes: 3 additions & 3 deletions client/composables/api/search.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ApiDto } from '@viewtube/shared';
import { type LocationQuery } from 'vue-router';
import type { VTSearchDto } from '../../../server/src/mapper/dto/search/vt-search.dto';

export type FilterType = { filterValue: any; filterType?: any; filterName: any };

Expand All @@ -21,7 +21,7 @@ export const useGetSearchResult = () => {
`search`,
async () => {
const { apiUrl } = useApiUrl();
const searchResponse = await vtFetch<VTSearchDto>(`${apiUrl.value}search`, {
const searchResponse = await vtFetch<ApiDto<'VTSearchDto'>>(`${apiUrl.value}search`, {
query: { q: searchQuery.value, filters: searchFilters.value }
});

Expand All @@ -33,7 +33,7 @@ export const useGetSearchResult = () => {
);
};

const getSearchFilters = (query: LocationQuery) => {
export const getSearchFilters = (query: LocationQuery) => {
const searchParams = new URLSearchParams(query as Record<string, string>);
const filters: Record<string, string> = {};

Expand Down
3 changes: 1 addition & 2 deletions client/composables/proxyUrls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ export const useProxyUrls = () => {

const origin = window?.location?.origin ?? '';

const streamProxy = `${clientApiUrl.value}proxy/stream?url=`;
const streamProxy = `${clientApiUrl.value}proxy/stream?originUrl=${origin}&url=`;
return {
imgProxy: `${clientApiUrl.value}proxy/image?url=`,
streamProxy,
m3u8Proxy: `${clientApiUrl.value}proxy/m3u8?proxyUrl=${origin}${streamProxy}&url=`,
videoPlaybackProxy: `${clientApiUrl.value}videoplayback`,
textProxy: `${clientApiUrl.value}proxy/text?url=`
};
Expand Down
1 change: 0 additions & 1 deletion client/composables/videoplayer/videoSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export const useVideoSource = (video: Ref<ApiDto<'VTVideoInfoDto'>>) => {
sourceType = VideoSourceType.HLS;
source = video.value.hlsManifestUrl;
} else if (video.value.dashManifest) {
const googlevideoRegex = /https:\/\/.*?.googlevideo\.com/gi;
const manifest = video.value.dashManifest.replace(googlevideoRegex, videoPlaybackProxy);
sourceType = VideoSourceType.DASH;
source = 'data:application/dash+xml;charset=utf-8;base64,' + btoa(manifest);
Expand Down
103 changes: 56 additions & 47 deletions client/pages/results.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
import RelatedSearches from '@/components/search/RelatedSearches.vue';
import Spinner from '@/components/Spinner.vue';
import Filters from '@/components/search/Filters.vue';
import SeparatorSmall from '@/components/list/SeparatorSmall.vue';
import BadgeButton from '@/components/buttons/BadgeButton.vue';
import { useMessagesStore } from '@/store/messages';
import { useSettingsStore } from '@/store/settings';
import type { ApiDto } from '@viewtube/shared';
const VideoEntry = resolveComponent('ListVideoEntry');
const PlaylistEntry = resolveComponent('ListPlaylistEntry');
Expand All @@ -14,6 +17,8 @@ const Shelf = resolveComponent('SearchShelf');
const route = useRoute();
const messagesStore = useMessagesStore();
const settingsStore = useSettingsStore();
const { vtFetch } = useVtFetch();
const { apiUrl } = useApiUrl();
const searchQuery = computed(() => {
const searchParams = new URLSearchParams(route.query as Record<string, string>);
Expand All @@ -33,16 +38,16 @@ onMounted(() => {
}
});
// const additionalResultItems = ref([]);
// const searchContinuationData = ref<any>(searchData.value?.searchResults.continuation);
const additionalResultItems = ref([]);
const searchContinuationData = ref<any>(searchData.value?.continuation);
// watch(
// () => searchData.value,
// newData => {
// // additionalResultItems.value = [];
// searchContinuationData.value = newData?.searchResults.continuation;
// }
// );
watch(
() => searchData.value,
newData => {
additionalResultItems.value = [];
searchContinuationData.value = newData?.continuation;
}
);
watch(error, newValue => {
if (newValue) {
Expand Down Expand Up @@ -76,42 +81,46 @@ const getListEntryType = (type: string) => {
}
};
// const loadMoreVideos = async () => {
// moreVideosLoading.value = true;
// page.value += 1;
const moreVideosLoading = ref(false);
const page = ref(1);
const loadMoreVideos = async () => {
moreVideosLoading.value = true;
page.value += 1;
// if (searchData.value?.searchResults && searchContinuationData.value) {
// try {
// const searchContinuation = await vtFetch(
// `${apiUrl.value}search/continuation`,
// {
// method: 'POST',
// body: {
// continuationData: searchContinuationData.value
// }
// }
// );
if (searchData.value && searchContinuationData.value) {
try {
const searchContinuation = await vtFetch<ApiDto<'VTSearchDto'>>(`${apiUrl.value}search`, {
query: {
q: searchQuery.value,
filters: getSearchFilters(route.query),
continuationString: searchContinuationData.value
}
});
// if (searchContinuation) {
// additionalResultItems.value = [...additionalResultItems.value, ...searchContinuation.items];
// searchContinuationData.value = searchContinuation.continuation;
// }
// } catch (error) {
// messagesStore.createMessage({
// type: 'error',
// title: 'Unable to load more results',
// message: 'Try again or use a different search term for more results'
// });
// }
// } else {
// messagesStore.createMessage({
// type: 'error',
// title: 'Unable to load more results',
// message: 'Use a different search term for more results'
// });
// }
// moreVideosLoading.value = false;
// };
if (searchContinuation) {
additionalResultItems.value = [
...additionalResultItems.value,
...searchContinuation.results
];
searchContinuationData.value = searchContinuation.continuation;
}
} catch (error) {
messagesStore.createMessage({
type: 'error',
title: 'Unable to load more results',
message: 'Try again or use a different search term for more results'
});
}
} else {
messagesStore.createMessage({
type: 'error',
title: 'Unable to load more results',
message: 'Use a different search term for more results'
});
}
moreVideosLoading.value = false;
};
</script>

<template>
Expand Down Expand Up @@ -144,7 +153,7 @@ const getListEntryType = (type: string) => {
:lazy="true"
/>
</div>
<!-- <SeparatorSmall v-if="!pending && additionalResultItems.length > 0"
<SeparatorSmall v-if="!pending && additionalResultItems.length > 0"
>More results</SeparatorSmall
>
<div v-if="!pending && additionalResultItems.length > 0" class="search-videos-container">
Expand All @@ -161,12 +170,12 @@ const getListEntryType = (type: string) => {
:lazy="true"
/>
</div>
<div class="show-more-btn-container">
<div v-if="searchContinuationData" class="show-more-btn-container">
<BadgeButton :click="loadMoreVideos" :loading="moreVideosLoading">
<VTIcon name="mdi:reload" />
<p>Show more</p>
</BadgeButton>
</div> -->
</div>
</div>
</div>
</template>
Expand Down Expand Up @@ -273,7 +282,7 @@ const getListEntryType = (type: string) => {
.show-more-btn-container {
display: flex;
width: 100%;
padding: 0 0 20px 0;
padding: 20px 0 20px 0;

> a {
margin: 0 auto;
Expand Down
1 change: 1 addition & 0 deletions client/utils/googlevideoRegex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const googlevideoRegex = /https:\/\/.*?.googlevideo\.com/gi;
6 changes: 5 additions & 1 deletion client/utils/videoplayer/adapters/hlsAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,11 @@ export const hlsAdapter = async ({
});

playerInstance?.on(Hls.Events.ERROR, (event, data) => {
if (!['fragParsingError', 'bufferStalledError'].includes(data.details)) {
if (
!['fragParsingError', 'bufferStalledError', 'levelLoadError', 'fragLoadError'].includes(
data.details
)
) {
console.log('error', event, data);
videoState.playerError = {
message: data.details,
Expand Down
6 changes: 3 additions & 3 deletions client/utils/videoplayer/adapters/rxPlayerAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ export const rxPlayerAdapter = async ({
}: RxPlayerAdapterOptions) => {
// RxPlayer.addFeatures([DASH_WASM]);

const RxPlayer = await import('rx-player').then(module => module.default);
const { DASH_WASM } = await import('rx-player/features');
const RxPlayer = await import('rx-player/minimal').then(module => module.default);
const { DASH, DASH_WASM } = await import('rx-player/features');
const { EMBEDDED_DASH_WASM, EMBEDDED_WORKER } = await import(
'rx-player/experimental/features/embeds'
);

try {
RxPlayer.addFeatures([DASH]);
await DASH_WASM.initialize({ wasmUrl: EMBEDDED_DASH_WASM }).catch(() => {});
} catch {
// Ignore
Expand Down Expand Up @@ -257,7 +258,6 @@ export const rxPlayerAdapter = async ({
};

const mapAudioTracks = (audioTracks: IAvailableAudioTrack[]): AudioTrack[] => {
console.log(audioTracks);
return audioTracks
.filter(audioTrack => {
if (videoState.languageList.length <= 1) return true;
Expand Down
4 changes: 3 additions & 1 deletion server/src/common/innertube/innertube.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import path from 'path';
import { Innertube, InnertubeConfig, UniversalCache } from 'youtubei.js';
import { Innertube, InnertubeConfig, Log, UniversalCache } from 'youtubei.js';
import { innertubeFetch } from './innertubeFetch';

Log.setLevel(Log.Level.ERROR);

let cacheDirectory = './cache';
if (process.env.VIEWTUBE_DATA_DIRECTORY) {
cacheDirectory = path.join(process.env.VIEWTUBE_DATA_DIRECTORY, 'cache');
Expand Down
30 changes: 1 addition & 29 deletions server/src/core/channels/channels.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CacheInterceptor, CacheTTL } from '@nestjs/cache-manager';
import { Controller, Get, Header, Param, Query, Res, UseInterceptors } from '@nestjs/common';
import { ApiResponse, ApiTags } from '@nestjs/swagger';
import { ApiTags } from '@nestjs/swagger';
import { FastifyReply } from 'fastify';
import { ChannelsService } from './channels.service';
import { ChannelInfoErrorDto } from './dto/channel-info-error.dto';
Expand Down Expand Up @@ -38,8 +38,6 @@ export class ChannelsController {

@Header('Cache-Control', 'public, max-age=3600')
@Get(':id')
@ApiResponse({ status: 404 })
@ApiResponse({ status: 500 })
@UseInterceptors(CacheInterceptor)
@CacheTTL(3600000)
getChannelInfo(@Param('id') channelId: string): Promise<ChannelInfoDto> {
Expand All @@ -48,8 +46,6 @@ export class ChannelsController {

@Header('Cache-Control', 'public, max-age=3600')
@Get(':id/home')
@ApiResponse({ status: 404 })
@ApiResponse({ status: 500 })
@UseInterceptors(CacheInterceptor)
@CacheTTL(3600000)
getChannelHome(@Param('id') channelId: string): Promise<ChannelHomeDto> {
Expand All @@ -58,8 +54,6 @@ export class ChannelsController {

@Header('Cache-Control', 'public, max-age=3600')
@Get(':id/videos')
@ApiResponse({ status: 404 })
@ApiResponse({ status: 500 })
@UseInterceptors(CacheInterceptor)
@CacheTTL(3600000)
getChannelVideos(
Expand All @@ -71,8 +65,6 @@ export class ChannelsController {

@Header('Cache-Control', 'public, max-age=3600')
@Get('videos/continuation')
@ApiResponse({ status: 404 })
@ApiResponse({ status: 500 })
@UseInterceptors(CacheInterceptor)
@CacheTTL(3600000)
getChannelVideosContinuation(
Expand All @@ -85,8 +77,6 @@ export class ChannelsController {

@Header('Cache-Control', 'public, max-age=3600')
@Get(':id/shorts')
@ApiResponse({ status: 404 })
@ApiResponse({ status: 500 })
@UseInterceptors(CacheInterceptor)
@CacheTTL(3600000)
getChannelShorts(
Expand All @@ -98,8 +88,6 @@ export class ChannelsController {

@Header('Cache-Control', 'public, max-age=3600')
@Get(':id/livestreams')
@ApiResponse({ status: 404 })
@ApiResponse({ status: 500 })
@UseInterceptors(CacheInterceptor)
@CacheTTL(3600000)
getChannelLivestreams(
Expand All @@ -111,8 +99,6 @@ export class ChannelsController {

@Header('Cache-Control', 'public, max-age=3600')
@Get(':id/playlists')
@ApiResponse({ status: 404 })
@ApiResponse({ status: 500 })
@UseInterceptors(CacheInterceptor)
@CacheTTL(3600000)
getChannelPlaylists(@Param('id') channelId: string): Promise<ChannelPlaylistsDto> {
Expand All @@ -121,8 +107,6 @@ export class ChannelsController {

@Header('Cache-Control', 'public, max-age=3600')
@Get('playlists/continuation')
@ApiResponse({ status: 404 })
@ApiResponse({ status: 500 })
@UseInterceptors(CacheInterceptor)
@CacheTTL(3600000)
getChannelPlaylistsContinuation(
Expand All @@ -133,8 +117,6 @@ export class ChannelsController {

@Header('Cache-Control', 'public, max-age=3600')
@Get(':id/search')
@ApiResponse({ status: 404 })
@ApiResponse({ status: 500 })
@UseInterceptors(CacheInterceptor)
@CacheTTL(3600000)
searchChannel(
Expand All @@ -146,8 +128,6 @@ export class ChannelsController {

@Header('Cache-Control', 'public, max-age=3600')
@Get('search/continuation')
@ApiResponse({ status: 404 })
@ApiResponse({ status: 500 })
@UseInterceptors(CacheInterceptor)
@CacheTTL(3600000)
searchChannelContinuation(
Expand All @@ -158,8 +138,6 @@ export class ChannelsController {

@Header('Cache-Control', 'public, max-age=3600')
@Get('relatedchannels/continuation')
@ApiResponse({ status: 404 })
@ApiResponse({ status: 500 })
@UseInterceptors(CacheInterceptor)
@CacheTTL(3600000)
getRelatedChannelsContinuation(
Expand All @@ -170,8 +148,6 @@ export class ChannelsController {

@Header('Cache-Control', 'public, max-age=3600')
@Get(':id/communityposts')
@ApiResponse({ status: 404 })
@ApiResponse({ status: 500 })
@UseInterceptors(CacheInterceptor)
@CacheTTL(3600000)
getChannelCommunityPosts(@Param('id') channelId: string): Promise<ChannelCommunityPostsDto> {
Expand All @@ -180,8 +156,6 @@ export class ChannelsController {

@Header('Cache-Control', 'public, max-age=3600')
@Get('communityposts/continuation')
@ApiResponse({ status: 404 })
@ApiResponse({ status: 500 })
@UseInterceptors(CacheInterceptor)
@CacheTTL(3600000)
getChannelCommunityPostsContinuation(
Expand All @@ -193,8 +167,6 @@ export class ChannelsController {

@Header('Cache-Control', 'public, max-age=3600')
@Get(':id/stats')
@ApiResponse({ status: 404 })
@ApiResponse({ status: 500 })
@UseInterceptors(CacheInterceptor)
@CacheTTL(3600000)
getChannelStats(@Param('id') channelId: string): Promise<ChannelStatsDto> {
Expand Down
Loading

0 comments on commit 1708c03

Please sign in to comment.