public ProcessPlaylistsJob(
     ILogger <ProcessPlaylistsJob> logger,
     UserManager <ApplicationUser> userManager,
     IPlaylistRepository playlistRepository,
     IEntryRepository entryRepository,
     IUnitOfWork unitOfWork,
     IOptions <StorageSettings> storageSettings,
     IOptions <ImageFileStorageSettings> imageFileStorageSettings,
     IOptions <AppSettings> appSettings,
     IYouTubeParser youTubeParser,
     MixcloudParser mixcloudParser) : base(logger)
 {
     _userManager = userManager;
     _unitOfWork  = unitOfWork;
     _imageFileStorageSettings = imageFileStorageSettings.Value;
     _youTubeParser            = youTubeParser;
     _mixcloudParser           = mixcloudParser;
     _playlistRepository       = playlistRepository;
     _entryRepository          = entryRepository;
     _storageSettings          = storageSettings.Value;
     _appSettings = appSettings.Value;
 }
        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);
        }