Files
subpy/Navidrome.py
T
0x01FE 0ca2547b54 New Buttons (#5)
Added two new buttons to the player:
 - Favorite song button
 - Queue mode button

Reviewed-on: #5
2025-11-05 13:16:51 -06:00

98 lines
2.7 KiB
Python

import requests
import urllib.parse
import SubSonic
"""
Navidrome has some API endpoints that are not included in the SubSonic or OpenSubSonic standards.
Nor are they documented anywhere I can find, the NavidromeAPI class is a collection of methods to interact with this hidden API.
The endpoints are reverse engineered from observing requests made by the Navidrome WebUI.
"""
class NavidromeAPI:
username: str
password: str
base_url: str
auth_token: str
auth_header: dict = {}
def __init__(self, u: str, p: str, base_url: str):
self.username = u
self.password = p
self.base_url = base_url
self.auth_token = self._login()
self.auth_header['X-Nd-Authorization'] = f"Bearer {self.auth_token}"
def _encodePayload(self, payload: dict) -> str:
return urllib.parse.urlencode(payload, quote_via=urllib.parse.quote_plus)
def _login(self) -> str:
url = self.base_url + '/auth/login'
payload = {
'username': self.username,
'password': self.password
}
response = requests.post(url, json=payload)
j = response.json()
return j['token']
def getAllSongs(self, end: int, start: int, order: str = 'ASC', sort: str = 'title') -> list[SubSonic.Song]:
url = self.base_url + '/api/song?'
payload = {
"_end": end,
"_order": order,
"_sort": sort,
"_start": start
}
response = requests.get(url + self._encodePayload(payload), headers=self.auth_header)
print(len(response.content))
return [SubSonic.Song(song_d) for song_d in response.json()]
def getAlbums(self, end: int, start: int, order: str = 'ACS', sort: str = 'name', name: str | None = None, seed: float | None = None) -> list[SubSonic.Album]:
url = self.base_url + '/api/album?'
payload = {
"_end": end,
"_order": order,
"_sort" : sort,
"_start": start,
"seed": 0.0
}
if seed:
payload['seed'] = seed
if name:
payload['name'] = name
response = requests.get(url + self._encodePayload(payload), headers=self.auth_header)
print(response.content)
return [SubSonic.Album(album_d) for album_d in response.json()]
def getSong(self, id: str):
url = self.base_url + '/api/song?'
payload = {
"id" : id
}
response = requests.get(url + self._encodePayload(payload), headers=self.auth_header)
return response.json()
def isSongStarred(self, id: str) -> bool:
info = self.getSong(id)
return info[0]['starred']