Self-hosted music streaming without barriers.
ResoNode is a self-hosted music streaming platform designed to provide full control over a personal music library. It serves as an alternative to commercial streaming services, allowing users to host their own server and access their music remotely without subscriptions, ads, or data tracking.
Unlike other media servers like Plex or Jellyfin, ResoNode is built with a specific focus on resilience and connection simplicity for users with dynamic IPs.
- Data Sovereignty: You host the MP3 files. The library is not subject to licensing agreements or removals.
- Connection Mechanism: Removes the need for static IPs, dynamic DNS (DDNS), or complex VPN configurations (like WireGuard/Tailscale). It uses a discovery system based on Cloudflare Tunnels and Gmail to locate the server automatically.
- Hybrid Playback:
- Streaming: Plays directly from the server when an internet connection is available.
- Offline Mode: Downloads playlists to local storage. The app manages the local database transparently, switching modes automatically when network connectivity is lost.
- The Vault: An automated file system that organizes uploads by Artist, Album, and Track.
- Legacy Support: Designed with a lightweight interface and a custom TLS 1.2 implementation, ensuring smooth performance even on older hardware (Android 4.4+) used as dedicated media players.
The project consists of two main components:
- Server (Python/FastAPI): Runs on a host machine (Linux/Windows/Mac). Manages the file system, user authentication, and streaming logic.
- Client (Android): A native application optimized for low-latency streaming and offline synchronization.
To bypass carrier-grade NAT (CGNAT) and dynamic IPs without user intervention:
- Tunneling: Upon startup,
server_launcher.pyinitiates a secure Cloudflare Tunnel (cloudflared). - Assignment: Cloudflare assigns a temporary, random public URL (e.g.,
https://random-id.trycloudflare.com). - Broadcasting: The server detects this URL and emails it to a dedicated Gmail account via SMTP.
- Discovery: When the Android app launches, it checks the Gmail inbox via IMAP, retrieves the latest email from the server, and parses the new URL.
- Handshake: The app updates its configuration and establishes the connection.
An integrated, privacy-focused analytics engine designed to track listening habits without third-party data mining. Unlike standard streaming services, this feature is built with a local-first philosophy.
- Offline-Persistent Tracking: Playback history (duration and track counts) is recorded into an internal SQLite database. This ensures that statistics are captured even when using Offline Mode in areas with no connectivity.
- Smart Synchronization: The app's
NetworkReceiverdetects when internet connectivity is restored and automatically pushes unsynced local logs to the server. This merges data from multiple devices into a single user profile. - Privacy & Community: The feature is strictly opt-in. Users have full control over their data visibility via Settings:
- OFF (Default): The app simply does not record any data.
- Private Mode: Statistics are strictly for personal viewing.
- Public Mode: Users can opt-in to a server-wide leaderboard to compare listening times with other members of the instance.
- Python 3.8 or higher.
- Cloudflared: The Cloudflare tunnel daemon must be installed and available in the system PATH.
- Gmail Account: A dedicated account is recommended for the handshake process. App Passwords must be enabled.
-
Install Dependencies:
pip install fastapi uvicorn python-multipart mutagen requests
-
Configuration:
- Navigate to the
server/directory. - Locate
server_config_example.py. - Rename it to
server_config.py(this file is git-ignored to prevent credential leakage). - Edit the file with your credentials:
API_SECRET_KEY = "YOUR_SECURE_KEY" # Must match the key in the Android App GMAIL_USER = "your_email@gmail.com" GMAIL_PASS = "your_app_password" DESTINATION_EMAIL = "destination_email@gmail.com" PORT = 8000
- Navigate to the
-
Run the Server: Execute the launcher script from within the server directory. This will start the API, initialize the tunnel, and send the connection email.
cd server python server_launcher.py
- Open the project in Android Studio.
- Security Configuration:
- Navigate to
app/src/main/java/com/example/resonode/. - Modify the file named
Config.javausing it as a template. - Fill in the required fields:
API_SECRET_KEY: Must match the server key exactly.GMAIL_EMAIL/PASSWORD: Credentials used to read the connection email.
- Navigate to
- Build: compile the APK and install it on the target device.
ResoNode includes a user-friendly helper script to upload your local music library to your server without technical hassles.
- Ensure your server is running.
- Run the uploader script from the project root:
python music_uploader.py
- Follow the interactive wizard:
- Select Source: Drag and drop your local music folder containing
.mp3files into the terminal window. - Select Environment: Choose whether you are at home (Local IP) or away (Cloudflare Tunnel).
- Select Destination: (Optional) Choose a specific playlist folder on the server to link the music to.
- Select Source: Drag and drop your local music folder containing
The script automatically filters for MP3s, creates a ZIP package, and handles the upload process for you.
If you prefer to build your own tools or integrations, the server exposes the following endpoint:
- URL:
/upload_zip - Method:
POST - Headers:
x-secret-key: [YOUR_API_SECRET_KEY] - Body (Multipart/Form-Data):
file: A.zipfile containing valid MP3s.target_playlist: (Optional) Name of a subfolder/playlist.
ResoNode includes a built-in Over-The-Air update mechanism. You don't need to manually copy APKs to your phone.
- Check: Every time the App opens, it queries
/update/check. - Compare: It compares the server's
version.jsonwith the installed app version. - Install: If a newer version is found, it downloads and prompts the user to install it.
If you ever want to experiment and modify this app, feel free to do it! A helper script deploy_tool.py is included to automate this process.
- Build: Generate a Signed APK in Android Studio (
Build > Generate Signed Bundle / APK > APK > Debug/Release). - Run: Execute the tool from the project root:
python deploy_tool.py
- Follow the wizard:
- It detects the latest APK automatically.
- Enter the new Version Code (must be higher than current).
- Enter the Changelog.
- Select Mode:
[1] SSH/SCP: For local network deployment (requires SSH access).[2] HTTP Upload: Deploys via the Cloudflare Tunnel. Useful if you are coding away from home.
This project is a proof of concept regarding media streaming and network traversal. Users are responsible for ensuring they have the legal rights to the media files hosted, streamed, and downloaded on their private servers.






