예제 #1
0
 public void Initialize(ProgressNotification progressNotification = null)
 {
     Server.Log(LogCategory.Notice, "Generating world around spawn point...");
     for (int x = -5; x < 5; x++)
     {
         for (int z = -5; z < 5; z++)
             World.GetChunk(new Coordinates2D(x, z));
         int progress = (int)(((x + 5) / 10.0) * 100);
         if (progressNotification != null)
             progressNotification(progress / 100.0, "Generating world...");
         if (progress % 10 == 0)
             Server.Log(LogCategory.Notice, "{0}% complete", progress + 10);
     }
     Server.Log(LogCategory.Notice, "Simulating the world for a moment...");
     for (int x = -5; x < 5; x++)
     {
         for (int z = -5; z < 5; z++)
         {
             var chunk = World.GetChunk(new Coordinates2D(x, z));
             for (byte _x = 0; _x < Chunk.Width; _x++)
             {
                 for (byte _z = 0; _z < Chunk.Depth; _z++)
                 {
                     for (int _y = 0; _y < chunk.GetHeight(_x, _z); _y++)
                     {
                         var coords = new Coordinates3D(x + _x, _y, z + _z);
                         var data = World.GetBlockData(coords);
                         var provider = World.BlockRepository.GetBlockProvider(data.ID);
                         provider.BlockUpdate(data, data, Server, World);
                     }
                 }
             }
         }
         int progress = (int)(((x + 5) / 10.0) * 100);
         if (progressNotification != null)
             progressNotification(progress / 100.0, "Simulating world...");
         if (progress % 10 == 0)
             Server.Log(LogCategory.Notice, "{0}% complete", progress + 10);
     }
     World.Save();
 }
예제 #2
0
 protected abstract void FinalizeSearch(Series series, dynamic options, Boolean reportsFound, ProgressNotification notification);
예제 #3
0
 public abstract List <EpisodeParseResult> PerformSearch(Series series, dynamic options, ProgressNotification notification);
예제 #4
0
 public void Setup()
 {
     _notification = new ProgressNotification("Test");
     WithTempAsAppPath();
 }
 public virtual void Start(ProgressNotification notification, dynamic options)
 {
     Logger.Info("Running search history cleanup.");
     _searchHistoryProvider.Cleanup();
 }
예제 #6
0
 public Task <IEnumerable <ILive <BeatmapSetInfo> > > Import(ProgressNotification notification, params ImportTask[] tasks)
 {
     return(beatmapModelManager.Import(notification, tasks));
 }
        private void load(BeatmapModelDownloader beatmaps)
        {
            this.beatmaps = beatmaps;

            beatmaps.PostNotification = n => recentNotification = n as ProgressNotification;
        }
예제 #8
0
        private List <BeatmapCollection> readCollections(Stream stream, ProgressNotification notification = null)
        {
            if (notification != null)
            {
                notification.Text     = "Reading collections...";
                notification.Progress = 0;
            }

            var result = new List <BeatmapCollection>();

            try
            {
                using (var sr = new SerializationReader(stream))
                {
                    sr.ReadInt32(); // Version

                    int collectionCount = sr.ReadInt32();
                    result.Capacity = collectionCount;

                    for (int i = 0; i < collectionCount; i++)
                    {
                        if (notification?.CancellationToken.IsCancellationRequested == true)
                        {
                            return(result);
                        }

                        var collection = new BeatmapCollection {
                            Name = { Value = sr.ReadString() }
                        };
                        int mapCount = sr.ReadInt32();

                        for (int j = 0; j < mapCount; j++)
                        {
                            if (notification?.CancellationToken.IsCancellationRequested == true)
                            {
                                return(result);
                            }

                            string checksum = sr.ReadString();

                            var beatmap = beatmaps.QueryBeatmap(b => b.MD5Hash == checksum);
                            if (beatmap != null)
                            {
                                collection.Beatmaps.Add(beatmap);
                            }
                        }

                        if (notification != null)
                        {
                            notification.Text     = $"Imported {i + 1} of {collectionCount} collections";
                            notification.Progress = (float)(i + 1) / collectionCount;
                        }

                        result.Add(collection);
                    }
                }
            }
            catch (Exception e)
            {
                Logger.Error(e, "Failed to read collection database.");
            }

            return(result);
        }
예제 #9
0
 public Task <IEnumerable <ScoreInfo> > Import(ProgressNotification notification, params ImportTask[] tasks)
 {
     return(scoreModelManager.Import(notification, tasks));
 }
예제 #10
0
        /// <summary>
        /// Downloads a beatmap.
        /// </summary>
        /// <param name="beatmapSetInfo">The <see cref="BeatmapSetInfo"/> to be downloaded.</param>
        /// <param name="noVideo">Whether the beatmap should be downloaded without video. Defaults to false.</param>
        public void Download(BeatmapSetInfo beatmapSetInfo, bool noVideo = false)
        {
            var existing = GetExistingDownload(beatmapSetInfo);

            if (existing != null || api == null)
            {
                return;
            }

            if (!api.LocalUser.Value.IsSupporter)
            {
                PostNotification?.Invoke(new SimpleNotification
                {
                    Icon = FontAwesome.fa_superpowers,
                    Text = "You gotta be a supporter to download for now 'yo"
                });
                return;
            }

            var downloadNotification = new ProgressNotification
            {
                CompletionText = $"Imported {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}!",
                Text           = $"Downloading {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}",
            };

            var request = new DownloadBeatmapSetRequest(beatmapSetInfo, noVideo);

            request.DownloadProgressed += progress =>
            {
                downloadNotification.State    = ProgressNotificationState.Active;
                downloadNotification.Progress = progress;
            };

            request.Success += data =>
            {
                downloadNotification.Text = $"Importing {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}";

                Task.Factory.StartNew(() =>
                {
                    // This gets scheduled back to the update thread, but we want the import to run in the background.
                    using (var stream = new MemoryStream(data))
                        using (var archive = new OszArchiveReader(stream))
                            Import(archive);

                    downloadNotification.State = ProgressNotificationState.Completed;
                }, TaskCreationOptions.LongRunning);

                currentDownloads.Remove(request);
            };

            request.Failure += data =>
            {
                downloadNotification.State = ProgressNotificationState.Completed;
                Logger.Error(data, "Failed to get beatmap download information");
                currentDownloads.Remove(request);
            };

            downloadNotification.CancelRequested += () =>
            {
                request.Cancel();
                currentDownloads.Remove(request);
                downloadNotification.State = ProgressNotificationState.Cancelled;
                return(true);
            };

            currentDownloads.Add(request);
            PostNotification?.Invoke(downloadNotification);

            // don't run in the main api queue as this is a long-running task.
            Task.Factory.StartNew(() => request.Perform(api), TaskCreationOptions.LongRunning);
            BeatmapDownloadBegan?.Invoke(request);
        }
        protected override void FinalizeSearch(Series series, dynamic options, Boolean reportsFound, ProgressNotification notification)
        {
            logger.Warn("Unable to find {0} in any of indexers.", options.Episode);

            notification.CurrentMessage = reportsFound ? String.Format("Sorry, couldn't find {0}, that matches your preferences.", options.Episode.AirDate)
                                                        : String.Format("Sorry, couldn't find {0} in any of indexers.", options.Episode);
        }
        public override List <EpisodeParseResult> PerformSearch(Series series, dynamic options, ProgressNotification notification)
        {
            if (options.Episode == null)
            {
                throw new ArgumentException("Episode is invalid");
            }

            notification.CurrentMessage = "Looking for " + options.Episode;

            var reports = new List <EpisodeParseResult>();
            var title   = GetSearchTitle(series);

            Parallel.ForEach(_indexerProvider.GetEnabledIndexers(), indexer =>
            {
                try
                {
                    reports.AddRange(indexer.FetchDailyEpisode(title, options.Episode.AirDate));
                }

                catch (Exception e)
                {
                    logger.ErrorException(String.Format("An error has occurred while searching for {0} - {1:yyyy-MM-dd} from: {2}",
                                                        series.Title, options.Episode.AirDate, indexer.Name), e);
                }
            });

            return(reports);
        }
예제 #13
0
        protected void Import(ProgressNotification notification, params string[] paths)
        {
            notification.Progress = 0;
            notification.Text     = "Import is initialising...";

            var term = $"{typeof(TModel).Name.Replace("Info", "").ToLower()}";

            List <TModel> imported = new List <TModel>();

            int current = 0;

            foreach (string path in paths)
            {
                if (notification.State == ProgressNotificationState.Cancelled)
                {
                    // user requested abort
                    return;
                }

                try
                {
                    var text = "Importing ";

                    if (path.Length > 1)
                    {
                        text += $"{++current} of {paths.Length} {term}s..";
                    }
                    else
                    {
                        text += $"{term}..";
                    }

                    // only show the filename if it isn't a temporary one (as those look ugly).
                    if (!path.Contains(Path.GetTempPath()))
                    {
                        text += $"\n{Path.GetFileName(path)}";
                    }

                    notification.Text = text;

                    imported.Add(Import(path));

                    notification.Progress = (float)current / paths.Length;
                }
                catch (Exception e)
                {
                    e = e.InnerException ?? e;
                    Logger.Error(e, $@"Could not import ({Path.GetFileName(path)})");
                }
            }

            if (imported.Count == 0)
            {
                notification.Text  = "Import failed!";
                notification.State = ProgressNotificationState.Cancelled;
            }
            else
            {
                notification.CompletionText = imported.Count == 1
                    ? $"Imported {imported.First()}!"
                    : $"Imported {current} {term}s!";

                if (imported.Count > 0 && PresentImport != null)
                {
                    notification.CompletionText       += " Click to view.";
                    notification.CompletionClickAction = () =>
                    {
                        PresentImport?.Invoke(imported);
                        return(true);
                    };
                }

                notification.State = ProgressNotificationState.Completed;
            }
        }
예제 #14
0
 public void Register(ProgressNotification notification)
 {
     _progressNotification.Add(notification.Id, notification);
 }
예제 #15
0
        public virtual SearchHistory ProcessReports(Series series, dynamic options, List <EpisodeParseResult> episodeParseResults,
                                                    SearchHistory searchResult, ProgressNotification notification)
        {
            var items = new List <SearchHistoryItem>();

            searchResult.Successes = new List <Int32>();

            foreach (var episodeParseResult in episodeParseResults
                     .OrderByDescending(c => c.Quality)
                     .ThenBy(c => c.EpisodeNumbers.MinOrDefault())
                     .ThenBy(c => c.Age))
            {
                try
                {
                    var item = new SearchHistoryItem
                    {
                        ReportTitle = episodeParseResult.OriginalString,
                        NzbUrl      = episodeParseResult.NzbUrl,
                        Indexer     = episodeParseResult.Indexer,
                        Quality     = episodeParseResult.Quality.Quality,
                        Proper      = episodeParseResult.Quality.Proper,
                        Size        = episodeParseResult.Size,
                        Age         = episodeParseResult.Age,
                        Language    = episodeParseResult.Language
                    };

                    items.Add(item);

                    logger.Trace("Analysing report " + episodeParseResult);
                    episodeParseResult.Series = _seriesProvider.FindSeries(episodeParseResult.CleanTitle);

                    if (episodeParseResult.Series == null || episodeParseResult.Series.SeriesId != series.SeriesId)
                    {
                        item.SearchError = ReportRejectionType.WrongSeries;
                        continue;
                    }

                    episodeParseResult.Episodes = _episodeProvider.GetEpisodesByParseResult(episodeParseResult);

                    if (searchResult.Successes.Intersect(episodeParseResult.Episodes.Select(e => e.EpisodeId)).Any())
                    {
                        item.SearchError = ReportRejectionType.Skipped;
                        continue;
                    }

                    CheckReport(series, options, episodeParseResult, item);
                    if (item.SearchError != ReportRejectionType.None)
                    {
                        continue;
                    }

                    item.SearchError = _allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult);

                    if (item.SearchError == ReportRejectionType.None)
                    {
                        if (DownloadReport(notification, episodeParseResult, item))
                        {
                            searchResult.Successes.AddRange(episodeParseResult.Episodes.Select(e => e.EpisodeId));
                        }
                    }
                }
                catch (Exception e)
                {
                    logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e);
                }
            }

            searchResult.SearchHistoryItems = items;
            return(searchResult);
        }
예제 #16
0
        protected async Task <IEnumerable <TModel> > Import(ProgressNotification notification, params ImportTask[] tasks)
        {
            if (tasks.Length == 0)
            {
                notification.CompletionText = $"No {HumanisedModelName}s were found to import!";
                notification.State          = ProgressNotificationState.Completed;
                return(Enumerable.Empty <TModel>());
            }

            notification.Progress = 0;
            notification.Text     = $"{HumanisedModelName.Humanize(LetterCasing.Title)} import is initialising...";

            int current = 0;

            var imported = new List <TModel>();

            bool isLowPriorityImport = tasks.Length > low_priority_import_batch_size;

            await Task.WhenAll(tasks.Select(async task =>
            {
                notification.CancellationToken.ThrowIfCancellationRequested();

                try
                {
                    var model = await Import(task, isLowPriorityImport, notification.CancellationToken);

                    lock (imported)
                    {
                        if (model != null)
                        {
                            imported.Add(model);
                        }
                        current++;

                        notification.Text     = $"Imported {current} of {tasks.Length} {HumanisedModelName}s";
                        notification.Progress = (float)current / tasks.Length;
                    }
                }
                catch (TaskCanceledException)
                {
                    throw;
                }
                catch (Exception e)
                {
                    Logger.Error(e, $@"Could not import ({task})", LoggingTarget.Database);
                }
            }));

            if (imported.Count == 0)
            {
                notification.Text  = $"{HumanisedModelName.Humanize(LetterCasing.Title)} import failed!";
                notification.State = ProgressNotificationState.Cancelled;
            }
            else
            {
                notification.CompletionText = imported.Count == 1
                    ? $"Imported {imported.First()}!"
                    : $"Imported {imported.Count} {HumanisedModelName}s!";

                if (imported.Count > 0 && PresentImport != null)
                {
                    notification.CompletionText       += " Click to view.";
                    notification.CompletionClickAction = () =>
                    {
                        PresentImport?.Invoke(imported);
                        return(true);
                    };
                }

                notification.State = ProgressNotificationState.Completed;
            }

            return(imported);
        }
예제 #17
0
        /// <summary>
        /// Import one or more <see cref="TModel"/> items from filesystem <paramref name="paths"/>.
        /// This will post notifications tracking progress.
        /// </summary>
        /// <param name="paths">One or more archive locations on disk.</param>
        public void Import(params string[] paths)
        {
            var notification = new ProgressNotification
            {
                Text     = "Import is initialising...",
                Progress = 0,
                State    = ProgressNotificationState.Active,
            };

            PostNotification?.Invoke(notification);

            List <TModel> imported = new List <TModel>();

            int current = 0;

            foreach (string path in paths)
            {
                if (notification.State == ProgressNotificationState.Cancelled)
                {
                    // user requested abort
                    return;
                }

                try
                {
                    notification.Text = $"Importing ({++current} of {paths.Length})\n{Path.GetFileName(path)}";

                    TModel import;
                    using (ArchiveReader reader = getReaderFrom(path))
                        imported.Add(import = Import(reader));

                    notification.Progress = (float)current / paths.Length;

                    // We may or may not want to delete the file depending on where it is stored.
                    //  e.g. reconstructing/repairing database with items from default storage.
                    // Also, not always a single file, i.e. for LegacyFilesystemReader
                    // TODO: Add a check to prevent files from storage to be deleted.
                    try
                    {
                        if (import != null && File.Exists(path))
                        {
                            File.Delete(path);
                        }
                    }
                    catch (Exception e)
                    {
                        Logger.Error(e, $@"Could not delete original file after import ({Path.GetFileName(path)})");
                    }
                }
                catch (Exception e)
                {
                    e = e.InnerException ?? e;
                    Logger.Error(e, $@"Could not import ({Path.GetFileName(path)})");
                }
            }

            if (imported.Count == 0)
            {
                notification.Text  = "Import failed!";
                notification.State = ProgressNotificationState.Cancelled;
            }
            else
            {
                notification.CompletionText         = $"Imported {current} {typeof(TModel).Name.Replace("Info", "").ToLower()}s!";
                notification.CompletionClickAction += () =>
                {
                    if (imported.Count > 0)
                    {
                        PresentCompletedImport(imported);
                    }
                    return(true);
                };
                notification.State = ProgressNotificationState.Completed;
            }
        }
예제 #18
0
        public void Start(ProgressNotification notification, dynamic options)
        {
            List <Series> seriesToRename;

            if (options == null || options.SeriesId <= 0)
            {
                seriesToRename = _seriesProvider.GetAllSeries().ToList();
            }

            else
            {
                seriesToRename = new List <Series> {
                    _seriesProvider.GetSeries(options.SeriesId)
                };
            }

            foreach (var series in seriesToRename)
            {
                notification.CurrentMessage = String.Format("Renaming episodes for '{0}'", series.Title);

                Logger.Debug("Getting episodes from database for series: {0}", series.SeriesId);
                var episodeFiles = _mediaFileProvider.GetSeriesFiles(series.SeriesId);

                if (episodeFiles == null || episodeFiles.Count == 0)
                {
                    Logger.Warn("No episodes in database found for series: {0}", series.SeriesId);
                    return;
                }

                var newEpisodeFiles = new List <EpisodeFile>();
                var oldEpisodeFiles = new List <EpisodeFile>();

                foreach (var episodeFile in episodeFiles)
                {
                    try
                    {
                        var oldFile = new EpisodeFile(episodeFile);
                        var newFile = _diskScanProvider.MoveEpisodeFile(episodeFile);

                        if (newFile != null)
                        {
                            newEpisodeFiles.Add(newFile);
                            oldEpisodeFiles.Add(oldFile);
                        }
                    }

                    catch (Exception e)
                    {
                        Logger.WarnException("An error has occurred while renaming file", e);
                    }
                }

                //Remove & Create Metadata for episode files
                _metadataProvider.RemoveForEpisodeFiles(oldEpisodeFiles);
                _metadataProvider.CreateForEpisodeFiles(newEpisodeFiles);

                //Start AfterRename

                var message = String.Format("Renamed: Series {0}", series.Title);
                _externalNotificationProvider.AfterRename(message, series);

                notification.CurrentMessage = String.Format("Rename completed for {0}", series.Title);
            }
        }
예제 #19
0
        protected async Task Import(ProgressNotification notification, params string[] paths)
        {
            notification.Progress = 0;
            notification.Text     = "Import is initialising...";

            int current = 0;

            var imported = new List <TModel>();

            await Task.WhenAll(paths.Select(async path =>
            {
                notification.CancellationToken.ThrowIfCancellationRequested();

                try
                {
                    var model = await Import(path, notification.CancellationToken);

                    lock (imported)
                    {
                        if (model != null)
                        {
                            imported.Add(model);
                        }
                        current++;

                        notification.Text     = $"Imported {current} of {paths.Length} {HumanisedModelName}s";
                        notification.Progress = (float)current / paths.Length;
                    }
                }
                catch (TaskCanceledException)
                {
                    throw;
                }
                catch (Exception e)
                {
                    Logger.Error(e, $@"Could not import ({Path.GetFileName(path)})", LoggingTarget.Database);
                }
            }));

            if (imported.Count == 0)
            {
                notification.Text  = "Import failed!";
                notification.State = ProgressNotificationState.Cancelled;
            }
            else
            {
                notification.CompletionText = imported.Count == 1
                    ? $"Imported {imported.First()}!"
                    : $"Imported {imported.Count} {HumanisedModelName}s!";

                if (imported.Count > 0 && PresentImport != null)
                {
                    notification.CompletionText       += " Click to view.";
                    notification.CompletionClickAction = () =>
                    {
                        PresentImport?.Invoke(imported);
                        return(true);
                    };
                }

                notification.State = ProgressNotificationState.Completed;
            }
        }
예제 #20
0
        /// <summary>
        /// Downloads a beatmap.
        /// </summary>
        /// <param name="beatmapSetInfo">The <see cref="BeatmapSetInfo"/> to be downloaded.</param>
        /// <returns>A new <see cref="DownloadBeatmapSetRequest"/>, or an existing one if a download is already in progress.</returns>
        public DownloadBeatmapSetRequest Download(BeatmapSetInfo beatmapSetInfo)
        {
            var existing = GetExistingDownload(beatmapSetInfo);

            if (existing != null)
            {
                return(existing);
            }

            if (api == null)
            {
                return(null);
            }

            ProgressNotification downloadNotification = new ProgressNotification
            {
                Text = $"Downloading {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}",
            };

            var request = new DownloadBeatmapSetRequest(beatmapSetInfo);

            request.DownloadProgressed += progress =>
            {
                downloadNotification.State    = ProgressNotificationState.Active;
                downloadNotification.Progress = progress;
            };

            request.Success += data =>
            {
                downloadNotification.State = ProgressNotificationState.Completed;

                using (var stream = new MemoryStream(data))
                    using (var archive = new OszArchiveReader(stream))
                        Import(archive);

                currentDownloads.Remove(request);
            };

            request.Failure += data =>
            {
                downloadNotification.State = ProgressNotificationState.Completed;
                Logger.Error(data, "Failed to get beatmap download information");
                currentDownloads.Remove(request);
            };

            downloadNotification.CancelRequested += () =>
            {
                request.Cancel();
                currentDownloads.Remove(request);
                downloadNotification.State = ProgressNotificationState.Cancelled;
                return(true);
            };

            currentDownloads.Add(request);
            PostNotification?.Invoke(downloadNotification);

            // don't run in the main api queue as this is a long-running task.
            Task.Run(() => request.Perform(api));

            return(request);
        }
예제 #21
0
 public virtual void Start(ProgressNotification notification, dynamic options)
 {
     _logProvider.Trim();
 }