Skip to content

Commit 89e517f

Browse files
committed
fixes
1 parent d848c10 commit 89e517f

10 files changed

Lines changed: 387 additions & 189 deletions

File tree

src/background/media-manager.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,13 @@ class MediaManager {
682682
mediaId,
683683
frameId
684684
});
685+
} else if (action === AUTOSTOP.ACTION.PREV) {
686+
await browser.tabs.sendMessage(tabId, {
687+
type: AUTOSTOP.MSG.CONTROL,
688+
action: AUTOSTOP.ACTION.PREV,
689+
mediaId,
690+
frameId
691+
});
685692
}
686693
} catch (e) {
687694
Logger.error('Failed to control media:', e.message);

src/content/adapters/base-adapter.js

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,11 @@ class BaseAdapter {
122122
}
123123

124124
/**
125-
* Check if page has skip/next button
125+
* Check if skip is available (always true - we can seek to end)
126126
* @returns {boolean}
127127
*/
128128
hasSkipButton() {
129-
return false;
129+
return true;
130130
}
131131

132132
/**
@@ -271,11 +271,53 @@ class BaseAdapter {
271271
}
272272

273273
/**
274-
* Handle skip action
274+
* Handle skip action - seeks to end of media
275275
* @param {string} mediaId
276276
*/
277277
skip(mediaId) {
278-
// Override in subclass
278+
const stored = this.mediaElements.get(mediaId);
279+
let element = stored?.element;
280+
281+
// Fallback: find any playing media
282+
if (!element) {
283+
const allMedia = document.querySelectorAll('video, audio');
284+
for (const media of allMedia) {
285+
if (!media.paused && media.duration > 0) {
286+
element = media;
287+
break;
288+
}
289+
}
290+
}
291+
292+
if (element && isFinite(element.duration) && element.duration > 0) {
293+
Logger.debug('Skip: seeking to end', element.duration);
294+
element.currentTime = element.duration;
295+
}
296+
}
297+
298+
/**
299+
* Handle previous action - seeks to start of media
300+
* @param {string} mediaId
301+
*/
302+
prev(mediaId) {
303+
const stored = this.mediaElements.get(mediaId);
304+
let element = stored?.element;
305+
306+
// Fallback: find any playing media
307+
if (!element) {
308+
const allMedia = document.querySelectorAll('video, audio');
309+
for (const media of allMedia) {
310+
if (!media.paused && media.duration > 0) {
311+
element = media;
312+
break;
313+
}
314+
}
315+
}
316+
317+
if (element) {
318+
Logger.debug('Prev: seeking to start');
319+
element.currentTime = 0;
320+
}
279321
}
280322

281323
/**

src/content/adapters/generic-adapter.js

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -237,47 +237,33 @@ class GenericAdapter extends BaseAdapter {
237237
}
238238

239239
hasSkipButton() {
240-
const selectors = [
241-
'[class*="next"]',
242-
'[class*="skip"]',
243-
'[aria-label*="next" i]',
244-
'[aria-label*="skip" i]'
245-
];
246-
247-
for (const selector of selectors) {
248-
try {
249-
const btn = document.querySelector(selector);
250-
if (btn && !btn.disabled) return true;
251-
} catch (e) {}
252-
}
253-
254-
return false;
240+
// Skip is always available - we seek to end
241+
return true;
255242
}
256243

257244
skip(mediaId) {
245+
// Find the media element
246+
let element = null;
258247
const stored = this.mediaElements.get(mediaId);
259248

260-
// Try to find and click skip button
261-
const selectors = [
262-
'.next-button',
263-
'.skip-button',
264-
'[aria-label="Next"]',
265-
'[aria-label="Skip"]'
266-
];
267-
268-
for (const selector of selectors) {
269-
try {
270-
const btn = document.querySelector(selector);
271-
if (btn && !btn.disabled) {
272-
btn.click();
273-
return;
249+
if (stored?.element) {
250+
element = stored.element;
251+
} else {
252+
// Fallback: find any playing media
253+
const allMedia = document.querySelectorAll('video, audio');
254+
for (const media of allMedia) {
255+
if (!media.paused && media.duration > 0) {
256+
element = media;
257+
break;
274258
}
275-
} catch (e) {}
259+
}
276260
}
277261

278-
// Fallback: seek to end
279-
if (stored?.element?.duration && isFinite(stored.element.duration)) {
280-
stored.element.currentTime = stored.element.duration;
262+
if (element && isFinite(element.duration) && element.duration > 0) {
263+
Logger.debug('Skip: seeking to end', element.duration);
264+
element.currentTime = element.duration;
265+
} else {
266+
Logger.debug('Skip: no valid media element found');
281267
}
282268
}
283269
}

src/content/adapters/soundcloud-adapter.js

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,10 @@ class SoundCloudAdapter extends BaseAdapter {
271271
for (const selector of selectors) {
272272
try {
273273
const el = document.querySelector(selector);
274-
const text = el?.textContent?.trim();
274+
let text = el?.textContent?.trim();
275275
if (text && text.length > 0) {
276+
// Remove "Current track:" prefix if present
277+
text = text.replace(/^Current track:\s*/i, '');
276278
return text.substring(0, 100);
277279
}
278280
} catch (e) {}
@@ -328,13 +330,14 @@ class SoundCloudAdapter extends BaseAdapter {
328330
duration: this.getDuration(),
329331
currentTime: this.getCurrentTime(),
330332
isPlaying: this.isPlaying, // Use our tracked state
331-
hasSkip: !!this.getNextButton(),
333+
hasSkip: true,
332334
mediaType: 'audio'
333335
};
334336
}
335337

336338
hasSkipButton() {
337-
return !!this.getNextButton();
339+
// Always available - can click next or seek to end
340+
return true;
338341
}
339342

340343
// ===== Controls =====
@@ -402,9 +405,43 @@ class SoundCloudAdapter extends BaseAdapter {
402405

403406
skip(mediaId) {
404407
Logger.debug('SoundCloud: Skip command');
408+
409+
// Try SoundCloud's next button first
405410
const nextBtn = this.getNextButton();
406411
if (nextBtn) {
407412
nextBtn.click();
413+
return;
414+
}
415+
416+
// Fallback: seek to end of current track
417+
const audioElements = document.querySelectorAll('audio');
418+
for (const audio of audioElements) {
419+
if (!audio.paused && isFinite(audio.duration) && audio.duration > 0) {
420+
Logger.debug('SoundCloud: Seeking to end', audio.duration);
421+
audio.currentTime = audio.duration;
422+
return;
423+
}
424+
}
425+
}
426+
427+
prev(mediaId) {
428+
Logger.debug('SoundCloud: Prev command');
429+
430+
// Try SoundCloud's prev button first
431+
const prevBtn = this.getPrevButton();
432+
if (prevBtn) {
433+
prevBtn.click();
434+
return;
435+
}
436+
437+
// Fallback: seek to start of current track
438+
const audioElements = document.querySelectorAll('audio');
439+
for (const audio of audioElements) {
440+
if (!audio.paused && isFinite(audio.duration) && audio.duration > 0) {
441+
Logger.debug('SoundCloud: Seeking to start');
442+
audio.currentTime = 0;
443+
return;
444+
}
408445
}
409446
}
410447
}

src/content/media-detector.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ class MediaDetector {
3939
this.adapter.skip(mediaId);
4040
break;
4141

42+
case AUTOSTOP.ACTION.PREV:
43+
this.adapter.prev(mediaId);
44+
break;
45+
4246
case AUTOSTOP.ACTION.SET_VOLUME:
4347
this.adapter.setVolume(mediaId, volume);
4448
break;

src/manifest.json

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
{
22
"manifest_version": 2,
33
"name": "Auto-Stop Media",
4-
"version": "1.1.3",
4+
"version": "1.1.4",
55
"description": "Automatically pause media in other tabs when new media starts playing. Only one media plays at a time.",
66
"author": "purr",
77
"homepage_url": "https://github.com/purr/auto-stop",
88

99
"browser_specific_settings": {
1010
"gecko": {
1111
"id": "{a8f133d7-f5a5-4041-9fa0-56b1eeaa844e}",
12-
"strict_min_version": "142.0",
12+
"strict_min_version": "140.0",
1313
"data_collection_permissions": {
14-
"required": ["none"],
15-
"technical_data": false,
16-
"interaction_data": false
14+
"required": ["none"]
1715
}
1816
}
1917
},

0 commit comments

Comments
 (0)