Split software arch desc for easier manintenance. Many fixes related to next video playing and remote playback
This commit is contained in:
@@ -4,27 +4,27 @@
|
||||
* Handles user interactions with the next episode popup.
|
||||
* Backend manages countdown logic and autoplay decisions.
|
||||
*
|
||||
* Navigation uses goto() directly to load the next episode.
|
||||
* The player page's $effect detects the URL param change and
|
||||
* calls loadAndPlay for the new episode.
|
||||
*
|
||||
* TRACES: UR-023 | DR-047, DR-048
|
||||
*/
|
||||
|
||||
import { cancelAutoplayCountdown, playNextEpisode } from "$lib/api/autoplay";
|
||||
import { goto } from "$app/navigation";
|
||||
import { cancelAutoplayCountdown } from "$lib/api/autoplay";
|
||||
import { nextEpisode } from "$lib/stores/nextEpisode";
|
||||
import type { MediaItem } from "$lib/api/types";
|
||||
|
||||
/** Guard against double-navigation */
|
||||
let isNavigating = false;
|
||||
|
||||
/**
|
||||
* Cleanup next episode state (called on unmount/destroy)
|
||||
*/
|
||||
export function cleanup() {
|
||||
nextEpisode.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle episode ended event
|
||||
* Backend now handles autoplay decisions via on_playback_ended()
|
||||
* This function is kept for backwards compatibility but does nothing
|
||||
*/
|
||||
export async function handleEpisodeEnded(media: any) {
|
||||
// Backend now handles this - no action needed
|
||||
// The backend will emit ShowNextEpisodePopup event
|
||||
isNavigating = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,13 +36,36 @@ export async function cancelAutoPlay() {
|
||||
nextEpisode.hidePopup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to the next episode via goto().
|
||||
* Uses replaceState to prevent history buildup when auto-advancing.
|
||||
*/
|
||||
function navigateToEpisode(episode: MediaItem) {
|
||||
if (isNavigating) {
|
||||
console.warn("[NextEpisode] Already navigating, skipping duplicate navigation to", episode.id);
|
||||
return;
|
||||
}
|
||||
isNavigating = true;
|
||||
console.log("[NextEpisode] Navigating to next episode:", episode.id, episode.name);
|
||||
nextEpisode.hidePopup();
|
||||
goto(`/player/${episode.id}`, { replaceState: true }).finally(() => {
|
||||
isNavigating = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually play the next episode
|
||||
* Called when user clicks "Play Now" button on next episode popup
|
||||
*
|
||||
* @param nextEpisodeItem - The next episode to play
|
||||
*/
|
||||
export async function watchNextManually(nextEpisodeItem: any) {
|
||||
await playNextEpisode(nextEpisodeItem);
|
||||
nextEpisode.hidePopup();
|
||||
export async function watchNextManually(nextEpisodeItem: MediaItem) {
|
||||
await cancelAutoplayCountdown();
|
||||
navigateToEpisode(nextEpisodeItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-play the next episode when countdown reaches 0
|
||||
* Called by playerEvents when countdown_tick event has remaining_seconds: 0
|
||||
*/
|
||||
export function autoPlayNext(nextEpisodeItem: MediaItem) {
|
||||
navigateToEpisode(nextEpisodeItem);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ import { player, playbackPosition } from "$lib/stores/player";
|
||||
import { queue, currentQueueItem } from "$lib/stores/queue";
|
||||
import { playbackMode } from "$lib/stores/playbackMode";
|
||||
import { sleepTimer } from "$lib/stores/sleepTimer";
|
||||
import { nextEpisode } from "$lib/stores/nextEpisode";
|
||||
import { nextEpisode, nextEpisodeItem as nextEpisodeItemStore } from "$lib/stores/nextEpisode";
|
||||
import { autoPlayNext } from "$lib/services/nextEpisodeService";
|
||||
import { preloadUpcomingTracks } from "$lib/services/preload";
|
||||
import type { MediaItem } from "$lib/api/types";
|
||||
import { get } from "svelte/store";
|
||||
@@ -320,8 +321,17 @@ function handleShowNextEpisodePopup(
|
||||
|
||||
/**
|
||||
* Handle countdown tick event.
|
||||
* When countdown reaches 0, automatically trigger playback of the next episode.
|
||||
*/
|
||||
function handleCountdownTick(remainingSeconds: number): void {
|
||||
// Update next episode store with new countdown value
|
||||
nextEpisode.updateCountdown(remainingSeconds);
|
||||
|
||||
// Auto-play when countdown reaches 0
|
||||
if (remainingSeconds === 0) {
|
||||
const episode = get(nextEpisodeItemStore);
|
||||
if (episode) {
|
||||
autoPlayNext(episode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,13 @@ export type SyncOperation =
|
||||
| "unmark_favorite"
|
||||
| "update_progress"
|
||||
| "report_playback_start"
|
||||
| "report_playback_stopped";
|
||||
| "report_playback_stopped"
|
||||
| "playlist_create"
|
||||
| "playlist_delete"
|
||||
| "playlist_rename"
|
||||
| "playlist_add_items"
|
||||
| "playlist_remove_items"
|
||||
| "playlist_reorder_item";
|
||||
|
||||
/**
|
||||
* Simplified sync service - handles offline mutation queueing
|
||||
@@ -164,6 +170,32 @@ class SyncService {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
// ===== Playlist sync operations =====
|
||||
|
||||
async queuePlaylistCreate(playlistId: string, name: string, itemIds: string[]): Promise<number> {
|
||||
return this.queueMutation("playlist_create", playlistId, { name, itemIds });
|
||||
}
|
||||
|
||||
async queuePlaylistDelete(playlistId: string): Promise<number> {
|
||||
return this.queueMutation("playlist_delete", playlistId);
|
||||
}
|
||||
|
||||
async queuePlaylistRename(playlistId: string, name: string): Promise<number> {
|
||||
return this.queueMutation("playlist_rename", playlistId, { name });
|
||||
}
|
||||
|
||||
async queuePlaylistAddItems(playlistId: string, itemIds: string[]): Promise<number> {
|
||||
return this.queueMutation("playlist_add_items", playlistId, { itemIds });
|
||||
}
|
||||
|
||||
async queuePlaylistRemoveItems(playlistId: string, entryIds: string[]): Promise<number> {
|
||||
return this.queueMutation("playlist_remove_items", playlistId, { entryIds });
|
||||
}
|
||||
|
||||
async queuePlaylistReorderItem(playlistId: string, itemId: string, newIndex: number): Promise<number> {
|
||||
return this.queueMutation("playlist_reorder_item", playlistId, { itemId, newIndex });
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all sync operations for the current user (called during logout)
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user