first commit
This commit is contained in:
84
lib/features/music/data/services/music_service.dart
Normal file
84
lib/features/music/data/services/music_service.dart
Normal file
@@ -0,0 +1,84 @@
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
import '../../domain/models/track_model.dart';
|
||||
|
||||
class MusicService {
|
||||
const MusicService(this._client);
|
||||
|
||||
final SupabaseClient _client;
|
||||
|
||||
User get _currentUser {
|
||||
final user = _client.auth.currentUser;
|
||||
if (user == null) {
|
||||
throw StateError('No authenticated user');
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
/// Uploads a new track with an MP3 file and metadata.
|
||||
Future<void> uploadTrack({
|
||||
required Uint8List bytes,
|
||||
required String title,
|
||||
required String genreTag,
|
||||
required String extension,
|
||||
}) async {
|
||||
final user = _currentUser;
|
||||
final ts = DateTime.now().millisecondsSinceEpoch;
|
||||
final random = Random().nextInt(99999);
|
||||
final fileName = '$ts-$random.$extension';
|
||||
final path = 'tracks/${user.id}/$fileName';
|
||||
|
||||
// Upload audio to Supabase Storage
|
||||
await _client.storage.from('tracks').uploadBinary(
|
||||
path,
|
||||
bytes,
|
||||
fileOptions: const FileOptions(upsert: false),
|
||||
);
|
||||
|
||||
final audioUrl = _client.storage.from('tracks').getPublicUrl(path);
|
||||
|
||||
// Insert track record into PostgreSQL
|
||||
await _client.from('tracks').insert({
|
||||
'user_id': user.id,
|
||||
'title': title.trim().isEmpty ? 'UNTITLED' : title.trim().toUpperCase(),
|
||||
'audio_url': audioUrl,
|
||||
'genre_tag': genreTag.trim().isEmpty ? 'UNKNOWN' : genreTag.trim().toUpperCase(),
|
||||
'plays': 0,
|
||||
});
|
||||
}
|
||||
|
||||
/// Lists all tracks in chronological order.
|
||||
Future<List<TrackModel>> fetchTracks() async {
|
||||
final response = await _client
|
||||
.from('tracks')
|
||||
.select('*, profiles(username)')
|
||||
.order('created_at', ascending: false);
|
||||
|
||||
return List<Map<String, dynamic>>.from(response).map((row) {
|
||||
final username = (row['profiles'] as Map<String, dynamic>?)?['username'] as String?;
|
||||
return TrackModel.fromJson(row, username: username);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
/// Increments the play count of a track.
|
||||
Future<void> incrementPlays(String trackId) async {
|
||||
await _client.rpc('increment_track_plays', params: {'track_id': trackId});
|
||||
}
|
||||
|
||||
/// Fetches tracks for a specific user.
|
||||
Future<List<TrackModel>> fetchUserTracks(String userId) async {
|
||||
final response = await _client
|
||||
.from('tracks')
|
||||
.select('*, profiles(username)')
|
||||
.eq('user_id', userId)
|
||||
.order('created_at', ascending: false);
|
||||
|
||||
return List<Map<String, dynamic>>.from(response).map((row) {
|
||||
final username = (row['profiles'] as Map<String, dynamic>?)?['username'] as String?;
|
||||
return TrackModel.fromJson(row, username: username);
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user