🎉 Initial commit: AudiOhm - Alternative à Spotify avec streaming YouTube
Features: - Frontend Flutter avec thème néon cyberpunk - Backend FastAPI avec streaming YouTube - Base de données PostgreSQL + Redis - Authentification JWT complète - Recherche multi-source (DB + YouTube) - Playlists CRUD avec drag & drop - Queue management - Settings avec audio quality - Interface adaptative (Desktop + Mobile) Tech Stack: - Frontend: Flutter 3.2+, Riverpod - Backend: Python 3.11+, FastAPI - Database: PostgreSQL 15+ - Cache: Redis 7+ - Streaming: yt-dlp + FFmpeg 🚀 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
/// Library Provider - Library state management
|
||||
library;
|
||||
|
||||
import 'dart:async';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../../infrastructure/datasources/remote/playlist_api_service.dart';
|
||||
import '../../../infrastructure/datasources/remote/music_api_service.dart';
|
||||
import '../../../domain/entities/playlist.dart';
|
||||
import '../../../domain/entities/track.dart';
|
||||
import '../../../domain/entities/album.dart';
|
||||
import '../../../domain/entities/artist.dart';
|
||||
|
||||
/// Library state
|
||||
class LibraryState {
|
||||
final List<Playlist> playlists;
|
||||
final List<Track> likedSongs;
|
||||
final List<Album> savedAlbums;
|
||||
final List<Artist> followedArtists;
|
||||
final bool isLoading;
|
||||
final String? error;
|
||||
|
||||
const LibraryState({
|
||||
this.playlists = const [],
|
||||
this.likedSongs = const [],
|
||||
this.savedAlbums = const [],
|
||||
this.followedArtists = const [],
|
||||
this.isLoading = false,
|
||||
this.error,
|
||||
});
|
||||
|
||||
LibraryState copyWith({
|
||||
List<Playlist>? playlists,
|
||||
List<Track>? likedSongs,
|
||||
List<Album>? savedAlbums,
|
||||
List<Artist>? followedArtists,
|
||||
bool? isLoading,
|
||||
String? error,
|
||||
}) {
|
||||
return LibraryState(
|
||||
playlists: playlists ?? this.playlists,
|
||||
likedSongs: likedSongs ?? this.likedSongs,
|
||||
savedAlbums: savedAlbums ?? this.savedAlbums,
|
||||
followedArtists: followedArtists ?? this.followedArtists,
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
error: error,
|
||||
);
|
||||
}
|
||||
|
||||
int get totalItems => playlists.length + likedSongs.length + savedAlbums.length + followedArtists.length;
|
||||
}
|
||||
|
||||
/// Library notifier
|
||||
class LibraryNotifier extends StateNotifier<LibraryState> {
|
||||
LibraryNotifier(this._playlistApiService, this._musicApiService)
|
||||
: super(const LibraryState());
|
||||
|
||||
final PlaylistApiService _playlistApiService;
|
||||
final MusicApiService _musicApiService;
|
||||
|
||||
Future<void> loadLibrary() async {
|
||||
state = state.copyWith(isLoading: true, error: null);
|
||||
|
||||
try {
|
||||
// Load playlists in parallel
|
||||
final results = await Future.wait([
|
||||
_loadPlaylists(),
|
||||
// TODO: Implement these endpoints when backend is ready
|
||||
// _loadLikedSongs(),
|
||||
// _loadSavedAlbums(),
|
||||
// _loadFollowedArtists(),
|
||||
]);
|
||||
|
||||
state = LibraryState(
|
||||
playlists: results[0] as List<Playlist>,
|
||||
likedSongs: [],
|
||||
savedAlbums: [],
|
||||
followedArtists: [],
|
||||
);
|
||||
} catch (e) {
|
||||
state = LibraryState(
|
||||
playlists: state.playlists,
|
||||
likedSongs: state.likedSongs,
|
||||
savedAlbums: state.savedAlbums,
|
||||
followedArtists: state.followedArtists,
|
||||
error: e.toString(),
|
||||
);
|
||||
} finally {
|
||||
state = state.copyWith(isLoading: false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<Playlist>> _loadPlaylists() async {
|
||||
final playlistsJson = await _playlistApiService.getPlaylists();
|
||||
return playlistsJson
|
||||
.map((json) => Playlist.fromJson(json as Map<String, dynamic>))
|
||||
.toList();
|
||||
}
|
||||
|
||||
Future<void> addLikedSong(Track track) async {
|
||||
// TODO: Implement when backend endpoint is ready
|
||||
final updated = [...state.likedSongs, track];
|
||||
state = state.copyWith(likedSongs: updated);
|
||||
}
|
||||
|
||||
Future<void> removeLikedSong(String trackId) async {
|
||||
// TODO: Implement when backend endpoint is ready
|
||||
final updated = state.likedSongs.where((t) => t.id != trackId).toList();
|
||||
state = state.copyWith(likedSongs: updated);
|
||||
}
|
||||
|
||||
Future<void> addSavedAlbum(Album album) async {
|
||||
// TODO: Implement when backend endpoint is ready
|
||||
final updated = [...state.savedAlbums, album];
|
||||
state = state.copyWith(savedAlbums: updated);
|
||||
}
|
||||
|
||||
Future<void> removeSavedAlbum(String albumId) async {
|
||||
// TODO: Implement when backend endpoint is ready
|
||||
final updated = state.savedAlbums.where((a) => a.id != albumId).toList();
|
||||
state = state.copyWith(savedAlbums: updated);
|
||||
}
|
||||
|
||||
Future<void> followArtist(Artist artist) async {
|
||||
// TODO: Implement when backend endpoint is ready
|
||||
final updated = [...state.followedArtists, artist];
|
||||
state = state.copyWith(followedArtists: updated);
|
||||
}
|
||||
|
||||
Future<void> unfollowArtist(String artistId) async {
|
||||
// TODO: Implement when backend endpoint is ready
|
||||
final updated = state.followedArtists.where((a) => a.id != artistId).toList();
|
||||
state = state.copyWith(followedArtists: updated);
|
||||
}
|
||||
|
||||
Future<void> deletePlaylist(String playlistId) async {
|
||||
await _playlistApiService.deletePlaylist(playlistId);
|
||||
final updated = state.playlists.where((p) => p.id != playlistId).toList();
|
||||
state = state.copyWith(playlists: updated);
|
||||
}
|
||||
|
||||
Future<void> createPlaylist({
|
||||
required String name,
|
||||
String? description,
|
||||
String? imageUrl,
|
||||
bool isPublic = false,
|
||||
}) async {
|
||||
final playlistJson = await _playlistApiService.createPlaylist(
|
||||
name: name,
|
||||
description: description,
|
||||
imageUrl: imageUrl,
|
||||
isPublic: isPublic,
|
||||
);
|
||||
final playlist = Playlist.fromJson(playlistJson as Map<String, dynamic>);
|
||||
final updated = [...state.playlists, playlist];
|
||||
state = state.copyWith(playlists: updated);
|
||||
}
|
||||
|
||||
Future<void> refresh() async {
|
||||
await loadLibrary();
|
||||
}
|
||||
}
|
||||
|
||||
/// Library provider
|
||||
final libraryProvider = StateNotifierProvider<LibraryNotifier, LibraryState>((ref) {
|
||||
final playlistApiService = ref.watch(playlistApiServiceProvider);
|
||||
final musicApiService = ref.watch(musicApiServiceProvider);
|
||||
return LibraryNotifier(playlistApiService, musicApiService);
|
||||
});
|
||||
Reference in New Issue
Block a user