-
Notifications
You must be signed in to change notification settings - Fork 32
Fix per-user Last.fm integration #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
858a75a
Fix per-user Last.fm integration
Darep 49282de
refactor(auth): defer user synchronization
Darep 87077c4
refactor(frontend): simplify Last.fm scrobbler
Darep 5521df8
fix(lastfm): accept fractional track durations
Darep f8c0bc3
fix(lastfm): open authorization popup synchronously
Darep 4b95c2b
fix(lastfm): persist connection changes atomically
Darep ab45b43
fix(frontend): distinguish repeated track plays
Darep 3ba31c0
fix(frontend): scrobble by elapsed play time
Darep 71fe2f0
fix(frontend): skip plays already in progress
Darep 3e66284
fix(lastfm): report disconnect failures
Darep f0e8d71
fix(lastfm): explain non-JSON HTTP failures
Darep 3072eb1
fix(lastfm): preserve pending authorization
Darep 0ce4e11
fix(lastfm): handle failed submissions
Darep 6037cc9
fix(lastfm): report ignored submissions
Darep d54a70e
fix(frontend): count restored playback as a new instance
Darep 6e75f1d
fix(frontend): count actual playback progress
Darep 6da29e1
fix(lastfm): require tracks longer than thirty seconds
Darep 95bf1b4
fix(lastfm): align mutation responses
Darep 23a4a8a
fix(frontend): improve Last.fm playback tracking
Darep 5874ef6
fix: add some newlines
Darep cd4eb11
refactor(lastfm): clarify playback counter
Darep 4ec597d
Apply suggestion from @Darep
Darep ba61c48
refactor(lastfm): simplify scrobble state
Darep File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| import { useLastFM } from 'hooks/swr'; | ||
| import { useEffect, useRef } from 'react'; | ||
| import { usePlayerStore } from 'store'; | ||
| import { mutate } from 'swr'; | ||
| import { ApiError, request } from 'utils/api'; | ||
| import { createLastFMPlaybackTracker } from 'utils/LastFMPlayback'; | ||
|
|
||
| export const LastFMScrobbler = () => { | ||
| const { data: lastFM } = useLastFM(); | ||
| const scrobbledPlaybackCount = useRef<number | undefined>(undefined); | ||
|
|
||
| useEffect(() => { | ||
| if (!lastFM?.connected) return; | ||
|
|
||
| const trackPlayback = createLastFMPlaybackTracker(); | ||
| let startedAt = 0; | ||
|
|
||
| const sync = (player: ReturnType<typeof usePlayerStore.getState>) => { | ||
| const { song, state, position, parsedDuration, playbackCount } = player; | ||
|
|
||
| if (!song?.artist || !song.title) return; | ||
|
|
||
| const duration = parsedDuration || song.length || 0; | ||
|
|
||
| const playback = trackPlayback({ | ||
| duration, | ||
| playbackCount, | ||
| now: performance.now(), | ||
| position, | ||
| state, | ||
| }); | ||
|
|
||
| if (playback.started) { | ||
|
Darep marked this conversation as resolved.
|
||
| startedAt = Math.floor(Date.now() / 1000); | ||
| void request('/api/lastfm/now-playing', { | ||
| method: 'POST', | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| body: JSON.stringify({ artist: song.artist, track: song.title, album: song.album, duration }), | ||
| }).catch((error: unknown) => { | ||
| console.error(`Could not update Last.fm now playing for ${song.artist} — ${song.title}`, error); | ||
|
|
||
| if (error instanceof ApiError && error.status === 409) { | ||
| // Refresh connection state when the Last.fm session expires. | ||
| void mutate('/api/lastfm'); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| if (!playback.shouldScrobble || scrobbledPlaybackCount.current === playbackCount) { | ||
| return; | ||
| } | ||
|
|
||
| scrobbledPlaybackCount.current = playbackCount; | ||
|
|
||
| void request('/api/lastfm/scrobble', { | ||
| method: 'POST', | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| body: JSON.stringify({ | ||
| artist: song.artist, | ||
| track: song.title, | ||
| album: song.album, | ||
| duration, | ||
| timestamp: startedAt, | ||
| }), | ||
| }).catch((error: unknown) => { | ||
| console.error(`Could not scrobble ${song.artist} — ${song.title}`, error); | ||
|
|
||
| if (error instanceof ApiError && error.status === 409) { | ||
| // Refresh connection state when the Last.fm session expires. | ||
| void mutate('/api/lastfm'); | ||
| } | ||
| }); | ||
| }; | ||
|
|
||
| // Set initial state | ||
| sync(usePlayerStore.getState()); | ||
|
|
||
| // Continuously sync playback state when state in store updates | ||
| return usePlayerStore.subscribe(sync); | ||
|
Darep marked this conversation as resolved.
|
||
| }, [lastFM?.connected]); | ||
|
|
||
| return null; | ||
| }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Undo this removal of a newline.