fix(wave): switch to the new context right away when activity or mood changes
Changing the activity or mood used to keep the current track playing and only replace the upcoming ones, so nothing seemed to happen. Now the first track of the new batch starts immediately (web and Android). The interrupted track is not reported to the wave as a skip and is recorded in history only if it played for at least 30 s, so a context change does not teach the recommender a false dislike. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7cf741d82f
commit
6ad49fe0e3
2 files changed
+38
-4
No files matched your search
@@ -186,7 +186,10 @@ export class Player {
|
||||
void this.load(true);
|
||||
}
|
||||
|
||||
/** Сменить занятие / настроение на лету: текущий трек доигрывает, дальше — новая пачка. */
|
||||
/**
|
||||
* Сменить занятие / настроение на лету: сразу играет первый трек новой пачки (docs/recommendations.md#6.7).
|
||||
* Прерванный трек — не скип: волне сигнал не уходит, в историю он попадает, только если играл ≥ 30 с.
|
||||
*/
|
||||
async setWaveContext(activity: string | null, mood: string | null) {
|
||||
const wave = this.state.wave;
|
||||
if (!wave) return this.startWave(activity, mood);
|
||||
@@ -197,10 +200,17 @@ export class Player {
|
||||
body: { activity, mood },
|
||||
}),
|
||||
);
|
||||
const fresh = res.tracks.filter((t) => t.available && t.stream_url);
|
||||
this.queue.dropUpcoming();
|
||||
this.queue.append(res.tracks.filter((t) => t.available && t.stream_url));
|
||||
this.queue.append(fresh);
|
||||
this.update({ wave: { ...wave, activity: res.activity, mood: res.mood, fallback: res.fallback } });
|
||||
this.syncQueue();
|
||||
if (fresh.length && this.queue.next()) {
|
||||
this.finishAttempt('skip', true);
|
||||
this.syncQueue();
|
||||
void this.load(true);
|
||||
} else {
|
||||
this.syncQueue();
|
||||
}
|
||||
}
|
||||
|
||||
stopWave() {
|
||||
@@ -395,11 +405,19 @@ export class Player {
|
||||
}
|
||||
|
||||
/** Завершает текущую попытку: событие с реально прослушанным временем. */
|
||||
private finishAttempt(type: 'play_end' | 'skip') {
|
||||
/** neutral — трек прерван сменой контекста волны: не отрицательный сигнал и без короткого «скипа» в событиях. */
|
||||
private finishAttempt(type: 'play_end' | 'skip', neutral = false) {
|
||||
const a = this.attempt;
|
||||
if (!a) return;
|
||||
this.attempt = null;
|
||||
const pos = Math.round(this.audio.currentTime * 1000);
|
||||
if (neutral) {
|
||||
if (a.playedMs >= EARLY_SKIP_MS) {
|
||||
this.events.push({ type: 'skip', track_id: a.track.id, position_ms: pos, played_ms: Math.round(a.playedMs) });
|
||||
void this.events.flush();
|
||||
}
|
||||
return;
|
||||
}
|
||||
const kind = type === 'skip' ? a.outcome(pos) : 'play_end';
|
||||
this.events.push({ type: kind, track_id: a.track.id, position_ms: pos, played_ms: Math.round(a.playedMs) });
|
||||
void this.events.flush();
|
||||
|
||||
Reference in new issue
Block a user