GSOC 2025: Integrate music streaming from Subsonic

About Me

Name: Mohammad Amanullah

Matrix Handle: @m.amanullah7:matrix.org

IRC Nickname: m.amanullah7

Time Zone: UTC+5:30

Email: ullahaman072003@gmail.com

GitHub: mAmanullah7 (Mohammad Amanullah) · GitHub

LeetCode: https://leetcode.com/u/m_amanullah7/

I’m Mohammad Amanullah, currently a pre final year student at National Institute of Technology Agartala and along with that i’m a diploma level student at Indian Institute of Technology Madras. My coding journey started in jan 2023 just few month after joining college, my journey started with c college course , then i decided to shift c++ as i was interested

in competitive programming(cp), and slowly i started enjoying doing cp, in second year python course introduced and i loved python other than any other language, and after that a new course and project introduced “MAD1” (modern application development) in which my techstack was Flask, jinja2, bootstrap,js this how my development journey started and in this course project i scored 100/100 S grade.

Other than my academic i’m leading weCan a social club NIT Agartala, student led non profit organisation working toward the empowerment of underprivileged children through education

When i’m not either coding and not in weCan then i must be playing Cricket, Football or listening songs on loudspeaker, sometimes i also play BGMI and i’m not big fan of movies until unless its science fiction


Why Me?

The strongest thing about me is my problem solving skills as a cp. I get intuition very fast and even if I don’t have knowledge or its the first time I’m seeing it then I learn very fast as my never give up attitude never lets me give up.

In the past few months i’m familiarized with listenbrainz codebase, and trying to contribute as much as i can. In this period i’ve interacted with mentors in community and they helped me to throughout the time and i learned a lot.

My PR

PR #3233: 404 Error Fix in explore.py: Improved error handling for the “Music Neighborhood” page.

The root cause was that the fetchone() method returned None when the database query didn’t find any matching records, likely because the artist name or ID I was searching for didn’t exist in the database


Proposed Project

Project: Integrate Music Streaming from Subsonic

Proposed mentor: Lucifer/Mayhem

Project length: 175 hours

Allow users to play music from their Subsonic servers (e.g., Navidrome) directly in BrainzPlayer. There are mainly 3 core functionalities which I need to solve:

  • Backend: SubsonicService class that will handle Subsonic API calls and a subsonic_servers table which will save user credentials.

  • Frontend: Will create a React form in the Connect Services section for users to input their Subsonic server details.

  • BrainzPlayer Integration: For this I need to create a SubsonicPlayer class to BrainzPlayer so users can search and stream tracks, and we also need to take care of proper state management.

For better view u can see here:

Implementation

Db Schema: subsonic_servers table to store Subsonic credentials, which should support multiple servers per user


CREATE TABLE subsonic_servers (

user_id INTEGER NOT NULL, #Link Subsonic server to a LB user.

username TEXT NOT NULL, #for authentication

password TEXT NOT NULL,

host_url TEXT NOT NULL, #URL of the Subsonic server

PRIMARY KEY (user_id, host_url) #combination of user_id and host_url must be unique.

);

Will add this table via a migration and I need to create a function in db/subsonic.py which will save and retrieve server details.

Class Changes in db/subsonic.py:


# listenbrainz/db/subsonic.py

def save_subsonic_server(user_id, username, password, host_url):

"""Save a Subsonic server for a user."""

# Logic will update soon

pass

def get_subsonic_servers(user_id):

"""# Logic will update soon."""

# Logic to query subsonic_servers table

pass

Then I need to Implement a SubsonicService class in domain/subsonic_services.py which will handle Subsonic API calls.

For Authentication will use MD5 hashing with per-request salts (md5(password + salt)),

eg - GET <host>/rest/ping.view?u=user&t=token&s=salt&v=1.13.0&c=listenbrainz.

For Search will use search2.view to find the tracks by title and artist.

Class Changes in domain/subsonic_services.py:


# listenbrainz/domain/subsonic_services.py

class SubsonicService:

def __init__(self, user_id):

"""Initialize with user_id and load server details."""

pass

def authenticate(self, password, salt):

"""Generate MD5 hash for authentication."""

pass

def ping(self):

"""Validate Subsonic server connection using ping.view."""

pass

def search(self, title, artist):

"""Search for tracks using search2.view."""

pass

def stream(self, track_id):

"""Get stream URL using stream.view."""

pass

Frontend: Will create a React form in the Connect Services[link: ListenBrainz] section for users to input their Subsonic server details. The form will include fields for host URL, username, and password, a “Play music on ListenBrainz” button to connect, and a “Disable” button to disconnect. After submission, it will display a success or error message.

We need to take care of State Management as well

For Track : const [currentTrack, setCurrentTrack] = useState<Track | null>(null) which will store title, artist, and duration.

Will use audio.currentTime for the current position and audio.duration for the total length.
Update a progress bar with audio.addEventListener("timeupdate", () => setProgress(audio.currentTime / audio.duration * 100)).

Handle track completion with audio.addEventListener("ended", () => onTrackEnd()).

When a track is played 40-50% (not sure) of its duration,then we need to submit a listen to /1/submit-listens. I’ll use the MusicBrainz API to match the track and get its MBID for accurate recording.

Class added in `MusicServices.tsx:


// frontend/js/src/settings/music-service/details/MusicServices.tsx

import React, { useState } from 'react';

const SubsonicSettings: React.FC = () => {

const [hostUrl, setHostUrl] = useState('');

const [username, setUsername] = useState('');

const [password, setPassword] = useState('');

const [message, setMessage] = useState('');

const handleConnect = async () => {

// Logic will update soon

};

const handleDisable = () => {

// Logic will update soon

};

return (

<div className="service-section">

<h2>Subsonic</h2>

<p>Connect to your Subsonic server to play music on ListenBrainz.</p>

{/* Form fields and buttons */}

</div>

);

};

export default SubsonicSettings;

BrainzPlayer Integration: For this I need to create a SubsonicPlayer class to BrainzPlayer so users can search and stream tracks, and we also need to take care of proper state management. I’ll add the SubsonicPlayer class to the existing BrainzPlayer.tsx without creating a new page.

Class Changes in BrainzPlayer.tsx:


// frontend/js/src/brainzplayer/BrainzPlayer.tsx

class SubsonicPlayer {

private subsonicService: SubsonicService;

constructor(subsonicService: SubsonicService) {

this.subsonicService = subsonicService;

}

async searchTrack(title: string, artist: string) {

// Logic will update soon

}

async streamTrack(trackId: string) {

// Logic will update soon

}

}

// Update BrainzPlayer to include SubsonicPlayer

class BrainzPlayer extends React.Component {

// Logic will update soon

private subsonicPlayer: SubsonicPlayer;

// Logic will update soon

}

Timeline (12 Weeks, 175 Hours)
  • Week 1 (10h): Set up a local Navidrome server for testing and finalize Subsonic API research.

  • Weeks 2-3: i’ll create the subsonic_servers table, set up the listenbrainz/domain/subsonic_services.py file, and implement the SubsonicService class. And will ddd the /api/subsonic-config endpoint.

  • Weeks 4-5: will add the component and embed it into the existing MusicServices.tsx page, integrating it with /api/subsonic-config.

  • Weeks 6-8: Will add the SubsonicPlayer class to BrainzPlayer.tsx, implement search and streaming, and handle state management.

  • Weeks 9-10: Write unit tests (backend and frontend), document the feature in ListenBrainz’s docs.

  • Weeks 11-12 buffer time: will be fixing bugs any changes required,new features, review, submission blogs etc.

Community Affinities

What type of music do you listen to? (please list a series of MBIDs as examples)

I mostly love to listen song like pop, rock and sad and love

I love how ListenBrainz helps me track all my listening at one place and its open source also.


Programming Precedents

When did you first start programming?
My coding journey started in jan 2023 just few month after joining college, my journey started with c college course , then i decided to shift c++ as i was interested in competitive programming(cp)

Have you contributed to other open source projects? If so, which projects and can we see some of your code?
No listenBrainz is my first open source in which i have contributed

If you have not contributed to open source projects, do you have other code we can look at?

I’ve created various project but most and also working on some project my recent project
In which i got perfect 100/100 s grade
HousehelpHub https://github.com/mAmanullah7/HouseHelp-Hub
Live : https://amanullah7.pythonanywhere.com/

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

Ive done various different types of projects over different periods of time like HousehelpHub, Fitometer, sehatGPT, EventEase, these projects gives me edge of working on different languages and can learn new tech very fast


Practical Requirements

I currently use a M1 Macbook Air, 8GB RAM, 512GB SSD.

How much time are you available weekly, and how would you plan to use it?

In summer break, I can easily work 30-40 hours a week for the project as I won’t have any other commitments.

NOTE: just an overiew there are some chnages still left!!

2 Likes

Hi,

GSoC proposals should be under the GSoC applications community; please move this post there if you would like it to be considered for GSoC.

Thanks @julian45 for pointing out it’s updated now!

Thanks @chaban for moving my proposal to Gsoc Section really appreciate it!