414 lines
12 KiB
TypeScript
414 lines
12 KiB
TypeScript
|
|
import { postgrestLocalUrl, postgrestUrl, siteUrl, strapiUrl } from './constants';
|
|
import { getSafeDate } from './dates';
|
|
import qs from 'qs';
|
|
import { IStream } from '@futureporn/types';
|
|
|
|
|
|
|
|
const fetchStreamsOptions = {
|
|
next: {
|
|
tags: ['streams'],
|
|
revalidation: 1
|
|
}
|
|
}
|
|
|
|
|
|
export async function getStreamByUUID(uuid: string): Promise<IStream> {
|
|
// const query = qs.stringify({
|
|
// filters: {
|
|
// cuid: {
|
|
// $eq: cuid
|
|
// }
|
|
// },
|
|
// pagination: {
|
|
// limit: 1
|
|
// },
|
|
// populate: {
|
|
// vtuber: {
|
|
// fields: ['slug', 'displayName']
|
|
// },
|
|
// tweet: {
|
|
// fields: ['isChaturbateInvite', 'isFanslyInvite', 'url']
|
|
// },
|
|
// vods: {
|
|
// fields: ['note', 'cuid', 'publishedAt'],
|
|
// populate: {
|
|
// tagVodRelations: {
|
|
// fields: ['id']
|
|
// },
|
|
// timestamps: '*'
|
|
// }
|
|
// }
|
|
// }
|
|
// });
|
|
const query = `select=*,vods(*),vtuber:vtubers(slug,display_name,id,image,image_blur)&uuid=eq.${uuid}&limit=1`
|
|
const res = await fetch(`${postgrestUrl}/streams?${query}`);
|
|
const json = await res.json();
|
|
console.log(json)
|
|
return json[0];
|
|
}
|
|
|
|
export function getUrl(stream: IStream, slug: string, date: string): string {
|
|
return `${siteUrl}/vt/${slug}/stream/${getSafeDate(date)}`
|
|
}
|
|
|
|
|
|
export function getPaginatedUrl(): (slug: string, pageNumber: number) => string {
|
|
return (slug: string, pageNumber: number) => {
|
|
return `${siteUrl}/vt/${slug}/streams/${pageNumber}`
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export function getLocalizedDate(stream: IStream): string {
|
|
return new Date(stream.date).toLocaleDateString()
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function getStreamsForYear(year: number): Promise<IStream[]> {
|
|
const startOfYear = new Date(year, 0, 0);
|
|
const endOfYear = new Date(year, 11, 31);
|
|
|
|
const pageSize = 100; // Number of records per page
|
|
let currentPage = 0;
|
|
let allStreams: IStream[] = [];
|
|
|
|
while (true) {
|
|
const query = qs.stringify({
|
|
filters: {
|
|
date: {
|
|
$gte: startOfYear,
|
|
$lte: endOfYear,
|
|
},
|
|
},
|
|
populate: {
|
|
vtuber: {
|
|
fields: ['displayName']
|
|
}
|
|
},
|
|
pagination: {
|
|
page: currentPage,
|
|
pageSize: pageSize,
|
|
}
|
|
});
|
|
|
|
const res = await fetch(`${postgrestUrl}/streams?${query}`, fetchStreamsOptions);
|
|
|
|
if (!res.ok) {
|
|
// Handle error if needed
|
|
console.error('here is the res.body')
|
|
|
|
console.error((await res.text()));
|
|
throw new Error(`Error fetching streams: ${res.status}`);
|
|
}
|
|
|
|
const json = await res.json();
|
|
const streams = json as IStream[];
|
|
|
|
if (streams.length === 0) {
|
|
// No more records, break the loop
|
|
break;
|
|
}
|
|
|
|
allStreams = [...allStreams, ...streams];
|
|
currentPage += pageSize;
|
|
}
|
|
|
|
return allStreams;
|
|
}
|
|
|
|
export async function getStream(id: number): Promise<IStream> {
|
|
const query = qs.stringify({
|
|
filters: {
|
|
id: {
|
|
$eq: id
|
|
}
|
|
}
|
|
});
|
|
const res = await fetch(`${postgrestUrl}/vods?${query}`, fetchStreamsOptions);
|
|
const json = await res.json();
|
|
return json.data;
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function getAllStreams(archiveStatuses = ['missing', 'issue', 'good']): Promise<IStream[]> {
|
|
throw new Error('getAllStreams function is not performant. please use something more efficient.')
|
|
const pageSize = 100; // Adjust this value as needed
|
|
const sortDesc = true; // Adjust the sorting direction as needed
|
|
|
|
const allStreams: IStream[] = [];
|
|
let currentPage = 1;
|
|
|
|
while (true) {
|
|
const query = qs.stringify({
|
|
populate: {
|
|
vtuber: {
|
|
fields: ['slug', 'displayName', 'image', 'imageBlur', 'themeColor'],
|
|
},
|
|
muxAsset: {
|
|
fields: ['playbackId', 'assetId'],
|
|
},
|
|
thumbnail: {
|
|
fields: ['cdnUrl', 'url'],
|
|
},
|
|
tagstreamRelations: {
|
|
fields: ['tag'],
|
|
populate: ['tag'],
|
|
},
|
|
videoSrcB2: {
|
|
fields: ['url', 'key', 'uploadId', 'cdnUrl'],
|
|
},
|
|
tweet: {
|
|
fields: ['isChaturbateInvite', 'isFanslyInvite']
|
|
}
|
|
},
|
|
filters: {
|
|
archiveStatus: {
|
|
'$in': archiveStatuses
|
|
}
|
|
},
|
|
sort: {
|
|
date: sortDesc ? 'desc' : 'asc',
|
|
},
|
|
pagination: {
|
|
pageSize,
|
|
page: currentPage,
|
|
},
|
|
});
|
|
const response = await fetch(`${postgrestUrl}/streams?${query}`, fetchStreamsOptions);
|
|
const responseData = await response.json();
|
|
|
|
if (!responseData.data || responseData.data.length === 0) {
|
|
// No more data to fetch
|
|
break;
|
|
}
|
|
|
|
allStreams.push(...responseData.data);
|
|
currentPage++;
|
|
}
|
|
|
|
return allStreams;
|
|
}
|
|
|
|
export async function getStreamForVtuber(vtuberId: number, safeDate: string): Promise<IStream> {
|
|
const query = qs.stringify({
|
|
populate: {
|
|
vods: {
|
|
fields: [
|
|
'id',
|
|
'date'
|
|
]
|
|
},
|
|
tweet: {
|
|
fields: [
|
|
'id'
|
|
]
|
|
}
|
|
}
|
|
});
|
|
|
|
const response = await fetch(`${postgrestUrl}/streams?${query}`, fetchStreamsOptions);
|
|
|
|
if (response.status !== 200) throw new Error('network fetch error while attempting to getStreamForVtuber');
|
|
|
|
const responseData = await response.json();
|
|
return responseData;
|
|
}
|
|
|
|
export async function getAllStreamsForVtuber(vtuberId: number, archiveStatuses = ['missing', 'issue', 'good']): Promise<IStream[]> {
|
|
const maxRetries = 3;
|
|
|
|
let retries = 0;
|
|
let allStreams: IStream[] = [];
|
|
let currentPage = 1;
|
|
|
|
while (retries < maxRetries) {
|
|
try {
|
|
const query = qs.stringify({
|
|
populate: '*',
|
|
filters: {
|
|
archiveStatus: {
|
|
'$in': archiveStatuses
|
|
},
|
|
vtuber: {
|
|
id: {
|
|
$eq: vtuberId
|
|
}
|
|
}
|
|
},
|
|
sort: {
|
|
date: 'desc',
|
|
},
|
|
pagination: {
|
|
pageSize: 100,
|
|
page: currentPage,
|
|
},
|
|
});
|
|
|
|
// console.log(`strapiUrl=${strapiUrl}`)
|
|
const response = await fetch(`${postgrestUrl}/streams?${query}`, fetchStreamsOptions)
|
|
|
|
if (response.status !== 200) {
|
|
// If the response status is not 200 (OK), consider it a network failure
|
|
const bod = await response.text();
|
|
console.log(response.status);
|
|
console.log(bod);
|
|
retries++;
|
|
continue;
|
|
}
|
|
|
|
const responseData = await response.json();
|
|
|
|
if (!responseData.data || responseData.data.length === 0) {
|
|
// No more data to fetch
|
|
break;
|
|
}
|
|
|
|
allStreams.push(...responseData.data);
|
|
currentPage++;
|
|
} catch (error) {
|
|
// Network failure or other error occurred
|
|
retries++;
|
|
}
|
|
}
|
|
|
|
if (retries === maxRetries) {
|
|
throw new Error(`Failed to fetch streams after ${maxRetries} retries.`);
|
|
}
|
|
|
|
return allStreams;
|
|
}
|
|
|
|
/**
|
|
* Used as table data on /archive page.
|
|
* .pageIndex, pagination.pageSize
|
|
*/
|
|
|
|
export async function fetchStreamData({ pageIndex, pageSize }: { pageIndex: number, pageSize: number }) {
|
|
// console.log(`fetchStreamData() invoked`)
|
|
const offset = pageIndex * pageSize;
|
|
// const query = qs.stringify({
|
|
// populate: {
|
|
// vtuber: {
|
|
// fields: ['slug', 'displayName', 'publishedAt', 'image', 'imageBlur']
|
|
// }
|
|
// },
|
|
// filters: {
|
|
// vtuber: {
|
|
// publishedAt: {
|
|
// $notNull: true
|
|
// }
|
|
// }
|
|
// },
|
|
// pagination: {
|
|
// start: offset,
|
|
// limit: pageSize,
|
|
// withCount: true
|
|
// },
|
|
// sort: ['date:desc']
|
|
// })
|
|
const query = 'select=*,vtuber:vtubers(id,slug,image,image_blur,theme_color,display_name)'
|
|
const response = await fetch(
|
|
`${postgrestUrl}/streams?${query}`
|
|
);
|
|
const data = await response.json();
|
|
// console.log(data)
|
|
const filtered = data.filter((datum: any) => !!datum?.vtuber)
|
|
const d = {
|
|
rows: filtered,
|
|
pageCount: Math.ceil(filtered.length / pageSize),
|
|
rowCount: filtered,
|
|
}
|
|
// console.log(`fetchStreamData with pageIndex=${pageIndex}, pageSize=${pageSize}\n\n${JSON.stringify(d, null, 2)}`)
|
|
return d;
|
|
}
|
|
|
|
export async function getStreamCountForVtuber(vtuberId: number, archiveStatuses = ['missing', 'issue', 'good']): Promise<number> {
|
|
if (!vtuberId) throw new Error(`getStreamCountForVtuber requires a vtuberId, but it was undefined.`);
|
|
const res = await fetch(
|
|
`${postgrestLocalUrl}/streams?vtuber_id=eq.${vtuberId}&archive_status=in.(${archiveStatuses.join(',')})&limit=1`,
|
|
Object.assign(fetchStreamsOptions, {
|
|
headers: {
|
|
'Prefer': 'count=exact'
|
|
}
|
|
})
|
|
)
|
|
const total = res.headers.get('Content-Range')?.split('/').at(-1)
|
|
const data = await res.json()
|
|
// console.log(`getStreamCountForVtuber with vtuberId=${vtuberId}, archiveStatuses=${archiveStatuses}, Content-Range=${res.headers.get('Content-Range')}`)
|
|
// console.log(JSON.stringify(data, null, 2))
|
|
if (!total) {
|
|
console.error(`Failed to getStreamCountForVtuber-- total was falsy.`)
|
|
return 1;
|
|
}
|
|
else return parseInt(total)+1;
|
|
}
|
|
|
|
export async function getStreamsForVtuber(vtuberId: number, page: number = 1, pageSize: number = 25, sortDesc = true): Promise<IStream[]> {
|
|
// console.log(`getStreamsForVtuber() with strapiUrl=${strapiUrl}`)
|
|
const query = qs.stringify(
|
|
{
|
|
populate: {
|
|
vtuber: {
|
|
fields: [
|
|
'id',
|
|
]
|
|
}
|
|
},
|
|
filters: {
|
|
vtuber: {
|
|
id: {
|
|
$eq: vtuberId
|
|
}
|
|
}
|
|
},
|
|
pagination: {
|
|
page: page,
|
|
pageSize: pageSize
|
|
},
|
|
sort: {
|
|
date: (sortDesc) ? 'desc' : 'asc'
|
|
}
|
|
}
|
|
)
|
|
const res = await fetch(`${postgrestUrl}/streams?${query}`, fetchStreamsOptions)
|
|
const data = await res.json()
|
|
// console.log(data)
|
|
return data
|
|
}
|
|
|
|
|
|
// /**
|
|
// * This returns stale data, because futureporn-historian is broken.
|
|
// * @todo get live data from historian
|
|
// * @see https://gitea.futureporn.net/futureporn/futureporn-historian/issues/1
|
|
// */
|
|
// export async function getProgress(vtuberSlug: string): Promise<{ complete: number; total: number }> {
|
|
// const query = qs.stringify({
|
|
// filters: {
|
|
// vtuber: {
|
|
// slug: {
|
|
// $eq: vtuberSlug
|
|
// }
|
|
// }
|
|
// }
|
|
// })
|
|
// const data = await fetch(`${postgrestUrl}/streams?${query}`, fetchStreamsOptions)
|
|
// .then((res) => res.json())
|
|
// .then((g) => {
|
|
// return g
|
|
// })
|
|
|
|
// const total = data.meta.pagination.total
|
|
|
|
// return {
|
|
// complete: total,
|
|
// total: total
|
|
// }
|
|
// }
|