0.2.76 - Icon Packs
This commit is contained in:
@@ -120,6 +120,70 @@ func (s *Store) DeleteLibraryItemsBefore(ctx context.Context, cutoff time.Time)
|
||||
return tag.RowsAffected(), nil
|
||||
}
|
||||
|
||||
// NamedItem is the least a caller can be told about a catalogue row and still identify
|
||||
// it: what it is called and, where the library knows, when it came out.
|
||||
type NamedItem struct {
|
||||
ID string
|
||||
Name string
|
||||
Year int
|
||||
}
|
||||
|
||||
// LibraryItemsByName finds catalogue rows by title, case-insensitively.
|
||||
//
|
||||
// The comparison that decides the answer is not this one: the caller normalises both
|
||||
// sides (punctuation and spacing are where an *arr and Emby actually differ) and picks by
|
||||
// year. This is the narrowing query — a handful of rows out of twenty thousand — so that
|
||||
// the matching rule can stay a pure function with one definition.
|
||||
func (s *Store) LibraryItemsByName(ctx context.Context, itemType, name string) ([]NamedItem, error) {
|
||||
trimmed := strings.TrimSpace(name)
|
||||
if trimmed == "" {
|
||||
return nil, nil
|
||||
}
|
||||
rows, err := s.pool.Query(ctx, `
|
||||
SELECT id, name, COALESCE(production_year, 0)
|
||||
FROM library_items
|
||||
WHERE type = $1 AND lower(name) = lower($2)
|
||||
LIMIT 50`, itemType, trimmed)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("store: library items by name: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
out := []NamedItem{}
|
||||
for rows.Next() {
|
||||
var item NamedItem
|
||||
if err := rows.Scan(&item.ID, &item.Name, &item.Year); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, item)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
// DeleteLibraryItem removes one item and anything derived from it.
|
||||
//
|
||||
// The credits marker goes with it, and that is the point of doing this in one place: the
|
||||
// marker table is keyed on the item id and nothing else prunes it, so a title deleted from
|
||||
// the library would otherwise leave a Skip Credits position behind for a file that no
|
||||
// longer exists — and if that id were ever reused, in front of the wrong programme.
|
||||
//
|
||||
// Deleting a series takes its episodes with it, because Emby's own hierarchy is the only
|
||||
// thing that made those rows meaningful.
|
||||
func (s *Store) DeleteLibraryItem(ctx context.Context, itemID string) (int64, error) {
|
||||
if strings.TrimSpace(itemID) == "" {
|
||||
return 0, nil
|
||||
}
|
||||
tag, err := s.pool.Exec(ctx,
|
||||
`DELETE FROM library_items WHERE id = $1 OR series_id = $1`, itemID)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("store: delete library item: %w", err)
|
||||
}
|
||||
if _, err := s.pool.Exec(ctx,
|
||||
`DELETE FROM credits_markers WHERE item_id = $1 OR series_id = $1`, itemID); err != nil {
|
||||
return 0, fmt.Errorf("store: delete credits markers: %w", err)
|
||||
}
|
||||
return tag.RowsAffected(), nil
|
||||
}
|
||||
|
||||
// SearchLibrary answers from the imported library rather than Emby.
|
||||
//
|
||||
// Full-text match first, with a trailing ILIKE so partial words ("sever") still hit
|
||||
|
||||
Reference in New Issue
Block a user