* feat(collections): add profile-scoped display filters
* refactor(collections): dedup display-filter helpers per review
Address code-review feedback on the profile-scoped display filters
without changing behavior:
- Widen CompletedHistoryItemMap to accept ProgressCompletionStore and
drop the duplicate completedHistoryItemMapForProgress copy.
- Extract the duplicated MDBList candidate retry loop into a generic
collectionutil.FetchMDBListWithFallback helper, used by both the user
and library collection syncers, and cover it with unit tests.
- Reuse validateOptionalLibraryIDs in HandleUpdateCollection instead of
an inline positive-ID loop.
- Import the shared COLLECTION_{WATCH,MEDIA}_FILTER_OPTIONS in the
template config form rather than redefining them locally.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(collections): sanitize query_definition library_ids fallback
readSourceConfigLibraryIDs validated source_config.library_ids (finite,
positive, truncated, deduplicated) but returned the query_definition
fallback raw, so legacy rows could surface zero/negative/duplicate IDs
that the backend now rejects on save. Extract a shared sanitizer and
apply it to both paths.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* refactor(docs): This makes the agents annoying to work with
* Improve playback session handling
* Support collection source order in catalog filters
* fix(collections): address display filter review feedback
* refactor(catalog): remove duplicate collection query params
* Hide episode media scope for collection overlays
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
58 lines
1.7 KiB
Go
58 lines
1.7 KiB
Go
package collectionutil
|
|
|
|
import "strings"
|
|
|
|
// NormalizeMDBListURL accepts either an MDBList page URL or its JSON variant
|
|
// and returns the canonical JSON URL. Trailing slashes and accidental repeated
|
|
// /json suffixes are tolerated.
|
|
func NormalizeMDBListURL(url string) string {
|
|
url = strings.TrimSpace(url)
|
|
if url == "" {
|
|
return ""
|
|
}
|
|
url = strings.TrimRight(url, "/")
|
|
for strings.HasSuffix(url, "/json/json") {
|
|
url = strings.TrimSuffix(url, "/json")
|
|
}
|
|
if !strings.HasSuffix(url, "/json") {
|
|
url += "/json"
|
|
}
|
|
return url
|
|
}
|
|
|
|
// FetchMDBListWithFallback tries each candidate URL in order and returns the
|
|
// entries from the first successful fetch, recovering when source_config and
|
|
// source_url drift. It returns the last error when every candidate fails.
|
|
// Callers should guard against an empty url list beforehand; an empty list
|
|
// yields a nil result and nil error.
|
|
func FetchMDBListWithFallback[T any](urls []string, fetch func(string) ([]T, error)) ([]T, error) {
|
|
var entries []T
|
|
var err error
|
|
for _, url := range urls {
|
|
entries, err = fetch(url)
|
|
if err == nil {
|
|
return entries, nil
|
|
}
|
|
}
|
|
return entries, err
|
|
}
|
|
|
|
// MDBListURLCandidates returns unique canonical JSON URLs, preserving argument
|
|
// order. It lets syncers recover when source_config and source_url drift.
|
|
func MDBListURLCandidates(urls ...string) []string {
|
|
candidates := make([]string, 0, len(urls))
|
|
seen := make(map[string]struct{}, len(urls))
|
|
for _, url := range urls {
|
|
normalized := NormalizeMDBListURL(url)
|
|
if normalized == "" {
|
|
continue
|
|
}
|
|
if _, ok := seen[normalized]; ok {
|
|
continue
|
|
}
|
|
seen[normalized] = struct{}{}
|
|
candidates = append(candidates, normalized)
|
|
}
|
|
return candidates
|
|
}
|