···211211 }
212212213213 // If we have a last successful source and the feature is enabled, prioritize it
214214- if (enableLastSuccessfulSource && lastSuccessfulSource) {
214214+ // BUT only if we're not resuming from a specific source (to preserve custom order)
215215+ if (
216216+ enableLastSuccessfulSource &&
217217+ lastSuccessfulSource &&
218218+ !startFromSourceId
219219+ ) {
215220 const lastSourceIndex = baseSourceOrder.indexOf(lastSuccessfulSource);
216221 if (lastSourceIndex !== -1) {
217222 baseSourceOrder = [
···222227 }
223228224229 // If starting from a specific source ID, filter the order to start AFTER that source
230230+ // This preserves the custom order while starting from the next source
225231 let filteredSourceOrder = baseSourceOrder;
226232 if (startFromSourceId) {
227233 const startIndex = filteredSourceOrder.indexOf(startFromSourceId);
+32-3
src/pages/PlayerView.tsx
···4747 const [resumeFromSourceId, setResumeFromSourceId] = useState<string | null>(
4848 null,
4949 );
5050+ const storeResumeFromSourceId = usePlayerStore((s) => s.resumeFromSourceId);
5151+ const setResumeFromSourceIdInStore = usePlayerStore(
5252+ (s) => s.setResumeFromSourceId,
5353+ );
5054 const [startAtParam] = useQueryParam("t");
5155 const {
5256 status,
···7680 setLastSuccessfulSource(null);
7781 };
7882 }, [setLastSuccessfulSource]);
8383+8484+ // Reset resume from source ID when leaving the player
8585+ useEffect(() => {
8686+ return () => {
8787+ setResumeFromSourceId(null);
8888+ setResumeFromSourceIdInStore(null);
8989+ };
9090+ }, [setResumeFromSourceIdInStore]);
79918092 const paramsData = JSON.stringify({
8193 media: params.media,
···169181 (startFromSourceId: string) => {
170182 // Set resume source first
171183 setResumeFromSourceId(startFromSourceId);
184184+ setResumeFromSourceIdInStore(startFromSourceId);
172185 // Then change status in next tick to ensure re-render
173186 setTimeout(() => {
174187 setStatus(playerStatus.SCRAPING);
175188 }, 0);
176189 },
177177- [setStatus],
190190+ [setStatus, setResumeFromSourceIdInStore],
178191 );
179192193193+ // Sync store value to local state when it changes (e.g., from settings)
194194+ // or when status changes to SCRAPING
195195+ useEffect(() => {
196196+ if (storeResumeFromSourceId && status === playerStatus.SCRAPING) {
197197+ if (
198198+ !resumeFromSourceId ||
199199+ resumeFromSourceId !== storeResumeFromSourceId
200200+ ) {
201201+ setResumeFromSourceId(storeResumeFromSourceId);
202202+ }
203203+ }
204204+ }, [storeResumeFromSourceId, resumeFromSourceId, status]);
205205+180206 const playAfterScrape = useCallback(
181207 (out: RunOutput | null) => {
182208 if (!out) return;
···223249 <SourceSelectPart media={scrapeMedia} />
224250 ) : (
225251 <ScrapingPart
226226- key={`scraping-${resumeFromSourceId || "default"}`}
252252+ key={`scraping-${resumeFromSourceId || storeResumeFromSourceId || "default"}`}
227253 media={scrapeMedia}
228228- startFromSourceId={resumeFromSourceId || undefined}
254254+ startFromSourceId={
255255+ resumeFromSourceId || storeResumeFromSourceId || undefined
256256+ }
229257 onResult={(sources, sourceOrder) => {
230258 setErrorData({
231259 sourceOrder,
···234262 setScrapeNotFound();
235263 // Clear resume state after scraping
236264 setResumeFromSourceId(null);
265265+ setResumeFromSourceIdInStore(null);
237266 }}
238267 onGetStream={playAfterScrape}
239268 />