feat(podcasts): scanner exclusion — podcasts libraries are feed-managed (task 1.2)
WHY: podcast download roots hold fetcher-written episode files; the FS
walker must never discover them (invariant 4) — a walk would double-
ingest episodes as scanner items and fight the fetcher's sole-writer
rule (D9). Every scan/watch path funnels through MediaScanner.SetFolders
(StartScanner, ScanLibrary jobs incl. scoped single-folder scans,
watch mode), so the filter lives there once: folders resolving to a
podcasts-type library are dropped before registration, with a log line.
Belt and braces: ScanLibrary's per-folder scope refuses purpose='podcast'
folders explicitly (400) — the panel-level path that bypasses type
resolution. AddLibraryFolder now derives purpose from the library type
('podcast' for podcasts libraries, enforced single download root;
'scan' default elsewhere), so folder purpose and library type cannot
diverge through the API.
This commit is contained in:
1 parent
0b7ad0f376
commit
c0e6993273
6 files changed
+77
-3
No files matched your search
@@ -22,6 +22,8 @@ type Querier interface {
|
||||
// ============================================
|
||||
AddBookToKoboShelf(ctx context.Context, arg AddBookToKoboShelfParams) (KoboShelves, error)
|
||||
// Library Folders queries
|
||||
// purpose: 'scan' (FS-walker root, default) | 'podcast' (download root;
|
||||
// scanner-skipped, written by the podcast download worker instead).
|
||||
AddLibraryFolder(ctx context.Context, arg AddLibraryFolderParams) (LibraryFolders, error)
|
||||
// Second consecutive missing scan: hide the item from all browsing while
|
||||
// preserving reading history in case the file returns.
|
||||
|
||||
@@ -123,17 +123,20 @@ func (q *Queries) AddBookToKoboShelf(ctx context.Context, arg AddBookToKoboShelf
|
||||
}
|
||||
|
||||
const AddLibraryFolder = `-- name: AddLibraryFolder :one
|
||||
INSERT INTO library_folders (library_id, folder_path) VALUES ($1, $2) RETURNING id, library_id, folder_path, created_at, purpose
|
||||
INSERT INTO library_folders (library_id, folder_path, purpose) VALUES ($1, $2, $3) RETURNING id, library_id, folder_path, created_at, purpose
|
||||
`
|
||||
|
||||
type AddLibraryFolderParams struct {
|
||||
LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
|
||||
FolderPath string `db:"folder_path" json:"folder_path"`
|
||||
Purpose string `db:"purpose" json:"purpose"`
|
||||
}
|
||||
|
||||
// Library Folders queries
|
||||
// purpose: 'scan' (FS-walker root, default) | 'podcast' (download root;
|
||||
// scanner-skipped, written by the podcast download worker instead).
|
||||
func (q *Queries) AddLibraryFolder(ctx context.Context, arg AddLibraryFolderParams) (LibraryFolders, error) {
|
||||
row := q.db.QueryRow(ctx, AddLibraryFolder, arg.LibraryID, arg.FolderPath)
|
||||
row := q.db.QueryRow(ctx, AddLibraryFolder, arg.LibraryID, arg.FolderPath, arg.Purpose)
|
||||
var i LibraryFolders
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
|
||||
@@ -97,7 +97,9 @@ DELETE FROM libraries WHERE id = $1;
|
||||
|
||||
-- Library Folders queries
|
||||
-- name: AddLibraryFolder :one
|
||||
INSERT INTO library_folders (library_id, folder_path) VALUES ($1, $2) RETURNING *;
|
||||
-- purpose: 'scan' (FS-walker root, default) | 'podcast' (download root;
|
||||
-- scanner-skipped, written by the podcast download worker instead).
|
||||
INSERT INTO library_folders (library_id, folder_path, purpose) VALUES ($1, $2, $3) RETURNING *;
|
||||
|
||||
-- name: GetLibraryFolders :many
|
||||
SELECT * FROM library_folders WHERE library_id = $1 ORDER BY created_at;
|
||||
|
||||
Reference in new issue
Block a user