Files
PlaylistShared/PlaylistShared.Pwa/Services/AudioPlayerService.cs

186 lines
6.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using MudBlazor;
using PlaylistShared.Shared;
using PlaylistShared.Shared.DTO;
using System.Net.Http.Json;
namespace PlaylistShared.Pwa.Services;
public class AudioPlayerService : IAudioPlayerService
{
private readonly TokenStorage _tokenStorage;
private readonly ISnackbar _snackbar;
private readonly HttpClient _http;
private string? _currentTrackId;
private string? _currentTrackTitle;
private string? _currentTrackCoverUrl;
private bool _isPlaying;
private double _currentVolume = 70;
private double _currentProgress;
private string _currentTime = "0:00";
private string _totalTime = "0:00";
public string? CurrentTrackId => _currentTrackId;
public string? CurrentTrackTitle => _currentTrackTitle;
public string? CurrentTrackCoverUrl => _currentTrackCoverUrl;
public bool IsPlaying => _isPlaying;
public double CurrentVolume
{
get => _currentVolume;
set
{
_currentVolume = value;
OnStateChanged?.Invoke();
}
}
public double CurrentProgress => _currentProgress;
public string CurrentTime => _currentTime;
public string TotalTime => _totalTime;
public event Action? OnStateChanged;
public AudioPlayerService(TokenStorage tokenStorage, ISnackbar snackbar, HttpClient httpClient)
{
_tokenStorage = tokenStorage;
_snackbar = snackbar;
_http = httpClient;
}
// Внешние команды (вызываются из компонентов)
public async Task LoadAndPlayAsync(string trackId, string? accessToken = null, string? playlistShareToken = null, string? title = null, string? coverUrl = null)
{
// Если accessToken не передан, пытаемся получить его из хранилища
if (string.IsNullOrWhiteSpace(accessToken))
{
var tokens = await _tokenStorage.GetTokensAsync();
accessToken = tokens.token;
}
// Проверяем, есть ли чем авторизоваться
if (string.IsNullOrWhiteSpace(accessToken) && string.IsNullOrWhiteSpace(playlistShareToken))
{
_snackbar.Add("Не удалось воспроизвести трек: отсутствует токен авторизации или идентификатор расшаренного плейлиста.", Severity.Error);
return;
}
// Если title и coverUrl не переданы, нужно запросить через API
if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(coverUrl))
{
try
{
var trackInfo = await GetTrackInfo(trackId, accessToken, playlistShareToken);
title = trackInfo?.Title;
coverUrl = trackInfo?.CoverUri;
}
catch (Exception ex)
{
// Логируем ошибку, но продолжаем без обложки/названия
Console.WriteLine($"Failed to fetch track info: {ex.Message}");
}
}
_currentTrackId = trackId;
_currentTrackTitle = title ?? "Неизвестный трек";
_currentTrackCoverUrl = coverUrl;
_isPlaying = true;
OnStateChanged?.Invoke();
OnLoadAndPlayRequested?.Invoke(trackId, accessToken, playlistShareToken);
}
public async Task PlayAsync()
{
_isPlaying = true;
OnStateChanged?.Invoke();
OnPlayRequested?.Invoke();
}
public async Task PauseAsync()
{
_isPlaying = false;
OnStateChanged?.Invoke();
OnPauseRequested?.Invoke();
}
public async Task StopAsync()
{
_isPlaying = false;
_currentTrackId = null;
_currentProgress = 0;
_currentTime = "0:00";
OnStateChanged?.Invoke();
OnStopRequested?.Invoke();
}
public async Task SeekToAsync(double percent)
{
OnSeekRequested?.Invoke(percent);
}
public async Task SetVolumeAsync(double volume)
{
_currentVolume = volume;
OnStateChanged?.Invoke();
OnVolumeChangeRequested?.Invoke(volume);
}
// События для связи с реальным AudioPlayer компонентом
public event Func<string, string?, string?, Task>? OnLoadAndPlayRequested;
public event Func<Task>? OnPlayRequested;
public event Func<Task>? OnPauseRequested;
public event Func<Task>? OnStopRequested;
public event Func<double, Task>? OnSeekRequested;
public event Func<double, Task>? OnVolumeChangeRequested;
// Внутренние методы для обновления состояния из AudioPlayer
public void SetPlayingState(bool isPlaying)
{
_isPlaying = isPlaying;
OnStateChanged?.Invoke();
}
public void SetCurrentTrack(string? trackId)
{
_currentTrackId = trackId;
OnStateChanged?.Invoke();
}
public void UpdateProgress(double progress, string currentTime, string totalTime)
{
_currentProgress = progress;
_currentTime = currentTime;
_totalTime = totalTime;
OnStateChanged?.Invoke();
}
public void NotifyTrackEnded()
{
_isPlaying = false;
_currentTrackId = null;
_currentProgress = 0;
_currentTime = "0:00";
OnStateChanged?.Invoke();
}
/// <summary>
/// Вспомогательный метод для получения информации о треке через API
/// </summary>
/// <param name="trackId"></param>
/// <param name="accessToken"></param>
/// <param name="sharedPlaylistId"></param>
/// <returns></returns>
private async Task<(string? Title, string? CoverUri)?> GetTrackInfo(string trackId, string? accessToken, string? sharedPlaylistId)
{
var url = $"/api/audio/track-info/{trackId}";
if (!string.IsNullOrEmpty(accessToken))
url += $"?access_token={accessToken}";
else if (!string.IsNullOrEmpty(sharedPlaylistId))
url += $"?shared_id={sharedPlaylistId}";
var response = await _http.GetFromJsonAsync<ApiResponse<YandexTrack>>(url);
if (response?.Success == true)
{
return (response.Data.Title, response.Data.CoverUri);
}
return null;
}
}