-
Notifications
You must be signed in to change notification settings - Fork 2
feat: add optional songs filter to content creation pipeline #112
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
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
1ba1849
feat: add album-record-store template and dynamic template loading
sidneyswift dd6f056
feat: add optional songs filter to content creation pipeline
sidneyswift eff3a80
refactor: remove unrelated changes, keep only songs[] filtering
sweetmantech 62bb3df
refactor: extract filterSongPaths into separate file
sweetmantech 33c889c
test: add filterSongPaths tests
sweetmantech 5ffc9eb
refactor: selectAudioClip accepts payload directly
sweetmantech 31dd7ad
refactor: simplify selectAudioClip signature and filter guard
sweetmantech c3f2fc4
refactor: use shared logStep in filterSongPaths
sweetmantech 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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| import { describe, it, expect, vi } from "vitest"; | ||
| import { filterSongPaths } from "../filterSongPaths"; | ||
|
|
||
| vi.mock("../../sandboxes/logStep", () => ({ | ||
| logStep: vi.fn(), | ||
| })); | ||
|
|
||
| describe("filterSongPaths", () => { | ||
| const artistSlug = "gatsby-grace"; | ||
|
|
||
| it("keeps only paths matching the requested slugs", () => { | ||
| const songPaths = [ | ||
| "artists/gatsby-grace/songs/hiccups/hiccups.mp3", | ||
| "artists/gatsby-grace/songs/adhd/adhd.mp3", | ||
| "artists/gatsby-grace/songs/freefall/freefall.mp3", | ||
| ]; | ||
|
|
||
| const result = filterSongPaths(songPaths, ["hiccups", "adhd"], artistSlug); | ||
|
|
||
| expect(result).toEqual([ | ||
| "artists/gatsby-grace/songs/hiccups/hiccups.mp3", | ||
| "artists/gatsby-grace/songs/adhd/adhd.mp3", | ||
| ]); | ||
| }); | ||
|
|
||
| it("uses exact matching — 'ad' does not match 'adhd'", () => { | ||
| const songPaths = [ | ||
| "artists/gatsby-grace/songs/adhd/adhd.mp3", | ||
| "artists/gatsby-grace/songs/ad/ad.mp3", | ||
| ]; | ||
|
|
||
| const result = filterSongPaths(songPaths, ["ad"], artistSlug); | ||
|
|
||
| expect(result).toEqual([ | ||
| "artists/gatsby-grace/songs/ad/ad.mp3", | ||
| ]); | ||
| }); | ||
|
|
||
| it("throws when no songs match", () => { | ||
| const songPaths = [ | ||
| "artists/gatsby-grace/songs/hiccups/hiccups.mp3", | ||
| ]; | ||
|
|
||
| expect(() => filterSongPaths(songPaths, ["nonexistent"], artistSlug)).toThrow( | ||
| "None of the specified songs [nonexistent] were found for artist gatsby-grace", | ||
| ); | ||
| }); | ||
|
|
||
| it("handles case-insensitive slug matching", () => { | ||
| const songPaths = [ | ||
| "artists/gatsby-grace/songs/Hiccups/Hiccups.mp3", | ||
| ]; | ||
|
|
||
| const result = filterSongPaths(songPaths, ["hiccups"], artistSlug); | ||
|
|
||
| expect(result).toEqual([ | ||
| "artists/gatsby-grace/songs/Hiccups/Hiccups.mp3", | ||
| ]); | ||
| }); | ||
|
|
||
| it("trims whitespace from slugs", () => { | ||
| const songPaths = [ | ||
| "artists/gatsby-grace/songs/hiccups/hiccups.mp3", | ||
| ]; | ||
|
|
||
| const result = filterSongPaths(songPaths, [" hiccups "], artistSlug); | ||
|
|
||
| expect(result).toEqual([ | ||
| "artists/gatsby-grace/songs/hiccups/hiccups.mp3", | ||
| ]); | ||
| }); | ||
|
|
||
| it("returns all paths when songs is undefined", () => { | ||
| const songPaths = [ | ||
| "artists/gatsby-grace/songs/hiccups/hiccups.mp3", | ||
| "artists/gatsby-grace/songs/adhd/adhd.mp3", | ||
| ]; | ||
|
|
||
| const result = filterSongPaths(songPaths, undefined, artistSlug); | ||
|
|
||
| expect(result).toEqual(songPaths); | ||
| }); | ||
|
|
||
| it("returns all paths when songs is empty", () => { | ||
| const songPaths = [ | ||
| "artists/gatsby-grace/songs/hiccups/hiccups.mp3", | ||
| ]; | ||
|
|
||
| const result = filterSongPaths(songPaths, [], artistSlug); | ||
|
|
||
| expect(result).toEqual(songPaths); | ||
| }); | ||
|
|
||
| it("works with org repo encoded paths", () => { | ||
| const songPaths = [ | ||
| "__ORG_REPO__https://github.com/org/repo__artists/gatsby-grace/songs/hiccups/hiccups.mp3", | ||
| ]; | ||
|
|
||
| const result = filterSongPaths(songPaths, ["hiccups"], artistSlug); | ||
|
|
||
| expect(result).toEqual([songPaths[0]]); | ||
| }); | ||
| }); |
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,37 @@ | ||
| import { parseSongPath } from "./listArtistSongs"; | ||
| import { logStep } from "../sandboxes/logStep"; | ||
|
|
||
| /** | ||
| * Filters song paths to only include those matching the given slugs. | ||
| * Uses exact slug matching against the directory name under /songs/. | ||
| * Returns songPaths unmodified when songs is empty or undefined. | ||
| * | ||
| * @param songPaths - Encoded song paths from listArtistSongs | ||
| * @param songs - Song slugs to keep (e.g. ["hiccups", "adhd"]) | ||
| * @param artistSlug - Artist slug (for error messages) | ||
| * @returns Filtered song paths | ||
| */ | ||
| export function filterSongPaths( | ||
| songPaths: string[], | ||
| songs: string[] | undefined, | ||
| artistSlug: string, | ||
| ): string[] { | ||
| if (!songs || songs.length === 0) return songPaths; | ||
|
|
||
| const requested = new Set(songs.map(s => s.trim().toLowerCase()).filter(Boolean)); | ||
|
|
||
| const filtered = songPaths.filter(encodedPath => { | ||
| const { filePath } = parseSongPath(encodedPath); | ||
| const match = filePath.match(/\/songs\/([^/]+)\//); | ||
| return !!match && requested.has(match[1].toLowerCase()); | ||
| }); | ||
|
|
||
| if (filtered.length === 0) { | ||
| throw new Error( | ||
| `None of the specified songs [${songs.join(", ")}] were found for artist ${artistSlug}`, | ||
| ); | ||
| } | ||
|
|
||
| logStep("Filtered to specified songs", false, { songs, matchCount: filtered.length }); | ||
| return filtered; | ||
| } |
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
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.
Harden
songsvalidation to reject empty/invalid slugs.Right now
songsaccepts[""](or whitespace), which can lead to unintended filtering behavior downstream. Validate each slug and reject empty entries at the schema boundary.🔧 Proposed schema tightening
🤖 Prompt for AI Agents