public async Task <AffectedViewersDto> Handle(DeletePlaylistCommand request, CancellationToken cancellationToken) { try { using var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled); var room = await _roomRepository.GetAsync(request.RoomId, cancellationToken) ?? throw new ArgumentException("Room could not be found"); var playlist = await _playlistRepository.GetAsync(room.ActivePlaylistId.Value, cancellationToken) ?? throw new ArgumentException("Playlist could not be found"); var viewer = await _viewerRepository.GetAsync(request.MemberId, cancellationToken) ?? throw new ArgumentException("Viewer could not be found"); if (!playlist.Owner.Equals(viewer)) { throw new InformativeException("Playlist does not belong to you"); } await _playlistRepository.DeleteAsync(playlist.Id, cancellationToken); var remainingPlaylists = await _playlistRepository.GetAllByViewerAsync(request.MemberId, cancellationToken); if (remainingPlaylists == null || remainingPlaylists.Count == 0) { var newPlaylistId = _identifierProvider.GenerateGuid(); var newPlaylist = new Playlist(newPlaylistId, "Temporary", viewer); await _playlistRepository.AddAsync(newPlaylist, cancellationToken); room.UpdateSelectedPlaylist(newPlaylist); } else { room.UpdateSelectedPlaylist(remainingPlaylists.First()); } await _roomRepository.UpdateAsync(room, cancellationToken); transaction.Complete(); var affectedViewers = room.Viewers.ToList(); affectedViewers.Add(room.Host); return(_mapper.Map <AffectedViewersDto>(affectedViewers)); } catch (InformativeException exception) { _logger.LogError(exception, $"Could not delete playlist {request.RoomId.ToString()} by member " + $"{request.MemberId.ToString()}"); throw; } catch (Exception exception) { _logger.LogError(exception, $"Could not delete playlist {request.RoomId.ToString()} by member " + $"{request.MemberId.ToString()}"); throw new InformativeException("Could not delete playlist. Please retry"); } }
public async Task <PlaylistDto> Handle(GetPlaylistQuery request, CancellationToken cancellationToken) { try { var room = await _roomRepository.GetAsync(request.RoomId, cancellationToken) ?? throw new InformativeException("Room could not be found"); if (!room.IsPlaylistSelected) { throw new InformativeException("There is no playlist in the room"); } var playlist = await _playlistRepository.GetAsync(room.ActivePlaylistId.Value, cancellationToken); var availablePlaylists = await _playlistRepository.GetAllByViewerAsync( room.Host.Profile.Id, cancellationToken); var dto = _mapper.Map <PlaylistDto>(playlist); dto.AvailablePlaylists = _mapper.Map <IList <SelectablePlaylistDto> >(availablePlaylists); return(dto); } catch (Exception exception) { _logger.LogError(exception, $"Could not get playlist {request.RoomId}"); throw new InformativeException("Could not get playlist. Please retry"); } }
public async Task <AffectedViewersDto> Handle(ChangeActivePlaylistCommand request, CancellationToken cancellationToken) { try { using var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled); var room = await _roomRepository.GetAsync(request.RoomId, cancellationToken) ?? throw new ArgumentException("Room could not be found"); var newPlaylist = await _playlistRepository.GetAsync(request.PlaylistId, cancellationToken) ?? throw new ArgumentException("New playlist could not be found"); room.UpdateSelectedPlaylist(newPlaylist); if (room.IsPlaylistSelected) { var previousPlaylist = await _playlistRepository.GetAsync(room.ActivePlaylistId.Value, cancellationToken) ?? throw new InvalidOperationException( "Previous active playlist could not be found"); if (previousPlaylist.IsTemporary) { await _playlistRepository.DeleteAsync(previousPlaylist.Id, cancellationToken); } } await _roomRepository.UpdateAsync(room, cancellationToken); transaction.Complete(); var affectedViewers = room.Viewers.ToList(); affectedViewers.Add(room.Host); return(_mapper.Map <AffectedViewersDto>(affectedViewers)); } catch (InformativeException exception) { _logger.LogError(exception, $"Could not change active playlist in room {request.RoomId.ToString()}"); throw; } catch (Exception exception) { _logger.LogError(exception, $"Could not change active playlist in room {request.RoomId.ToString()}"); throw new InformativeException("Could not change active playlist in room. Please retry"); } }
public async Task <Unit> Handle(SavePlaylistCommand request, CancellationToken cancellationToken) { try { using var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled); var room = await _roomRepository.GetAsync(request.RoomId, cancellationToken) ?? throw new ArgumentException("Room could not be found"); var viewer = await _viewerRepository.GetAsync(request.ViewerId, cancellationToken) ?? throw new ArgumentException("Viewer could not be found"); if (!room.Viewers.Contains(viewer)) { throw new InvalidOperationException("Viewer does not belong to this room"); } var activePlaylist = await _playlistRepository.GetAsync(room.ActivePlaylistId.Value, cancellationToken) ?? throw new ArgumentException("Playlist could not be found"); if (activePlaylist.Owner == viewer) { if (!activePlaylist.IsTemporary) { throw new InvalidOperationException("Playlist is added already"); } activePlaylist.IsTemporary = false; } else { Guid newPlaylistId = _identifierProvider.GenerateGuid(); activePlaylist = CreatePlaylistCopy(newPlaylistId, viewer, activePlaylist); } await _playlistRepository.AddAsync(activePlaylist, cancellationToken); transaction.Complete(); return(Unit.Value); } catch (InformativeException exception) { _logger.LogError(exception, $"Could not add playlist {request.RoomId.ToString()} " + $"to host of room {request.RoomId.ToString()}"); throw; } catch (Exception exception) { _logger.LogError(exception, $"Could not add playlist {request.RoomId.ToString()} " + $"to host of room {request.RoomId.ToString()}"); throw new InformativeException("Could not add playlist. Please retry"); } }
public async Task <IList <Playlist> > GetPlaylistsAsync() { using (_busyStack.GetToken()) { var items = await _playlistRepository.GetAsync() .ConfigureAwait(true); return(items.Select(p => _playlistMapper.Get(p)) .ToList()); } }
public async Task <AffectedViewersDto> Handle(SwitchContentCommand request, CancellationToken cancellationToken) { try { using var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled); var room = await _roomRepository.GetAsync(request.RoomId, cancellationToken) ?? throw new InvalidOperationException($"Room {request.RoomId.ToString()} does not exist"); var playlist = await _playlistRepository.GetAsync(room.ActivePlaylistId.Value, cancellationToken) ?? throw new InvalidOperationException($"Playlist {room.ActivePlaylistId.ToString()} " + $"does not exist"); ContentId contentId; if (playlist.Contains(room.CurrentContent?.ContentId)) { contentId = request.Direction == SwitchContentDirection.Next ? playlist.GetNextContent(room.CurrentContent?.ContentId) : playlist.GetPreviousContent(room.CurrentContent?.ContentId); } else { contentId = playlist.FirstOrDefault()?.ContentId; } room.CurrentContent = new CurrentContent( contentId, ContentPlayerState.Paused, playingTime: 0, lastUpdatedPlayingTime: DateTime.Now); await _roomRepository.UpdateAsync(room, cancellationToken); transaction.Complete(); var affectedViewers = room.Viewers.ToList(); affectedViewers.Add(room.Host); return(_mapper.Map <AffectedViewersDto>(affectedViewers)); } catch (InformativeException exception) { _logger.LogError(exception, $"Could not play next content from active playlist of " + $"room {request.RoomId.ToString()}"); throw; } catch (Exception exception) { _logger.LogError(exception, $"Could not play next content from active playlist of " + $"room {request.RoomId.ToString()}"); throw new InformativeException("Could not play next content from the playlist. Please retry"); } }
public async Task AddAsync(string url, string author, string title, Guid playlistId) { var playlist = await _playlistRepository.GetAsync(playlistId); if (playlist == null) { throw new Exception($"Playlist with id: '{playlistId}' does not exists"); } var song = new Song(url, author, title, playlistId); await _songRepository.AddAsync(song); }
public async Task <AffectedViewersDto> Handle(RemoveContentFromPlaylistCommand request, CancellationToken cancellationToken) { try { using var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled); var room = await _roomRepository.GetAsync(request.CurrentRoomId, cancellationToken) ?? throw new ArgumentException( $"Room {request.CurrentRoomId.ToString()} could not be found"); var activePlaylist = await _playlistRepository.GetAsync(room.ActivePlaylistId.Value, cancellationToken) ?? throw new InvalidOperationException( $"Playlist {room.ActivePlaylistId.ToString()} " + $"could not be found"); var contentId = _mapper.Map <ContentId>(request.ContentId); if (contentId.Equals(room.CurrentContent?.ContentId)) { throw new InformativeException("Could not remove currently playing content."); } activePlaylist.Remove(contentId); await _playlistRepository.UpdateAsync(activePlaylist, cancellationToken); transaction.Complete(); var affectedUsers = room.Viewers.ToList(); affectedUsers.Add(room.Host); return(_mapper.Map <AffectedViewersDto>(affectedUsers)); } catch (InformativeException exception) { _logger.LogError(exception, $"Could not remove content {request.ContentId} from active playlist of " + $"room {request.CurrentRoomId.ToString()}"); throw; } catch (Exception exception) { _logger.LogError(exception, $"Could not remove content {request.ContentId} from active playlist of " + $"room {request.CurrentRoomId.ToString()}"); throw new InformativeException("Could not remove content from the playlist. Please retry"); } }
public async Task <Unit> Handle(CloseRoomCommand request, CancellationToken cancellationToken) { try { using var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled); var room = await _roomRepository.GetAsync(request.RoomId, cancellationToken) ?? throw new ArgumentException("Room could not be found"); if (room.Host.Profile.Id != request.MemberId) { throw new InformativeException("Member does not have permission"); } if (room.IsPlaylistSelected) { var activePlaylist = await _playlistRepository.GetAsync(room.ActivePlaylistId.Value, cancellationToken) ?? throw new ArgumentException("Active playlist could not be found"); if (activePlaylist.IsTemporary) { await _playlistRepository.DeleteAsync(activePlaylist.Id, cancellationToken); } } await _roomRepository.DeleteAsync(room.Id, cancellationToken); transaction.Complete(); return(Unit.Value); } catch (InformativeException exception) { _logger.LogError(exception, $"Could not close room {request.RoomId.ToString()}"); throw; } catch (Exception exception) { _logger.LogError(exception, $"Could not close room {request.RoomId.ToString()}"); throw new InformativeException("Could not close room. Please retry"); } }
// [MaximumConcurrentExecutions(1)] // [DisableConcurrentExecution(timeoutInSeconds: 60 * 60 * 2)] public async Task <bool> Execute(ParsedItemResult item, Guid playlistId, PerformContext context) { _setContext(context); if (item is null || string.IsNullOrEmpty(item.VideoType)) { return(false); } Log($"Starting process item:\n\t{item.Id}\n\t{item.Title}\n\thttps://www.youtube.com/watch?v={item.Id}"); var playlist = await _playlistRepository.GetAsync(playlistId); var url = item.VideoType.ToLower().Equals("youtube") ? $"https://www.youtube.com/watch?v={item.Id}" : item.VideoType.Equals("mixcloud") ? $"https://mixcloud.com/{item.Id}" : string.Empty; if (string.IsNullOrEmpty(url)) { LogError($"Unknown video type for ParsedItem: {item.Id} - {playlist.Id}"); } else { Log($"Getting info"); var info = await _audioDownloader.GetInfo(url, playlist.Podcast.AppUserId); if (info != RemoteUrlType.Invalid) { Log($"URL is valid"); var podcast = await _podcastRepository.GetAsync(playlist.PodcastId); var uid = Guid.NewGuid(); Log($"Downloading audio"); var localFile = Path.Combine(Path.GetTempPath(), $"{System.Guid.NewGuid()}.mp3"); try { var entry = new PodcastEntry { SourceUrl = url, ProcessingStatus = ProcessingStatus.Uploading, Playlist = playlist, Podcast = podcast }; await _processor.GetInformation(entry, podcast.AppUserId); podcast.PodcastEntries.Add(entry); await _unitOfWork.CompleteAsync(); var result = await _preProcessor.PreProcessEntry(podcast.AppUser, entry); return(result == EntryProcessResult.Succeeded); } catch (AudioDownloadException e) { //TODO: we should mark this as failed //so we don't continuously process it LogError(e.Message); } } else { LogError($"Processing playlist item {item.Id} failed"); return(false); } } return(true); }
public async Task <bool> Execute(Guid playlistId, PerformContext context) { Log($"Starting playlist processing for {playlistId}"); context.WriteLine($"Starting playlist processing for {playlistId}"); try { var playlist = await _playlistRepository.GetAsync(playlistId); var cutoffDate = await _playlistRepository.GetCutoffDate(playlistId); var user = playlist.Podcast.AppUser; //first check user has a valid subscription var subs = user.GetCurrentSubscription(); var isGod = await _userManager.IsInRoleAsync(user, "god-mode"); if (subs is null && !isGod) { LogWarning($"User: {user.Id} does not have a valid subscription"); return(false); } //next check quotas Log("Checking quotas"); var quota = user.DiskQuota ?? _storageSettings.DefaultUserQuota; var totalUsed = (await _entryRepository.GetAllForUserAsync(user.Id)) .Select(x => x.AudioFileSize) .Sum(); if (totalUsed >= quota) { LogError($"Storage quota exceeded for {user.GetBestGuessName()}"); BackgroundJob.Enqueue <INotifyJobCompleteService>( service => service.NotifyUser( user.Id.ToString(), $"Failure processing playlist\n{playlist.Podcast.Title}\n", $"Your have exceeded your storage quota of {quota.Bytes().ToString()}", playlist.Podcast.GetAuthenticatedUrl(_appSettings.SiteUrl), playlist.Podcast.GetThumbnailUrl(_storageSettings.CdnUrl, _imageFileStorageSettings.ContainerName), NotificationOptions.StorageExceeded )); return(false); } Log("Quotas passed"); //check for active subscription var resultList = new List <ParsedItemResult>(); var count = user.PlaylistAllowedEntryCount ?? _storageSettings.DefaultEntryCount; if (_youTubeParser.ValidateUrl(playlist.SourceUrl)) { Log("Parsing YouTube"); var url = playlist.SourceUrl; resultList = await _youTubeParser .GetEntries( url, user.Id, cutoffDate, count); } else if (MixcloudParser.ValidateUrl(playlist.SourceUrl)) { Log("Parsing MixCloud"); var entries = await _mixcloudParser .GetEntries(playlist.SourceUrl, count); resultList = entries .OrderBy(r => r.UploadDate) .Take(_storageSettings.DefaultEntryCount) .ToList(); } Log($"Found {resultList.Count} candidates"); //order in reverse so the newest item is added first foreach (var item in resultList.Where(item => playlist.PodcastEntries.All(e => e.SourceItemId != item.Id))) { await _trimPlaylist(playlist, count); Log($"Found candidate\n\tParsedId:{item.Id}\n\tPodcastId:{playlist.Podcast.Id}\n\t{playlist.Id}"); BackgroundJob .Enqueue <ProcessPlaylistItemJob>( service => service.Execute(item, playlist.Id, null) ); } Log($"Finished playlists"); return(true); } catch (PlaylistExpiredException) { //TODO: Remove playlist and notify user LogError($"Playlist: {playlistId} cannot be found"); } catch (Exception ex) { LogError(ex.Message); context.WriteLine($"ERROR(ProcessPlayListJob): {ex.Message}"); } return(false); }
public async Task <PlaylistDto> GetAsync(Guid id) { var playlist = await _playlistRepository.GetAsync(id); return(_mapper.Map <Playlist, PlaylistDto>(playlist)); }
public Task <Page <Playlist> > GetAsync(PlaylistQuery query, CancellationToken cancel = default) { return(_playlistRepository.GetAsync(query, cancel)); }