Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions src/main/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ func main() {
log.Fatal(srv.Start())
}

slog.Info("Pulling playlist", "playlist", cfg.Flags.Playlist)

var tracks []*models.Track
var err error
if strings.HasPrefix(cfg.Flags.Playlist, "custom-") {
Expand All @@ -178,11 +180,15 @@ func main() {
tracks, err = disc.Discover()
}

if err != nil {
if err != nil {
slog.Error(err.Error(), "notify", true)
os.Exit(1)
}
allTracks := append([]*models.Track(nil), tracks...)
if cfg.ServerCfg.WebDataDir != "" {
backend.WritePlaylistCache(cfg.ServerCfg.WebDataDir, cfg.Flags.Playlist, allTracks, nil)
slog.Info("Saved playlist", "playlist", cfg.Flags.Playlist, "tracks", len(allTracks))
}

client, err := client.NewClient(&cfg)
if err != nil {
Expand Down Expand Up @@ -217,14 +223,6 @@ func main() {
}
}

if cfg.ServerCfg.Enabled {
added := make(map[string]bool)
for _, t := range tracks {
added[t.CleanTitle+"|"+t.Artist] = true
}
backend.WritePlaylistCache(cfg.Flags.CfgPath, cfg.Flags.Playlist, allTracks, added)
}

if err := client.CreatePlaylist(tracks); err != nil {
slog.Warn(err.Error())
} else {
Expand Down
14 changes: 13 additions & 1 deletion src/web/frontend/src/components/Settings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
fetchPathTemplatePresets, addPathTemplatePreset, deletePathTemplatePreset,
} from '../lib/api'
import { parseSlogLine, cronToFields, highlightEnv } from '../lib/utils'
import { fetchPlaylistTracks } from '../lib/listenbrainz'
import { fetchPlaylistTracks, clearPlaylistCache } from '../lib/listenbrainz'
import { motion, AnimatePresence } from 'motion/react'
import { Toggle } from './ui/Toggle'
import { Button, SectionLabel, Panel, LogRow } from './ui/common'
Expand Down Expand Up @@ -134,6 +134,7 @@ function CustomPlaylistsSection({
onDelete,
showImportModal,
setShowImportModal,
refreshTick = 0,
}) {
return (
<div className="mt-6">
Expand Down Expand Up @@ -170,6 +171,7 @@ function CustomPlaylistsSection({
onTracklistToggle={() => setOpenTracklist(v => v === cp.id ? null : cp.id)}
sourceUrl={cp.source_url || undefined}
onDelete={(opts) => onDelete(cp.id, opts)}
refreshTick={refreshTick}
/>
)
})}
Expand All @@ -181,6 +183,7 @@ function CustomPlaylistsSection({
playlist={openTracklist}
lbUser={null}
onRun={() => onSync(openTracklist)}
refreshTick={refreshTick}
/>
</TracklistSlide>

Expand Down Expand Up @@ -217,6 +220,8 @@ function HomeSection() {
const [rawLog, setRawLog] = useState(false)
const logRef = useRef(null)

const [refreshTick, setRefreshTick] = useState(0)

useEffect(() => {
Promise.all([
fetchConfig(),
Expand Down Expand Up @@ -255,6 +260,10 @@ function HomeSection() {
const onDone = useCallback(code => {
setStatus(code === 0 ? 'done ✓' : code === null ? 'error' : `failed (exit ${code})`)
setRunning(false)
if (code !== null) {
clearPlaylistCache()
setRefreshTick(t => t + 1)
}
}, [])

const { connect, disconnect } = useSSE({ onLine, onDone })
Expand Down Expand Up @@ -362,13 +371,15 @@ function HomeSection() {
nextRunText={nextRunText(p.value)}
tracklistOpen={openTracklist === p.value}
onTracklistToggle={() => setOpenTracklist(v => v === p.value ? null : p.value)}
refreshTick={refreshTick}
/>
))}
</div>
<TracklistSlide show={openTracklist && PLAYLISTS.some(p => p.value === openTracklist)} slideKey={openTracklist}>
<TracklistDropdown
lbUser={lbUser}
playlist={openTracklist}
refreshTick={refreshTick}
onRun={async () => {
await startRun(openTracklist, 'normal', true, false)
setRunning(true)
Expand All @@ -384,6 +395,7 @@ function HomeSection() {
{/* Custom Playlists */}
<CustomPlaylistsSection
customPlaylists={customPlaylists}
refreshTick={refreshTick}
schedules={schedules}
scheduleProps={scheduleProps}
openTracklist={openTracklist}
Expand Down
7 changes: 4 additions & 3 deletions src/web/frontend/src/components/ui/PlaylistCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ function nextUpdateLabel(playlistType) {
return `Next update ${nextMonday.toLocaleDateString([], { weekday: 'long', month: 'short', day: 'numeric' })}`
}

export function TracklistDropdown({ playlist, lbUser, onRun }) {
export function TracklistDropdown({ playlist, lbUser, onRun, refreshTick = 0 }) {
const [tracks, setTracks] = useState([])
const [generatedAt, setGeneratedAt] = useState(null)
const [loading, setLoading] = useState(true)
Expand Down Expand Up @@ -145,7 +145,7 @@ export function TracklistDropdown({ playlist, lbUser, onRun }) {
useEffect(() => {
if (!playlist) return
return loadTracks(false)
}, [playlist])
}, [playlist, refreshTick])

const handleFetch = () => {
if (!lbUser) return
Expand Down Expand Up @@ -376,6 +376,7 @@ export function PlaylistCard({
trackId,
artworkUrl,
sourceUrl,
refreshTick = 0,
}) {
const { value, name } = playlist
// trackFetchId: use real playlist ID (custom playlists) if provided, else fall back to value
Expand Down Expand Up @@ -428,7 +429,7 @@ export function PlaylistCard({
cancelled = true
if (retryTimer) clearTimeout(retryTimer)
}
}, [trackFetchId, s.enabled])
}, [trackFetchId, s.enabled, refreshTick])

useEffect(() => {
if (bgCovers.length < 2) return
Expand Down
5 changes: 5 additions & 0 deletions src/web/frontend/src/lib/listenbrainz.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
// Session-level cache — avoids repeat fetches on open/close within the same page load.
const memCache = new Map()

export function clearPlaylistCache(playlistType) {
if (playlistType) memCache.delete(playlistType)
else memCache.clear()
}

export async function fetchPlaylistTracks(playlistType, options = {}) {
const key = playlistType
if (!options.force && memCache.has(key)) return memCache.get(key)
Expand Down
Loading