GSoC 2026 : Playlists Sorting and Organization proposal by Akshay Jaiswal

[UPDATE: March 23] I have heavily revised this proposal for my official GSoC submission. I updated the database architecture, added detailed execution flowcharts, and refined the UI mockups based on community guidelines. I would love any final feedback from the team!

ListenBrainz: Playlists Sorting and Organization

Contact Information

Name: Akshay Jaiswal

Nickname: @Akkii05jaiswal

IRC / Matrix handle: @akkii_jaiswal:matrix.org

Email: jaiswalakshay2709@gmail.com

GitHub: https://github.com/Akki-jaiswal

LinkedIn: www.linkedin.com/in/akkii-jaiswal

Proposed Project

ListenBrainz users rely heavily on playlists, but the current infrastructure lacks robust personal organization and dynamic sorting. My project addresses four main deliverables:

  1. Implementing a personal labeling/folder system (LB-1302).

  2. Allowing dynamic track sorting within playlists (LB-1374).

  3. Enabling personal playlist search.

  4. Integrating MusicBrainz collections as read-only playlists (LB-961).

Part A: Playlist Organizing (LB-1302)

A naive approach would be to create a playlist_tag mapping table linking a tag_name to a playlist_id. However, because playlists can be collaborative, labels need to be personal to the user viewing them, not globally applied.

Proposed Database Schema: I will create a new table via migration that ties the label to both the playlist and the specific user.

CREATE TABLE playlist.user_playlist_label (
    id SERIAL PRIMARY KEY,
    playlist_id INT NOT NULL REFERENCES playlist.playlist(id) ON DELETE CASCADE,
    user_id INT NOT NULL REFERENCES public.user(id) ON DELETE CASCADE,
    label_name TEXT NOT NULL,
    created TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
    UNIQUE (playlist_id, user_id, label_name)
);

The UNIQUE constraint ensures a user cannot apply the exact same label to the same playlist twice, silently ignoring duplicate requests at the DB level.

Backend Python API:

I will add endpoints in webserver/views/playlist_api.py to handle CRUD operations for labels, verifying the user_id via the validate_auth_header() function before execution.

*# pseudocode for adding a personal label*

def add_label_to_playlist(db_conn, playlist_mbid, user_id, label_name):
    playlist_id = db_playlist.get_id_from_mbid(db_conn,
playlist_mbid)

Frontend (React) UI Additions:

For the UI, I will implement the “Gmail-style” sidebar mockups to filter playlists by label_name, and render pill-shaped label tags on the PlaylistCard components.

(Figure: High-fidelity mockups of the sidebar and tags are actively attached and discussed in my MetaBrainz Community Forum post under the gsoc-applications tag*.)*

image|406.832657856094x79

This will include:

  • A sidebar component to filter playlists by label_name.

  • Pill-shaped label tags rendered on the PlaylistCard components.

Part B: Playlist Ordering (LB-1374)

I will implement a dynamic client-side sorting dropdown (Title, Artist, Date). Once the user previews the new order in the React UI, they can click ‘Save’, which will trigger a POST /playlist//item/reorder request to update the playlist_recording.position values in the PostgreSQL backend.

Backend Modification:

# webserver/views/playlist_api.py
def get_playlist(playlist_mbid):
    sort_by = request.args.get('sort', 'position')
    # Valid options: 'position', 'created', 'title', 'artist', 'random'
    # Pass sort_by to db_playlist.get_by_mbid 
      to dynamically alter the ORDER BY clause


Frontend Implementation:

In the React frontend, a new dropdown component will trigger a refetch of the playlist data with the selected query parameter, updating the PlaylistItemCard renders without a full page reload.

Part C: Personal Playlist Search

I will append a ?scope=personal parameter to the /search API to restrict results to the user’s library. This enables users to efficiently search strictly within their own saved playlists.

image

Figure : Frontend UI mockup for the personal playlist search. The dropdown integrates with the labeling system (Part A), allowing users to granularly scope their search queries by specific playlist names or custom-assigned folders/labels.

Figure : Detailed technical flowchart illustrating the full-stack execution flow of the proposed personal playlist search feature. It details the complete request lifecycle: (1) React frontend logic, including user input and 300ms debouncing, (2) Python API endpoint validation and user authentication check to determine viewer_id, and (3) PostgreSQL backend operations, spanning SQL query construction, similarity scoring and filtering, and final dynamic sorting and pagination before returning results to the frontend for rendering.

Part D: MusicBrainz Collections as Playlists (LB-961)

As outlined in the official ideas list, MusicBrainz collections will be accessible via a separate tab and will not function as standard ListenBrainz playlists. To prevent unauthorized track reorganization, these collections will not be imported into the local playlist database table. Instead, I will map the external MB API data (focusing first on recording collections, then exploring release groups) to the ListenBrainz JSPF format on the fly. This payload will be rendered using the existing React component with a strict canEdit={false} prop to natively disable drag-and-drop sorting, while still building the API hooks necessary to support the requested “add/remove items” functionality directly back to MusicBrainz.

Backend Data Mapping:

# Proposed mapping logic in webserver/views/mb_collection_api.py
def fetch_and_map_mb_collection(collection_mbid: str, user_token: str) -> dict:
    # Fetch from external MB API
    mb_data = fetch_from_musicbrainz(collection_mbid)
    
    # Map to ListenBrainz JSPF
    jspf_payload = {
        "playlist": {
            "title": mb_data.get('name'),
            "track": map_mb_recordings_to_tracks(mb_data.get('recordings', [])),
            "extension": {
                "[https://musicbrainz.org/doc/jspf](https://musicbrainz.org/doc/jspf)": {
                    "is_mb_collection": True,
                    "read_only": True  # Security flag
                }
            }
        }
    }
    return jsonify(jspf_payload)


Frontend (React) Integration:

I will create a new tab for “MB Collections”. When rendering these specific JSPF payloads, I will utilize the existing Playlist.tsx component but pass a strict canEdit={false} prop.

JavaScript

//React implementation ensuring read-only state

<Playlist 
    playlistData={mappedMBCollection} 
    canEdit={false} 
    hideDeleteButtons={true} 
/>

This elegant component reuse ensures the UI natively disables drag-and-drop sorting and track deletion without requiring us to build an entirely new “Read-Only Playlist” view from scratch.

(Community Feedback Note: This proposal is currently live on the MetaBrainz Community Forum under the gsoc-applications tag to gather feedback. Additionally, I have engaged with the core team on Jira to investigate related API string limits (LB-1957), successfully coordinating with maintainers to ensure my future database schemas align with their upcoming mapper architecture ).

_______________________________________________________________________________

Timeline

Week Hours Key Deliverables
Week 1 14 hrs Database Migrations: Implement raw PostgreSQL migration scripts to create the playlist.user_playlist_label table. Add corresponding SQLAlchemy models in db/model/playlist.py and write DB unit tests for UNIQUE constraints.
Week 2 15 hrs Backend API (Labels): Build CRUD endpoints in playlist_api.py for adding, deleting, and updating personal labels. Integrate validate_auth_header() for strict security. Write backend API tests.
Week 3 15 hrs Frontend UI (Labels): Scaffold the “Gmail-style” React sidebar for label navigation. Create pill-shaped UI tags and integrate them into the existing PlaylistCard components.
Week 4 15 hrs Integration: Connect the React sidebar to the new backend APIs. Ensure state updates locally without errors. Submit Pull Request #1 (Playlist Organization).
Week 5 15 hrs Backend Sorting: Update GET /<playlist_mbid> endpoint to accept ?sort parameter (title, artist, created, random). Implement the dynamic SQLAlchemy ORDER BY logic.
Week 6 15 hrs Frontend Sorting: Build the React dropdown component for sorting. Integrate React Query to trigger refetches of playlist data dynamically without triggering a full page reload. Submit Pull Request #2 (Playlist Ordering).
Week 7 15 hrs Personal Search API: Midterm evaluation. Modify the /search API to accept a ?scope=personal parameter. Ensure the backend logic strictly filters results based on the logged-in user’s library.
Week 8 14 hrs Frontend Search UI: Connect the frontend search bar to the updated /search API, ensuring clean handling of the new personal scope parameters. Test query latency.
Week 9 14 hrs MB Collections API: Write the backend mapping logic in webserver/views/mb_collection_api.py to fetch external MusicBrainz API data and map it on the fly to ListenBrainz’s JSPF format.
Week 10 14 hrs Frontend Collections UI: Implement frontend integration for Collections. Reuse the existing <Playlist /> component, passing a strict canEdit={false} prop to ensure read-only status natively.
Week 11 14 hrs Testing: Write comprehensive frontend tests using Jest and React Testing Library for all new components (Sidebar, Sorting Dropdown, MB Collections view). Submit Pull Request #3 (Search & MB Collections).
Week 12 15 hrs Final Polish: Address any lingering mentor feedback, fix edge-case bugs, polish UI transitions, and write comprehensive API documentation. Prepare and submit final evaluations.

_______________________________________________________________________________

AI Usage Disclosure:

In accordance with the MetaBrainz guidelines, I want to transparently disclose that I utilize LLM tools as a development aid. Specifically, I use them for document formatting/structuring, correcting grammatical syntax, and as a “rubber duck” for bouncing initial database schema ideas before writing my own migrations. All core project ideation, technical architecture decisions, and final code submissions are entirely my own work, and I fully understand the implementation of all proposed code.

Community Affinities:

Music Tastes (MBIDs):

  • Blinding Lights - The Weeknd (MBID: 0bdaebde-7023-4416-a36c-dfc58eb190ea)

  • Shape of You - Ed Sheeran (MBID: b84ee85f-8d2a-43d9-abfc-f308a0ab6e58)

  • Tum Hi Ho - Arijit Singh (MBID: c3cc20ba-caeb-4589-a292-cc2de00947ba)

What aspects of the projects interest you the most?

I am deeply interested in Data Analytics and integrating machine learning workflows (such as my ongoing focus on MS Azure AI). ListenBrainz’s massive dataset and personal library infrastructure provide the perfect intersection of heavy database architecture and user-facing data visualization. Building robust systems to organize that data is a natural fit for my career trajectory.

Have you ever used Picard or other projects?

I am actively exploring the wider MetaBrainz ecosystem, focusing primarily on ListenBrainz’s scrobbling and playlist architecture to understand how data flows from the player to the backend databases.

Programming Precedents

When did you first start programming?

My formal programming journey began during my Computer Science studies, where I rapidly progressed from basic scripting to developing complex full-stack web applications and APIs.

Have you contributed to other open source projects?

Yes. Within MetaBrainz, I successfully deployed the ListenBrainz Docker environment and submitted a pull request (LB-812) to add React Testing Library tests for the PlaylistItemCard component. I have also submitted a pull request to the INCF (Brian2) open-source project, establishing their development environment. Furthermore,I have served as a Project Admin for GSSoC '25, which heavily honed my Git workflow and code review skills.

What sorts of programming projects have you done on your own time?

I developed FitLife Hub, utilizing a React frontend and a Python backend via Flask, mirroring the architectural separation used in ListenBrainz. I have also built an AI Fraud Detection System and a Fitness Chatbot, showcasing my ability to manage complex backend logic, machine learning integrations, and API routing.

Practical Requirements:

What computer(s) do you have available? I work on an ASUS TUF Gaming A15 (RTX 3050, Ryzen processor). It efficiently handles running the full ListenBrainz Docker environment, PostgreSQL databases, and message brokers concurrently without performance throttling.

How much time do you have available per week? I am fully committed to this project and will dedicate a minimum of 35 hours per week to ensure all milestones are met ahead of schedule. I will not be attending university courses or holding another job during the Summer of Code coding period, ensuring ListenBrainz has my full, undivided attention.

_______________________________________________________________________________

1 Like

I want to quickly apologize for my recent radio silence—I got tied up with some unavoidable commitments over the last few days.

I’ve just completely overhauled the main post above with my final, officially submitted GSoC proposal! It now includes the updated normalized database schema for Folders/Tags, execution flowcharts, and refined UI mockups.

Even though I was quiet on the forum, I was still chipping away at the codebase in the background. I spent time refining my open PR #3638 for LB-812 (PlaylistItemCard render tests).

I know this is an incredibly busy week with the deadline closing, but I would really appreciate any final feedback on the updated architecture above. Thanks!

Thank you for submitting your proposal! I have a few questions

If you plan to attach a tag to user_id + playlist_id then you’ll not be able to enable global search using tags.

I believe only the owners should be allowed to add tags to a playlist.

Will this be collapsible or permanent? Also, are you planing to add a search bar for searching folders? Incase there are like 100 folders, how are you planning to show them in the UI?

Can you elaborate on this? We also have an option to reorder the playlists manually. How will the two

I believe you’ve uploaded the wrong image here.

Can you elaborate on how do you plan to integrate the label system with search? How would that work in the backend?

how will this work?

Hi @anshgoyal31,

Thank you for taking the time to review this so thoroughly. These questions perfectly highlight the edge cases and scaling challenges we need to account for. Here is how I plan to handle them based on your feedback:

1. “If you plan to attach a tag to user_id + playlist_id then you’ll not be able to enable global search using tags. I believe only the owners should be allowed to add tags to a playlist.”

This is exactly why community feedback is so valuable; you are completely right. Tying tags globally to the playlist_id aligns much better with ListenBrainz’s broader ecosystem and long-term search goals. I will update the schema to make tags global, and implement strict API-level permission checks so that only the playlist owner (and potentially approved collaborators, if applicable) can create or assign tags to that specific playlist.

2. “Will this be collapsible or permanent? Also, are you planing to add a search bar for searching folders? Incase there are like 100 folders, how are you planning to show them in the UI?”

Great point on UI scalability. The folders will definitely be an accordion-style collapsible list to keep the sidebar clean. To handle the 100+ folder edge case without breaking the UX, I will wrap the list in a scrollable container with a set max-height. More importantly, I will add a small, debounced “Filter folders…” input at the top of the section so users can instantly find what they need without endless scrolling.

3. “Can you elaborate on this? We also have an option to reorder the playlists manually. How will the two work together?”

You’ve highlighted a critical UX collision here. To keep the existing manual drag-and-drop order as the “source of truth”, the new sorting dropdown (Title, Artist, Date) will strictly act as a temporary client-side view state. When a user selects “Sort by Artist”, the React UI dynamically re-renders, but the database remains untouched. If the user decides they want to make this new order permanent, they can click a new “Save Order” button, which fires the POST /playlist/<mbid>/item/reorder API to officially overwrite the manual position values in the database.

4. “I believe you’ve uploaded the wrong image here.”

Spot on—that was a markdown copy-paste error on my end during the transfer to Discourse. I will edit the main post shortly to swap in the correct sorting dropdown mockup.

5. “Can you elaborate on how do you plan to integrate the label system with search? How would that work in the backend?”

This is where the normalized database schema really pays off. Instead of rewriting the search logic, I plan to extend the query builder in db_playlist.py. If a query parameter like ?tag=rock is passed, the backend will dynamically JOIN the playlist table with the new playlist_tag_map and playlist_tag tables, filtering for that exact string. This allows us to scale the search endpoints gracefully.

6. “how will this work?” (Regarding map_mb_recordings_to_tracks)

To keep the frontend clean and entirely ignorant of MusicBrainz-specific logic, this will be a backend Python utility. It will iterate through the raw JSON returned by the MB API and map the required keys directly into ListenBrainz’s JSPF format (e.g., extracting artist-credit to JSPF’s creator, and injecting the recording MBIDs into the JSPF extension dict). The React <Playlist /> component will simply receive standard JSPF data, just with a canEdit={false} flag.

You refined the UI mockup based on community, that is for sure, but not in a good way.

It is completely unacceptable to be plagiarizing another contributors’ proposal, shame on you.
I’m not sure how you thought nobody would notice, but you’re certainly too old for this, there is no excuse.

You will not be selected or further mentored due to your actions.
I will also be reporting this to GSOC as well, and you will not be participating in the GSOC program this year.

You are completely right, and I have absolutely no excuses. I made a terrible, unethical decision to copy another contributor’s mockups and use AI to stitch together parts of this proposal instead of doing the hard work myself.

I deeply apologize to you​:pensive_face:, the MetaBrainz community, and especially the contributor whose work I plagiarized. It was incredibly disrespectful to the open-source process.

I completely accept the consequences of my actions, including being removed from consideration and reported to GSoC. I have learned a harsh but necessary lesson today about integrity. I am truly sorry for wasting the team’s time and violating the community’s trust.