85 lines
2.6 KiB
Dart
85 lines
2.6 KiB
Dart
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();
|
|
}
|
|
}
|