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
22 changes: 22 additions & 0 deletions controllers/appController.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,28 @@ describe('controllers/appController', () => {
}));
});

test('getHome handles upstream failures without crashing', async () => {
(http.get as jest.Mock)
.mockRejectedValueOnce(new Error('403'))
.mockResolvedValueOnce({ data: { result: [{ imdb_id: '2' }] } });
(fetchAndUpdatePosters as jest.Mock).mockResolvedValue(undefined);
(getLatest as jest.Mock).mockReturnValue(undefined);

const req: any = { query: {}, user: {} };
const res: any = {
locals: { APP_URL: 'http://app', CARD_TYPE: 'card' },
render: jest.fn(),
};

await appController.getHome(req, res, jest.fn());

expect(setLatest).not.toHaveBeenCalled();
expect(res.render).toHaveBeenCalledWith('index', expect.objectContaining({
newMovies: [],
newSeries: [{ imdb_id: '2' }],
}));
});

test('getHome returns cached results when available', async () => {
(getLatest as jest.Mock).mockReturnValue({
movies: [{ imdb_id: 'm1' }],
Expand Down
33 changes: 26 additions & 7 deletions controllers/appController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,20 +82,35 @@ const appController = {
});
}

const [axiosMovieResponse, axiosSeriesResponse] = await Promise.all([
const [movieResult, seriesResult] = await Promise.allSettled([
http.get(`https://${appConfig.VIDSRC_DOMAIN}/movies/latest/page-1.json`),
http.get(`https://${appConfig.VIDSRC_DOMAIN}/tvshows/latest/page-1.json`),
]);

let newMovies = axiosMovieResponse.data.result || [];
let newSeries = axiosSeriesResponse.data.result || [];
let newMovies =
movieResult.status === 'fulfilled' ? movieResult.value.data.result || [] : [];
let newSeries =
seriesResult.status === 'fulfilled' ? seriesResult.value.data.result || [] : [];

if (movieResult.status === 'rejected') {
console.warn('Failed to fetch latest movies; continuing with empty dataset');
}

if (seriesResult.status === 'rejected') {
console.warn('Failed to fetch latest series; continuing with empty dataset');
}

await Promise.all([
fetchAndUpdatePosters(newMovies),
fetchAndUpdatePosters(newSeries),
]);

setLatest({ movies: newMovies, series: newSeries });
const hasFeedFailure =
movieResult.status === 'rejected' || seriesResult.status === 'rejected';

if (!hasFeedFailure) {
setLatest({ movies: newMovies, series: newSeries });
}

res.render('index', {
newMovies,
Expand Down Expand Up @@ -132,7 +147,7 @@ const appController = {
*/
getView: asyncHandler(async (req: AuthRequest, res: Response) => {
const query = req.params.q || '';
const id = req.params.id;
const id = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const type = req.params.type as 'movie' | 'series';

const cookieHeader =
Expand All @@ -143,8 +158,12 @@ const appController = {
const preferredServer = match ? (match[1] as '1' | '2') : undefined;

if (type === 'series') {
let season = req.params.season;
let episode = req.params.episode;
let season = Array.isArray(req.params.season)
? req.params.season[0]
: req.params.season;
let episode = Array.isArray(req.params.episode)
? req.params.episode[0]
: req.params.episode;

if ((!season || !episode) && req.user) {
const redirectTo = await getResumeRedirect(req.user.id, id);
Expand Down
Loading