mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-15 21:56:18 -08:00
fix(downloads): accept nullable legacy coordinates
This commit is contained in:
1 parent
339dbde3c4
commit
a667bfbe05
5 files changed
+61
-12
No files matched your search
@@ -955,9 +955,11 @@ engine` (restart required) or
|
||||
fallback that migrates reusable rows to the canonical id. Renderer lookup
|
||||
preserves ambiguity or conflicting ownership as a distinct ineligible state,
|
||||
so neither the episode action nor the season count treats it as a row-less
|
||||
download. Pending and active rows plus completed available/unknown rows are
|
||||
skipped; failed, canceled, completed-missing, and unambiguous row-less
|
||||
episodes remain eligible.
|
||||
download. SQLite `null` and optional `undefined` coordinates both mean an
|
||||
incomplete canonical legacy row, matching the backend resolver. Pending and
|
||||
active rows plus completed available/unknown rows are skipped; failed,
|
||||
canceled, completed-missing, and unambiguous row-less episodes remain
|
||||
eligible.
|
||||
- Ready movie and grouped-series cards open a focused local detail. Movies play
|
||||
the finalized local file; series list only locally available episode rows and
|
||||
every episode action targets its own downloaded file. Focused routes disable
|
||||
|
||||
@@ -82,12 +82,14 @@ variants, contextual buttons, and theme-aware styling.
|
||||
coordinates are a legacy episode-compatibility fallback; ambiguous or
|
||||
conflicting matches resolve to an explicit renderer conflict state rather
|
||||
than masquerading as a missing row. Both the episode action and season count
|
||||
fail closed for that state, while restarting an eligible legacy row migrates
|
||||
it to the canonical id. Renderer-pending, queued, downloading, and paused
|
||||
episodes are skipped, as are completed rows whose file is available or whose
|
||||
availability is still unknown. Failed, canceled, completed-missing, and
|
||||
unambiguous row-less episodes are eligible; a completed-missing row is
|
||||
restarted as a fresh download. `DOWNLOADS_START` remains the only start IPC
|
||||
fail closed for that state. SQLite `null` and optional `undefined` coordinates
|
||||
both mean that a canonical legacy row is incomplete, matching the backend
|
||||
resolver, while restarting an eligible legacy row migrates it to the
|
||||
canonical id. Renderer-pending, queued, downloading, and paused episodes are
|
||||
skipped, as are completed rows whose file is available or whose availability
|
||||
is still unknown. Failed, canceled, completed-missing, and unambiguous
|
||||
row-less episodes are eligible; a completed-missing row is restarted as a
|
||||
fresh download. `DOWNLOADS_START` remains the only start IPC
|
||||
and may return the stable `reason: 'already-in-progress'` for an active match,
|
||||
which the coordinator counts as skipped. There is no batch IPC, schema
|
||||
migration, parallel transfer, or queue reordering: destination authorization,
|
||||
|
||||
@@ -42,6 +42,22 @@ describe('episode download identity', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
['series id', { seriesXtreamId: null }],
|
||||
['season number', { seasonNumber: null }],
|
||||
['episode number', { episodeNumber: null }],
|
||||
])(
|
||||
'treats a null legacy %s as an incomplete canonical row',
|
||||
(_label, override) => {
|
||||
const canonical = row(override);
|
||||
|
||||
expect(resolveEpisodeDownload(identity, [canonical])).toEqual({
|
||||
kind: 'match',
|
||||
download: canonical,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
it('fails closed when canonical and coordinate lookups find different rows', () => {
|
||||
const coordinateFallback = row({ xtreamId: 999 });
|
||||
const canonical = row();
|
||||
|
||||
@@ -18,9 +18,9 @@ export interface EpisodeDownloadRecord {
|
||||
readonly playlistId: string;
|
||||
readonly contentType: ElectronBridgePlaybackContentType;
|
||||
readonly xtreamId: number;
|
||||
readonly seriesXtreamId?: number;
|
||||
readonly seasonNumber?: number;
|
||||
readonly episodeNumber?: number;
|
||||
readonly seriesXtreamId?: number | null;
|
||||
readonly seasonNumber?: number | null;
|
||||
readonly episodeNumber?: number | null;
|
||||
readonly status: ElectronBridgeDownloadStatus;
|
||||
readonly fileAvailability?: ElectronDownloadFileAvailability;
|
||||
readonly filePath?: string;
|
||||
@@ -37,8 +37,11 @@ function hasConflictingCompleteCoordinates(
|
||||
): boolean {
|
||||
const { seriesXtreamId, seasonNumber, episodeNumber } = download;
|
||||
if (
|
||||
seriesXtreamId === null ||
|
||||
seriesXtreamId === undefined ||
|
||||
seasonNumber === null ||
|
||||
seasonNumber === undefined ||
|
||||
episodeNumber === null ||
|
||||
episodeNumber === undefined
|
||||
) {
|
||||
return false;
|
||||
|
||||
@@ -638,6 +638,32 @@ describe('SeasonContainerComponent', () => {
|
||||
expect(downloadsServiceStub.startDownload).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('keeps a failed canonical legacy row with null coordinates downloadable', () => {
|
||||
const episode = createEpisode();
|
||||
const legacy = {
|
||||
...createDownload(episode, { status: 'failed' }),
|
||||
seriesXtreamId: null,
|
||||
seasonNumber: null,
|
||||
episodeNumber: null,
|
||||
} as unknown as DownloadItem;
|
||||
downloadsServiceStub.downloads.set([legacy]);
|
||||
enableDownloads();
|
||||
setRequiredInputs({ '1': [episode] });
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const action = episodeAction(episode.id);
|
||||
const seasonButton = fixture.nativeElement.querySelector(
|
||||
'[data-test-id="download-season"]'
|
||||
) as HTMLButtonElement;
|
||||
expect(action.disabled).toBe(false);
|
||||
expect(action.querySelector('mat-icon')?.textContent).toContain(
|
||||
'download'
|
||||
);
|
||||
expect(seasonButton.disabled).toBe(false);
|
||||
expect(seasonButton.textContent).toContain('Download season (1)');
|
||||
});
|
||||
|
||||
it('gives the grid and list view radios localized accessible names', () => {
|
||||
TestBed.inject(TranslateService).setTranslation(
|
||||
'en',
|
||||
|
||||
Reference in new issue
Block a user