Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"projects": {
|
||||
"default": "offbrandspotifydb"
|
||||
}
|
||||
}
|
||||
BIN
4xnored.png
BIN
4xnored.png
Binary file not shown.
|
Before Width: | Height: | Size: 72 KiB |
@@ -1,151 +0,0 @@
|
||||
# Navidrome Integration Migration
|
||||
|
||||
This project has been migrated from a Firebase-based system with static data to use **Navidrome/Subsonic** as the backend music server.
|
||||
|
||||
## What Changed
|
||||
|
||||
### Removed:
|
||||
- Firebase authentication and database
|
||||
- Static album/artist data files
|
||||
- Custom database URLs and tracklist JSON files
|
||||
|
||||
### Added:
|
||||
- Navidrome/Subsonic API integration
|
||||
- Real-time music streaming
|
||||
- Dynamic music library loading
|
||||
- Album cover art from Navidrome
|
||||
- Playlist management through Navidrome
|
||||
- Star/favorite functionality
|
||||
- Scrobbling support
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
### 1. Install Navidrome
|
||||
|
||||
First, you need to set up a Navidrome server. You can:
|
||||
|
||||
- **Self-host**: Follow the [Navidrome installation guide](https://www.navidrome.org/docs/installation/)
|
||||
- **Docker**: Use the official Docker image
|
||||
- **Pre-built binaries**: Download from GitHub releases
|
||||
|
||||
### 2. Configure Environment Variables
|
||||
|
||||
Copy `.env.example` to `.env.local` and configure your Navidrome server:
|
||||
|
||||
```bash
|
||||
cp .env.example .env.local
|
||||
```
|
||||
|
||||
Edit `.env.local`:
|
||||
```env
|
||||
NEXT_PUBLIC_NAVIDROME_URL=http://localhost:4533
|
||||
NEXT_PUBLIC_NAVIDROME_USERNAME=your_username
|
||||
NEXT_PUBLIC_NAVIDROME_PASSWORD=your_password
|
||||
```
|
||||
|
||||
For production, use your actual Navidrome server URL:
|
||||
```env
|
||||
NEXT_PUBLIC_NAVIDROME_URL=https://your-navidrome-server.com
|
||||
NEXT_PUBLIC_NAVIDROME_USERNAME=your_username
|
||||
NEXT_PUBLIC_NAVIDROME_PASSWORD=your_password
|
||||
```
|
||||
|
||||
### 3. Install Dependencies
|
||||
|
||||
Remove Firebase dependencies and install:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### 4. Run the Application
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
### Music Library
|
||||
- **Albums**: Browse all albums in your Navidrome library
|
||||
- **Artists**: Browse all artists with album counts
|
||||
- **Songs**: Play individual tracks with streaming
|
||||
- **Search**: Search across artists, albums, and songs
|
||||
- **Playlists**: Create and manage playlists
|
||||
|
||||
### Audio Player
|
||||
- **Streaming**: Direct streaming from Navidrome server
|
||||
- **Queue Management**: Add albums/artists to queue
|
||||
- **Scrobbling**: Track listening history
|
||||
- **Controls**: Play, pause, skip, volume control
|
||||
|
||||
### User Features
|
||||
- **Favorites**: Star/unstar albums, artists, and songs
|
||||
- **Playlists**: Create, edit, and delete playlists
|
||||
- **Recently Added**: See newest additions to your library
|
||||
- **Album Artwork**: High quality cover art from Navidrome
|
||||
|
||||
## API Integration
|
||||
|
||||
The app uses the Subsonic API (compatible with Navidrome) with these endpoints:
|
||||
|
||||
- `ping` - Test server connection
|
||||
- `getArtists` - Get all artists
|
||||
- `getAlbums` - Get albums (newest, recent, etc.)
|
||||
- `getAlbum` - Get album details and tracks
|
||||
- `search3` - Search music library
|
||||
- `getPlaylists` - Get user playlists
|
||||
- `stream` - Stream audio files
|
||||
- `getCoverArt` - Get album/artist artwork
|
||||
- `star/unstar` - Favorite items
|
||||
- `scrobble` - Track listening
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
lib/
|
||||
navidrome.ts # Navidrome API client
|
||||
app/
|
||||
components/
|
||||
NavidromeContext.tsx # React context for Navidrome data
|
||||
AudioPlayerContext.tsx # Updated for Navidrome streaming
|
||||
album-artwork.tsx # Updated for Navidrome albums
|
||||
artist-icon.tsx # Updated for Navidrome artists
|
||||
AudioPlayer.tsx # Updated for streaming
|
||||
```
|
||||
|
||||
## Migration Notes
|
||||
|
||||
- **Authentication**: Removed Firebase auth (Navidrome handles users)
|
||||
- **Data Source**: Now uses live music library instead of static JSON
|
||||
- **Streaming**: Direct audio streaming instead of static file URLs
|
||||
- **Cover Art**: Dynamic cover art from Navidrome instead of static images
|
||||
- **Playlists**: Managed through Navidrome instead of static data
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Issues
|
||||
1. Verify Navidrome server is running
|
||||
2. Check URL, username, and password in `.env.local`
|
||||
3. Ensure CORS is properly configured in Navidrome
|
||||
4. Check network connectivity
|
||||
|
||||
### Audio Issues
|
||||
1. Verify audio files are properly imported in Navidrome
|
||||
2. Check browser audio permissions
|
||||
3. Ensure audio codecs are supported
|
||||
|
||||
### Performance
|
||||
1. Navidrome server performance affects loading times
|
||||
2. Consider server location for streaming quality
|
||||
3. Check network bandwidth for audio streaming
|
||||
|
||||
## Development
|
||||
|
||||
The app now uses TypeScript interfaces that match the Subsonic API responses. All components have been updated to work with the new data structure and real-time streaming.
|
||||
|
||||
Key changes:
|
||||
- Album interface now includes Navidrome-specific fields
|
||||
- Artist interface includes album counts and cover art
|
||||
- Song interface includes streaming URLs and metadata
|
||||
- Playlist interface matches Navidrome playlist structure
|
||||
@@ -37,7 +37,7 @@ const Ihateserverside: React.FC<IhateserversideProps> = ({ children }) => {
|
||||
{/* Main Content Area */}
|
||||
<div className="flex-1 flex overflow-hidden">
|
||||
{isSidebarVisible && (
|
||||
<div className="w-64 flex-shrink-0">
|
||||
<div className="w-64 flex-shrink-0 border-r">
|
||||
<Sidebar
|
||||
playlists={playlists}
|
||||
className="h-full overflow-y-auto"
|
||||
|
||||
@@ -84,7 +84,7 @@ export function Menu({ toggleSidebar, isSidebarVisible, toggleStatusBar, isStatu
|
||||
<>
|
||||
<Menubar className="rounded-none border-b border-none px-2 lg:px-4">
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger className="font-bold">offbrand spotify</MenubarTrigger>
|
||||
<MenubarTrigger className="font-bold">mice</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarItem onClick={() => setOpen(true)}>About Music</MenubarItem>
|
||||
<MenubarSeparator />
|
||||
|
||||
@@ -2,48 +2,6 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.text-balance {
|
||||
text-wrap: balance;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 240 10% 3.9%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 240 10% 3.9%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 240 10% 3.9%;
|
||||
--primary: 221.2 83.2% 53.3%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
--secondary: 240 4.8% 95.9%;
|
||||
--secondary-foreground: 240 5.9% 10%;
|
||||
--muted: 240 4.8% 95.9%;
|
||||
--muted-foreground: 240 3.8% 46.1%;
|
||||
--accent: 240 4.8% 95.9%;
|
||||
--accent-foreground: 240 5.9% 10%;
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 240 5.9% 90%;
|
||||
--input: 240 5.9% 90%;
|
||||
--ring: 240 5.9% 10%;
|
||||
--radius: 0.5rem;
|
||||
--chart-1: 12 76% 61%;
|
||||
--chart-2: 173 58% 39%;
|
||||
--chart-3: 197 37% 24%;
|
||||
--chart-4: 43 74% 66%;
|
||||
--chart-5: 27 87% 67%;
|
||||
}
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
@@ -82,9 +40,9 @@ body {
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
--hover: 240 27% 11%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
/* Blue Theme Dark */
|
||||
.theme-blue.dark {
|
||||
--background: 240 10% 3.9%;
|
||||
@@ -107,6 +65,7 @@ body {
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
--ring: 224.3 76.3% 48%;
|
||||
--hover: 240 27% 11%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
/* Violet Theme Dark */
|
||||
@@ -130,36 +89,10 @@ body {
|
||||
--border: 215 27.9% 16.9%;
|
||||
--input: 215 27.9% 16.9%;
|
||||
--ring: 263.4 70% 50.4%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
/* Default dark mode (fallback) */
|
||||
.dark {
|
||||
--background: 240 10% 3.9%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 240 10% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 240 10% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 217.2 91.2% 59.8%;
|
||||
--primary-foreground: 222.2 47.4% 11.2%;
|
||||
--secondary: 217.2 32.6% 17.5%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 217.2 32.6% 17.5%;
|
||||
--muted-foreground: 215 20.2% 65.1%;
|
||||
--accent: 217.2 32.6% 17.5%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 217.2 32.6% 17.5%;
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
--ring: 224.3 76.3% 48%;
|
||||
--chart-1: 220 70% 50%;
|
||||
--chart-2: 160 60% 45%;
|
||||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
--hover: 240 27% 11%;
|
||||
}
|
||||
|
||||
}
|
||||
.dark {
|
||||
--background: 240 10% 3.9%;
|
||||
@@ -187,8 +120,9 @@ body {
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
--hover: 240 27% 11%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ export const viewport: Viewport = {
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: {
|
||||
template: 'offbrand spotify | %s',
|
||||
default: 'offbrand spotify',
|
||||
template: 'mice | %s',
|
||||
default: 'mice',
|
||||
},
|
||||
description: 'a very awesome music streaming service',
|
||||
robots: {
|
||||
|
||||
@@ -2,9 +2,9 @@ import type { MetadataRoute } from 'next'
|
||||
|
||||
export default function manifest(): MetadataRoute.Manifest {
|
||||
return {
|
||||
name: 'Offbrand Spotify',
|
||||
name: 'mice',
|
||||
short_name: 'Offbrand',
|
||||
description: 'a very offbrand spotify clone',
|
||||
description: 'a very mice clone',
|
||||
start_url: '/',
|
||||
categories: ["music", "entertainment"],
|
||||
display_override: ['window-controls-overlay'],
|
||||
|
||||
12
colors.txt
12
colors.txt
@@ -1,12 +0,0 @@
|
||||
border is located at *
|
||||
hsl(214.3deg 3.81% 25%)
|
||||
|
||||
background color in sticky top-0
|
||||
hsl(0deg 0% 5.86%)
|
||||
|
||||
.text muted foreground
|
||||
hsl(0deg 0% 58.47%)
|
||||
|
||||
change in body color
|
||||
hsl(0 0% 100%)
|
||||
|
||||
BIN
preview.png
BIN
preview.png
Binary file not shown.
|
Before Width: | Height: | Size: 483 KiB |
BIN
public/Screenshot 2025-06-19 10.54.18 AM.png
Normal file
BIN
public/Screenshot 2025-06-19 10.54.18 AM.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 370 KiB |
BIN
public/buh.mp3
BIN
public/buh.mp3
Binary file not shown.
Reference in New Issue
Block a user