mirror of
https://github.com/Sonarr/Sonarr.git
synced 2024-10-29 23:12:39 +01:00
New: 'On Import Complete' notification when all episodes in a release are imported
Closes #363
This commit is contained in:
parent
1d06e40acb
commit
a83b521766
@ -59,6 +59,7 @@ class Notification extends Component {
|
||||
onGrab,
|
||||
onDownload,
|
||||
onUpgrade,
|
||||
onImportComplete,
|
||||
onRename,
|
||||
onSeriesAdd,
|
||||
onSeriesDelete,
|
||||
@ -71,6 +72,7 @@ class Notification extends Component {
|
||||
supportsOnGrab,
|
||||
supportsOnDownload,
|
||||
supportsOnUpgrade,
|
||||
supportsOnImportComplete,
|
||||
supportsOnRename,
|
||||
supportsOnSeriesAdd,
|
||||
supportsOnSeriesDelete,
|
||||
@ -105,7 +107,7 @@ class Notification extends Component {
|
||||
{
|
||||
supportsOnDownload && onDownload ?
|
||||
<Label kind={kinds.SUCCESS}>
|
||||
{translate('OnImport')}
|
||||
{translate('OnFileImport')}
|
||||
</Label> :
|
||||
null
|
||||
}
|
||||
@ -118,6 +120,14 @@ class Notification extends Component {
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
supportsOnImportComplete && onImportComplete ?
|
||||
<Label kind={kinds.SUCCESS}>
|
||||
{translate('OnImportComplete')}
|
||||
</Label> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
supportsOnRename && onRename ?
|
||||
<Label kind={kinds.SUCCESS}>
|
||||
@ -191,7 +201,7 @@ class Notification extends Component {
|
||||
}
|
||||
|
||||
{
|
||||
!onGrab && !onDownload && !onRename && !onHealthIssue && !onHealthRestored && !onApplicationUpdate && !onSeriesAdd && !onSeriesDelete && !onEpisodeFileDelete && !onManualInteractionRequired ?
|
||||
!onGrab && !onDownload && !onRename && !onImportComplete && !onHealthIssue && !onHealthRestored && !onApplicationUpdate && !onSeriesAdd && !onSeriesDelete && !onEpisodeFileDelete && !onManualInteractionRequired ?
|
||||
<Label
|
||||
kind={kinds.DISABLED}
|
||||
outline={true}
|
||||
@ -233,6 +243,7 @@ Notification.propTypes = {
|
||||
onGrab: PropTypes.bool.isRequired,
|
||||
onDownload: PropTypes.bool.isRequired,
|
||||
onUpgrade: PropTypes.bool.isRequired,
|
||||
onImportComplete: PropTypes.bool.isRequired,
|
||||
onRename: PropTypes.bool.isRequired,
|
||||
onSeriesAdd: PropTypes.bool.isRequired,
|
||||
onSeriesDelete: PropTypes.bool.isRequired,
|
||||
@ -244,6 +255,7 @@ Notification.propTypes = {
|
||||
onManualInteractionRequired: PropTypes.bool.isRequired,
|
||||
supportsOnGrab: PropTypes.bool.isRequired,
|
||||
supportsOnDownload: PropTypes.bool.isRequired,
|
||||
supportsOnImportComplete: PropTypes.bool.isRequired,
|
||||
supportsOnSeriesAdd: PropTypes.bool.isRequired,
|
||||
supportsOnSeriesDelete: PropTypes.bool.isRequired,
|
||||
supportsOnEpisodeFileDelete: PropTypes.bool.isRequired,
|
||||
|
@ -18,6 +18,7 @@ function NotificationEventItems(props) {
|
||||
onGrab,
|
||||
onDownload,
|
||||
onUpgrade,
|
||||
onImportComplete,
|
||||
onRename,
|
||||
onSeriesAdd,
|
||||
onSeriesDelete,
|
||||
@ -30,6 +31,7 @@ function NotificationEventItems(props) {
|
||||
supportsOnGrab,
|
||||
supportsOnDownload,
|
||||
supportsOnUpgrade,
|
||||
supportsOnImportComplete,
|
||||
supportsOnRename,
|
||||
supportsOnSeriesAdd,
|
||||
supportsOnSeriesDelete,
|
||||
@ -66,7 +68,7 @@ function NotificationEventItems(props) {
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="onDownload"
|
||||
helpText={translate('OnImport')}
|
||||
helpText={translate('OnFileImport')}
|
||||
isDisabled={!supportsOnDownload.value}
|
||||
{...onDownload}
|
||||
onChange={onInputChange}
|
||||
@ -87,6 +89,17 @@ function NotificationEventItems(props) {
|
||||
</div>
|
||||
}
|
||||
|
||||
<div>
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="onImportComplete"
|
||||
helpText={translate('OnImportComplete')}
|
||||
isDisabled={!supportsOnImportComplete.value}
|
||||
{...onImportComplete}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
|
@ -116,6 +116,7 @@ export default {
|
||||
selectedSchema.onGrab = selectedSchema.supportsOnGrab;
|
||||
selectedSchema.onDownload = selectedSchema.supportsOnDownload;
|
||||
selectedSchema.onUpgrade = selectedSchema.supportsOnUpgrade;
|
||||
selectedSchema.onImportComplete = selectedSchema.supportsOnImportComplete;
|
||||
selectedSchema.onRename = selectedSchema.supportsOnRename;
|
||||
selectedSchema.onSeriesAdd = selectedSchema.supportsOnSeriesAdd;
|
||||
selectedSchema.onSeriesDelete = selectedSchema.supportsOnSeriesDelete;
|
||||
|
@ -71,6 +71,10 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
|
||||
Mocker.GetMock<IProvideImportItemService>()
|
||||
.Setup(s => s.ProvideImportItem(It.IsAny<DownloadClientItem>(), It.IsAny<DownloadClientItem>()))
|
||||
.Returns<DownloadClientItem, DownloadClientItem>((i, p) => i);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.GetEpisodes(It.IsAny<IEnumerable<int>>()))
|
||||
.Returns(new List<Episode>());
|
||||
}
|
||||
|
||||
private RemoteEpisode BuildRemoteEpisode()
|
||||
|
@ -0,0 +1,14 @@
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(209)]
|
||||
public class add_on_import_complete_to_notifications : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Alter.Table("Notifications").AddColumn("OnImportComplete").AsBoolean().WithDefaultValue(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -89,6 +89,7 @@ namespace NzbDrone.Core.Datastore
|
||||
.Ignore(x => x.ImplementationName)
|
||||
.Ignore(i => i.SupportsOnGrab)
|
||||
.Ignore(i => i.SupportsOnDownload)
|
||||
.Ignore(i => i.SupportsOnImportComplete)
|
||||
.Ignore(i => i.SupportsOnUpgrade)
|
||||
.Ignore(i => i.SupportsOnRename)
|
||||
.Ignore(i => i.SupportsOnSeriesAdd)
|
||||
|
@ -34,6 +34,8 @@ namespace NzbDrone.Core.Download
|
||||
private readonly IParsingService _parsingService;
|
||||
private readonly ISeriesService _seriesService;
|
||||
private readonly ITrackedDownloadAlreadyImported _trackedDownloadAlreadyImported;
|
||||
private readonly IEpisodeService _episodeService;
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public CompletedDownloadService(IEventAggregator eventAggregator,
|
||||
@ -43,6 +45,8 @@ namespace NzbDrone.Core.Download
|
||||
IParsingService parsingService,
|
||||
ISeriesService seriesService,
|
||||
ITrackedDownloadAlreadyImported trackedDownloadAlreadyImported,
|
||||
IEpisodeService episodeService,
|
||||
IMediaFileService mediaFileService,
|
||||
Logger logger)
|
||||
{
|
||||
_eventAggregator = eventAggregator;
|
||||
@ -52,6 +56,8 @@ namespace NzbDrone.Core.Download
|
||||
_parsingService = parsingService;
|
||||
_seriesService = seriesService;
|
||||
_trackedDownloadAlreadyImported = trackedDownloadAlreadyImported;
|
||||
_episodeService = episodeService;
|
||||
_mediaFileService = mediaFileService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@ -198,11 +204,23 @@ namespace NzbDrone.Core.Download
|
||||
.Count() >= Math.Max(1,
|
||||
trackedDownload.RemoteEpisode.Episodes.Count);
|
||||
|
||||
var historyItems = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId)
|
||||
.OrderByDescending(h => h.Date)
|
||||
.ToList();
|
||||
|
||||
var grabbedHistory = historyItems.Where(h => h.EventType == EpisodeHistoryEventType.Grabbed).ToList();
|
||||
var releaseInfo = grabbedHistory.Count > 0 ? new GrabbedReleaseInfo(grabbedHistory) : null;
|
||||
|
||||
if (allEpisodesImported)
|
||||
{
|
||||
_logger.Debug("All episodes were imported for {0}", trackedDownload.DownloadItem.Title);
|
||||
trackedDownload.State = TrackedDownloadState.Imported;
|
||||
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, trackedDownload.RemoteEpisode.Series.Id));
|
||||
|
||||
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload,
|
||||
trackedDownload.RemoteEpisode.Series.Id,
|
||||
importResults.Where(c => c.Result == ImportResultType.Imported).Select(c => c.EpisodeFile).ToList(),
|
||||
releaseInfo));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -216,12 +234,9 @@ namespace NzbDrone.Core.Download
|
||||
// safe, but commenting for future benefit.
|
||||
|
||||
var atLeastOneEpisodeImported = importResults.Any(c => c.Result == ImportResultType.Imported);
|
||||
|
||||
var historyItems = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId)
|
||||
.OrderByDescending(h => h.Date)
|
||||
.ToList();
|
||||
|
||||
var allEpisodesImportedInHistory = _trackedDownloadAlreadyImported.IsImported(trackedDownload, historyItems);
|
||||
var episodes = _episodeService.GetEpisodes(trackedDownload.RemoteEpisode.Episodes.Select(e => e.Id));
|
||||
var files = _mediaFileService.GetFiles(episodes.Select(e => e.EpisodeFileId).Distinct());
|
||||
|
||||
if (allEpisodesImportedInHistory)
|
||||
{
|
||||
@ -245,7 +260,7 @@ namespace NzbDrone.Core.Download
|
||||
}
|
||||
|
||||
trackedDownload.State = TrackedDownloadState.Imported;
|
||||
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, trackedDownload.RemoteEpisode.Series.Id));
|
||||
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, trackedDownload.RemoteEpisode.Series.Id, files, releaseInfo));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1,17 +1,24 @@
|
||||
using NzbDrone.Common.Messaging;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Common.Messaging;
|
||||
using NzbDrone.Core.Download.TrackedDownloads;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
public class DownloadCompletedEvent : IEvent
|
||||
{
|
||||
public TrackedDownload TrackedDownload { get; private set; }
|
||||
public int SeriesId { get; set; }
|
||||
public int SeriesId { get; private set; }
|
||||
public List<EpisodeFile> EpisodeFiles { get; private set; }
|
||||
public GrabbedReleaseInfo Release { get; private set; }
|
||||
|
||||
public DownloadCompletedEvent(TrackedDownload trackedDownload, int seriesId)
|
||||
public DownloadCompletedEvent(TrackedDownload trackedDownload, int seriesId, List<EpisodeFile> episodeFiles, GrabbedReleaseInfo release)
|
||||
{
|
||||
TrackedDownload = trackedDownload;
|
||||
SeriesId = seriesId;
|
||||
EpisodeFiles = episodeFiles;
|
||||
Release = release;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
@ -0,0 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Common.Messaging;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
public class UntrackedDownloadCompletedEvent : IEvent
|
||||
{
|
||||
public Series Series { get; private set; }
|
||||
public List<Episode> Episodes { get; private set; }
|
||||
public List<EpisodeFile> EpisodeFiles { get; private set; }
|
||||
public ParsedEpisodeInfo ParsedEpisodeInfo { get; private set; }
|
||||
public string SourcePath { get; private set; }
|
||||
|
||||
public UntrackedDownloadCompletedEvent(Series series, List<Episode> episodes, List<EpisodeFile> episodeFiles, ParsedEpisodeInfo parsedEpisodeInfo, string sourcePath)
|
||||
{
|
||||
Series = series;
|
||||
Episodes = episodes;
|
||||
EpisodeFiles = episodeFiles;
|
||||
ParsedEpisodeInfo = parsedEpisodeInfo;
|
||||
SourcePath = sourcePath;
|
||||
}
|
||||
}
|
||||
}
|
@ -1456,10 +1456,11 @@
|
||||
"OnApplicationUpdate": "On Application Update",
|
||||
"OnEpisodeFileDelete": "On Episode File Delete",
|
||||
"OnEpisodeFileDeleteForUpgrade": "On Episode File Delete For Upgrade",
|
||||
"OnFileImport": "On File Import",
|
||||
"OnGrab": "On Grab",
|
||||
"OnHealthIssue": "On Health Issue",
|
||||
"OnHealthRestored": "On Health Restored",
|
||||
"OnImport": "On Import",
|
||||
"OnImportComplete": "On Import Complete",
|
||||
"OnLatestVersion": "The latest version of {appName} is already installed",
|
||||
"OnManualInteractionRequired": "On Manual Interaction Required",
|
||||
"OnRename": "On Rename",
|
||||
|
@ -171,7 +171,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
}
|
||||
|
||||
episodeFile = _mediaFileService.Add(episodeFile);
|
||||
importResults.Add(new ImportResult(importDecision));
|
||||
importResults.Add(new ImportResult(importDecision, episodeFile));
|
||||
|
||||
if (newDownload)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
|
||||
@ -7,6 +7,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
public class ImportResult
|
||||
{
|
||||
public ImportDecision ImportDecision { get; private set; }
|
||||
public EpisodeFile EpisodeFile { get; private set; }
|
||||
public List<string> Errors { get; private set; }
|
||||
|
||||
public ImportResultType Result
|
||||
@ -34,5 +35,14 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
ImportDecision = importDecision;
|
||||
Errors = errors.ToList();
|
||||
}
|
||||
|
||||
public ImportResult(ImportDecision importDecision, EpisodeFile episodeFile)
|
||||
{
|
||||
Ensure.That(importDecision, () => importDecision).IsNotNull();
|
||||
|
||||
ImportDecision = importDecision;
|
||||
EpisodeFile = episodeFile;
|
||||
Errors = new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -546,6 +546,24 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
||||
_logger.ProgressTrace("Manually imported {0} files", imported.Count);
|
||||
}
|
||||
|
||||
var untrackedImports = imported.Where(i => importedTrackedDownload.FirstOrDefault(t => t.ImportResult != i) == null).ToList();
|
||||
|
||||
if (untrackedImports.Any())
|
||||
{
|
||||
foreach (var groupedUntrackedImport in untrackedImports.GroupBy(i => new { i.EpisodeFile.SeriesId, i.EpisodeFile.SeasonNumber }))
|
||||
{
|
||||
var localEpisodes = groupedUntrackedImport.Select(u => u.ImportDecision.LocalEpisode).ToList();
|
||||
var episodeFiles = groupedUntrackedImport.Select(u => u.EpisodeFile).ToList();
|
||||
var localEpisode = localEpisodes.First();
|
||||
var series = localEpisode.Series;
|
||||
var sourcePath = localEpisodes.Select(l => l.Path).ToList().GetLongestCommonPath();
|
||||
var episodes = localEpisodes.SelectMany(l => l.Episodes).ToList();
|
||||
var parsedEpisodeInfo = localEpisode.FolderEpisodeInfo ?? localEpisode.FileEpisodeInfo;
|
||||
|
||||
_eventAggregator.PublishEvent(new UntrackedDownloadCompletedEvent(series, episodes, episodeFiles, parsedEpisodeInfo, sourcePath));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var groupedTrackedDownload in importedTrackedDownload.GroupBy(i => i.TrackedDownload.DownloadItem.DownloadId).ToList())
|
||||
{
|
||||
var trackedDownload = groupedTrackedDownload.First().TrackedDownload;
|
||||
@ -562,15 +580,20 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
||||
}
|
||||
}
|
||||
|
||||
var allEpisodesImported = groupedTrackedDownload.Select(c => c.ImportResult)
|
||||
.Where(c => c.Result == ImportResultType.Imported)
|
||||
var importedResults = groupedTrackedDownload.Select(c => c.ImportResult)
|
||||
.Where(c => c.Result == ImportResultType.Imported)
|
||||
.ToList();
|
||||
|
||||
var allEpisodesImported = importedResults
|
||||
.SelectMany(c => c.ImportDecision.LocalEpisode.Episodes).Count() >=
|
||||
Math.Max(1, trackedDownload.RemoteEpisode?.Episodes?.Count ?? 1);
|
||||
|
||||
if (allEpisodesImported)
|
||||
{
|
||||
var episodeFiles = importedResults.Select(i => i.EpisodeFile).ToList();
|
||||
|
||||
trackedDownload.State = TrackedDownloadState.Imported;
|
||||
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, importedSeries.Id));
|
||||
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, importedSeries.Id, episodeFiles, importedResults.First().ImportDecision.LocalEpisode.Release));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,11 @@ namespace NzbDrone.Core.Notifications.Apprise
|
||||
_proxy.SendNotification(EPISODE_DOWNLOADED_TITLE, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
_proxy.SendNotification(IMPORT_COMPLETE_TITLE, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
_proxy.SendNotification(EPISODE_DELETED_TITLE, deleteMessage.Message, Settings);
|
||||
|
@ -96,6 +96,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
|
||||
environmentVariables.Add("Sonarr_Download_Id", message.DownloadId ?? string.Empty);
|
||||
environmentVariables.Add("Sonarr_Release_CustomFormat", string.Join("|", remoteEpisode.CustomFormats));
|
||||
environmentVariables.Add("Sonarr_Release_CustomFormatScore", remoteEpisode.CustomFormatScore.ToString());
|
||||
environmentVariables.Add("Sonarr_Release_ReleaseType", remoteEpisode.ParsedEpisodeInfo.ReleaseType.ToString());
|
||||
|
||||
ExecuteScript(environmentVariables);
|
||||
}
|
||||
@ -158,6 +159,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
|
||||
environmentVariables.Add("Sonarr_Release_Indexer", message.Release?.Indexer);
|
||||
environmentVariables.Add("Sonarr_Release_Size", message.Release?.Size.ToString());
|
||||
environmentVariables.Add("Sonarr_Release_Title", message.Release?.Title);
|
||||
environmentVariables.Add("Sonarr_Release_ReleaseType", message.Release?.ReleaseType.ToString() ?? string.Empty);
|
||||
|
||||
if (message.OldFiles.Any())
|
||||
{
|
||||
@ -170,6 +172,65 @@ namespace NzbDrone.Core.Notifications.CustomScript
|
||||
ExecuteScript(environmentVariables);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
var series = message.Series;
|
||||
var episodes = message.Episodes;
|
||||
var episodeFiles = message.EpisodeFiles;
|
||||
var sourcePath = message.SourcePath;
|
||||
var environmentVariables = new StringDictionary();
|
||||
|
||||
environmentVariables.Add("Sonarr_EventType", "Download");
|
||||
environmentVariables.Add("Sonarr_InstanceName", _configFileProvider.InstanceName);
|
||||
environmentVariables.Add("Sonarr_ApplicationUrl", _configService.ApplicationUrl);
|
||||
environmentVariables.Add("Sonarr_Series_Id", series.Id.ToString());
|
||||
environmentVariables.Add("Sonarr_Series_Title", series.Title);
|
||||
environmentVariables.Add("Sonarr_Series_TitleSlug", series.TitleSlug);
|
||||
environmentVariables.Add("Sonarr_Series_Path", series.Path);
|
||||
environmentVariables.Add("Sonarr_Series_TvdbId", series.TvdbId.ToString());
|
||||
environmentVariables.Add("Sonarr_Series_TvMazeId", series.TvMazeId.ToString());
|
||||
environmentVariables.Add("Sonarr_Series_TmdbId", series.TmdbId.ToString());
|
||||
environmentVariables.Add("Sonarr_Series_ImdbId", series.ImdbId ?? string.Empty);
|
||||
environmentVariables.Add("Sonarr_Series_Type", series.SeriesType.ToString());
|
||||
environmentVariables.Add("Sonarr_Series_Year", series.Year.ToString());
|
||||
environmentVariables.Add("Sonarr_Series_OriginalLanguage", IsoLanguages.Get(series.OriginalLanguage).ThreeLetterCode);
|
||||
environmentVariables.Add("Sonarr_Series_Genres", string.Join("|", series.Genres));
|
||||
environmentVariables.Add("Sonarr_Series_Tags", string.Join("|", GetTagLabels(series)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_Ids", string.Join("|", episodeFiles.Select(f => f.Id)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_Count", message.EpisodeFiles.Count.ToString());
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_RelativePaths", string.Join("|", episodeFiles.Select(f => f.RelativePath)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_Paths", string.Join("|", episodeFiles.Select(f => Path.Combine(series.Path, f.RelativePath))));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeIds", string.Join(",", episodes.Select(e => e.Id)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_SeasonNumber", episodes.First().SeasonNumber.ToString());
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeNumbers", string.Join(",", episodes.Select(e => e.EpisodeNumber)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeAirDates", string.Join(",", episodes.Select(e => e.AirDate)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeAirDatesUtc", string.Join(",", episodes.Select(e => e.AirDateUtc)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeTitles", string.Join("|", episodes.Select(e => e.Title)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeOverviews", string.Join("|", episodes.Select(e => e.Overview)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_Qualities", string.Join("|", episodeFiles.Select(f => f.Quality.Quality.Name)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_QualityVersions", string.Join("|", episodeFiles.Select(f => f.Quality.Revision.Version)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_ReleaseGroups", string.Join("|", episodeFiles.Select(f => f.ReleaseGroup)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_SceneNames", string.Join("|", episodeFiles.Select(f => f.SceneName)));
|
||||
environmentVariables.Add("Sonarr_Download_Client", message.DownloadClientInfo?.Name ?? string.Empty);
|
||||
environmentVariables.Add("Sonarr_Download_Client_Type", message.DownloadClientInfo?.Type ?? string.Empty);
|
||||
environmentVariables.Add("Sonarr_Download_Id", message.DownloadId ?? string.Empty);
|
||||
environmentVariables.Add("Sonarr_Release_Group", message.ReleaseGroup ?? string.Empty);
|
||||
environmentVariables.Add("Sonarr_Release_Quality", message.ReleaseQuality.Quality.Name);
|
||||
environmentVariables.Add("Sonarr_Release_QualityVersion", message.ReleaseQuality.Revision.Version.ToString());
|
||||
environmentVariables.Add("Sonarr_Release_Indexer", message.Release?.Indexer ?? string.Empty);
|
||||
environmentVariables.Add("Sonarr_Release_Size", message.Release?.Size.ToString() ?? string.Empty);
|
||||
environmentVariables.Add("Sonarr_Release_Title", message.Release?.Title ?? string.Empty);
|
||||
|
||||
// Prefer the release type from the release, otherwise use the first imported file (useful for untracked manual imports)
|
||||
environmentVariables.Add("Sonarr_Release_ReleaseType", message.Release == null ? message.EpisodeFiles.First().ReleaseType.ToString() : message.Release.ReleaseType.ToString());
|
||||
environmentVariables.Add("Sonarr_SourcePath", sourcePath);
|
||||
environmentVariables.Add("Sonarr_SourceFolder", Path.GetDirectoryName(sourcePath));
|
||||
environmentVariables.Add("Sonarr_DestinationPath", message.DestinationPath);
|
||||
environmentVariables.Add("Sonarr_DestinationFolder", Path.GetDirectoryName(message.DestinationPath));
|
||||
|
||||
ExecuteScript(environmentVariables);
|
||||
}
|
||||
|
||||
public override void OnRename(Series series, List<RenamedEpisodeFile> renamedFiles)
|
||||
{
|
||||
var environmentVariables = new StringDictionary();
|
||||
|
@ -43,6 +43,13 @@ namespace NzbDrone.Core.Notifications.Email
|
||||
SendEmail(Settings, EPISODE_DOWNLOADED_TITLE_BRANDED, body);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
var body = $"All expected episode files in {message.Message} downloaded and sorted.";
|
||||
|
||||
SendEmail(Settings, IMPORT_COMPLETE_TITLE, body);
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
var body = $"{deleteMessage.Message} deleted.";
|
||||
|
@ -36,6 +36,11 @@ namespace NzbDrone.Core.Notifications.Gotify
|
||||
SendNotification(EPISODE_DOWNLOADED_TITLE, message.Message, message.Series);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
SendNotification(IMPORT_COMPLETE_TITLE, message.Message, message.Series);
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage message)
|
||||
{
|
||||
SendNotification(EPISODE_DELETED_TITLE, message.Message, message.Series);
|
||||
|
@ -12,6 +12,7 @@ namespace NzbDrone.Core.Notifications
|
||||
void OnGrab(GrabMessage grabMessage);
|
||||
void OnDownload(DownloadMessage message);
|
||||
void OnRename(Series series, List<RenamedEpisodeFile> renamedFiles);
|
||||
void OnImportComplete(ImportCompleteMessage message);
|
||||
void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage);
|
||||
void OnSeriesAdd(SeriesAddMessage message);
|
||||
void OnSeriesDelete(SeriesDeleteMessage deleteMessage);
|
||||
@ -23,6 +24,7 @@ namespace NzbDrone.Core.Notifications
|
||||
bool SupportsOnGrab { get; }
|
||||
bool SupportsOnDownload { get; }
|
||||
bool SupportsOnUpgrade { get; }
|
||||
bool SupportsOnImportComplete { get; }
|
||||
bool SupportsOnRename { get; }
|
||||
bool SupportsOnSeriesAdd { get; }
|
||||
bool SupportsOnSeriesDelete { get; }
|
||||
|
29
src/NzbDrone.Core/Notifications/ImportCompleteMessage.cs
Normal file
29
src/NzbDrone.Core/Notifications/ImportCompleteMessage.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Notifications
|
||||
{
|
||||
public class ImportCompleteMessage
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public Series Series { get; set; }
|
||||
public List<Episode> Episodes { get; set; }
|
||||
public List<EpisodeFile> EpisodeFiles { get; set; }
|
||||
public string SourcePath { get; set; }
|
||||
public DownloadClientItemClientInfo DownloadClientInfo { get; set; }
|
||||
public string DownloadId { get; set; }
|
||||
public GrabbedReleaseInfo Release { get; set; }
|
||||
public string DestinationPath { get; set; }
|
||||
public string ReleaseGroup { get; set; }
|
||||
public QualityModel ReleaseQuality { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Message;
|
||||
}
|
||||
}
|
||||
}
|
@ -27,6 +27,11 @@ namespace NzbDrone.Core.Notifications.Join
|
||||
_proxy.SendNotification(EPISODE_DOWNLOADED_TITLE_BRANDED, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
_proxy.SendNotification(IMPORT_COMPLETE_TITLE_BRANDED, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
_proxy.SendNotification(EPISODE_DELETED_TITLE_BRANDED, deleteMessage.Message, Settings);
|
||||
|
@ -32,6 +32,11 @@ namespace NzbDrone.Core.Notifications.Mailgun
|
||||
_proxy.SendNotification(EPISODE_DOWNLOADED_TITLE, downloadMessage.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
_proxy.SendNotification(IMPORT_COMPLETE_TITLE, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
var body = $"{deleteMessage.Message} deleted.";
|
||||
|
@ -39,6 +39,19 @@ namespace NzbDrone.Core.Notifications.Emby
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
if (Settings.Notify)
|
||||
{
|
||||
_mediaBrowserService.Notify(Settings, IMPORT_COMPLETE_TITLE_BRANDED, message.Message);
|
||||
}
|
||||
|
||||
if (Settings.UpdateLibrary)
|
||||
{
|
||||
_mediaBrowserService.Update(Settings, message.Series, "Created");
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnRename(Series series, List<RenamedEpisodeFile> renamedFiles)
|
||||
{
|
||||
if (Settings.UpdateLibrary)
|
||||
|
@ -35,6 +35,11 @@ namespace NzbDrone.Core.Notifications.Notifiarr
|
||||
_proxy.SendNotification(BuildOnDownloadPayload(message), Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
_proxy.SendNotification(BuildOnImportCompletePayload(message), Settings);
|
||||
}
|
||||
|
||||
public override void OnRename(Series series, List<RenamedEpisodeFile> renamedFiles)
|
||||
{
|
||||
_proxy.SendNotification(BuildOnRenamePayload(series, renamedFiles), Settings);
|
||||
|
@ -12,6 +12,7 @@ namespace NzbDrone.Core.Notifications
|
||||
{
|
||||
protected const string EPISODE_GRABBED_TITLE = "Episode Grabbed";
|
||||
protected const string EPISODE_DOWNLOADED_TITLE = "Episode Downloaded";
|
||||
protected const string IMPORT_COMPLETE_TITLE = "Import Complete";
|
||||
protected const string EPISODE_DELETED_TITLE = "Episode Deleted";
|
||||
protected const string SERIES_ADDED_TITLE = "Series Added";
|
||||
protected const string SERIES_DELETED_TITLE = "Series Deleted";
|
||||
@ -22,6 +23,7 @@ namespace NzbDrone.Core.Notifications
|
||||
|
||||
protected const string EPISODE_GRABBED_TITLE_BRANDED = "Sonarr - " + EPISODE_GRABBED_TITLE;
|
||||
protected const string EPISODE_DOWNLOADED_TITLE_BRANDED = "Sonarr - " + EPISODE_DOWNLOADED_TITLE;
|
||||
protected const string IMPORT_COMPLETE_TITLE_BRANDED = "Sonarr - " + IMPORT_COMPLETE_TITLE;
|
||||
protected const string EPISODE_DELETED_TITLE_BRANDED = "Sonarr - " + EPISODE_DELETED_TITLE;
|
||||
protected const string SERIES_ADDED_TITLE_BRANDED = "Sonarr - " + SERIES_ADDED_TITLE;
|
||||
protected const string SERIES_DELETED_TITLE_BRANDED = "Sonarr - " + SERIES_DELETED_TITLE;
|
||||
@ -51,6 +53,10 @@ namespace NzbDrone.Core.Notifications
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnRename(Series series, List<RenamedEpisodeFile> renamedFiles)
|
||||
{
|
||||
}
|
||||
@ -91,6 +97,7 @@ namespace NzbDrone.Core.Notifications
|
||||
public bool SupportsOnRename => HasConcreteImplementation("OnRename");
|
||||
public bool SupportsOnDownload => HasConcreteImplementation("OnDownload");
|
||||
public bool SupportsOnUpgrade => SupportsOnDownload;
|
||||
public bool SupportsOnImportComplete => HasConcreteImplementation("OnImportComplete");
|
||||
public bool SupportsOnSeriesAdd => HasConcreteImplementation("OnSeriesAdd");
|
||||
public bool SupportsOnSeriesDelete => HasConcreteImplementation("OnSeriesDelete");
|
||||
public bool SupportsOnEpisodeFileDelete => HasConcreteImplementation("OnEpisodeFileDelete");
|
||||
|
@ -11,6 +11,7 @@ namespace NzbDrone.Core.Notifications
|
||||
public bool OnGrab { get; set; }
|
||||
public bool OnDownload { get; set; }
|
||||
public bool OnUpgrade { get; set; }
|
||||
public bool OnImportComplete { get; set; }
|
||||
public bool OnRename { get; set; }
|
||||
public bool OnSeriesAdd { get; set; }
|
||||
public bool OnSeriesDelete { get; set; }
|
||||
@ -34,6 +35,9 @@ namespace NzbDrone.Core.Notifications
|
||||
[MemberwiseEqualityIgnore]
|
||||
public bool SupportsOnRename { get; set; }
|
||||
|
||||
[MemberwiseEqualityIgnore]
|
||||
public bool SupportsOnImportComplete { get; set; }
|
||||
|
||||
[MemberwiseEqualityIgnore]
|
||||
public bool SupportsOnSeriesAdd { get; set; }
|
||||
|
||||
@ -59,7 +63,7 @@ namespace NzbDrone.Core.Notifications
|
||||
public bool SupportsOnManualInteractionRequired { get; set; }
|
||||
|
||||
[MemberwiseEqualityIgnore]
|
||||
public override bool Enable => OnGrab || OnDownload || (OnDownload && OnUpgrade) || OnRename || OnSeriesAdd || OnSeriesDelete || OnEpisodeFileDelete || (OnEpisodeFileDelete && OnEpisodeFileDeleteForUpgrade) || OnHealthIssue || OnHealthRestored || OnApplicationUpdate || OnManualInteractionRequired;
|
||||
public override bool Enable => OnGrab || OnDownload || (OnDownload && OnUpgrade) || OnImportComplete || OnRename || OnSeriesAdd || OnSeriesDelete || OnEpisodeFileDelete || (OnEpisodeFileDelete && OnEpisodeFileDeleteForUpgrade) || OnHealthIssue || OnHealthRestored || OnApplicationUpdate || OnManualInteractionRequired;
|
||||
|
||||
public bool Equals(NotificationDefinition other)
|
||||
{
|
||||
|
@ -13,6 +13,7 @@ namespace NzbDrone.Core.Notifications
|
||||
List<INotification> OnGrabEnabled(bool filterBlockedNotifications = true);
|
||||
List<INotification> OnDownloadEnabled(bool filterBlockedNotifications = true);
|
||||
List<INotification> OnUpgradeEnabled(bool filterBlockedNotifications = true);
|
||||
List<INotification> OnImportCompleteEnabled(bool filterBlockedNotifications = true);
|
||||
List<INotification> OnRenameEnabled(bool filterBlockedNotifications = true);
|
||||
List<INotification> OnSeriesAddEnabled(bool filterBlockedNotifications = true);
|
||||
List<INotification> OnSeriesDeleteEnabled(bool filterBlockedNotifications = true);
|
||||
@ -71,6 +72,16 @@ namespace NzbDrone.Core.Notifications
|
||||
return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnUpgrade).ToList();
|
||||
}
|
||||
|
||||
public List<INotification> OnImportCompleteEnabled(bool filterBlockedNotifications = true)
|
||||
{
|
||||
if (filterBlockedNotifications)
|
||||
{
|
||||
return FilterBlockedNotifications(GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnImportComplete)).ToList();
|
||||
}
|
||||
|
||||
return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnImportComplete).ToList();
|
||||
}
|
||||
|
||||
public List<INotification> OnRenameEnabled(bool filterBlockedNotifications = true)
|
||||
{
|
||||
if (filterBlockedNotifications)
|
||||
@ -184,6 +195,7 @@ namespace NzbDrone.Core.Notifications
|
||||
definition.SupportsOnGrab = provider.SupportsOnGrab;
|
||||
definition.SupportsOnDownload = provider.SupportsOnDownload;
|
||||
definition.SupportsOnUpgrade = provider.SupportsOnUpgrade;
|
||||
definition.SupportsOnImportComplete = provider.SupportsOnImportComplete;
|
||||
definition.SupportsOnRename = provider.SupportsOnRename;
|
||||
definition.SupportsOnSeriesAdd = provider.SupportsOnSeriesAdd;
|
||||
definition.SupportsOnSeriesDelete = provider.SupportsOnSeriesDelete;
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
@ -18,6 +19,8 @@ namespace NzbDrone.Core.Notifications
|
||||
public class NotificationService
|
||||
: IHandle<EpisodeGrabbedEvent>,
|
||||
IHandle<EpisodeImportedEvent>,
|
||||
IHandle<DownloadCompletedEvent>,
|
||||
IHandle<UntrackedDownloadCompletedEvent>,
|
||||
IHandle<SeriesRenamedEvent>,
|
||||
IHandle<SeriesAddCompletedEvent>,
|
||||
IHandle<SeriesDeletedEvent>,
|
||||
@ -44,19 +47,7 @@ namespace NzbDrone.Core.Notifications
|
||||
|
||||
private string GetMessage(Series series, List<Episode> episodes, QualityModel quality)
|
||||
{
|
||||
var qualityString = quality.Quality.ToString();
|
||||
|
||||
if (quality.Revision.Version > 1)
|
||||
{
|
||||
if (series.SeriesType == SeriesTypes.Anime)
|
||||
{
|
||||
qualityString += " v" + quality.Revision.Version;
|
||||
}
|
||||
else
|
||||
{
|
||||
qualityString += " Proper";
|
||||
}
|
||||
}
|
||||
var qualityString = GetQualityString(series, quality);
|
||||
|
||||
if (series.SeriesType == SeriesTypes.Daily)
|
||||
{
|
||||
@ -82,6 +73,35 @@ namespace NzbDrone.Core.Notifications
|
||||
qualityString);
|
||||
}
|
||||
|
||||
private string GetFullSeasonMessage(Series series, int seasonNumber, QualityModel quality)
|
||||
{
|
||||
var qualityString = GetQualityString(series, quality);
|
||||
|
||||
return string.Format("{0} - Season {1} [{2}]",
|
||||
series.Title,
|
||||
seasonNumber,
|
||||
qualityString);
|
||||
}
|
||||
|
||||
private string GetQualityString(Series series, QualityModel quality)
|
||||
{
|
||||
var qualityString = quality.Quality.ToString();
|
||||
|
||||
if (quality.Revision.Version > 1)
|
||||
{
|
||||
if (series.SeriesType == SeriesTypes.Anime)
|
||||
{
|
||||
qualityString += " v" + quality.Revision.Version;
|
||||
}
|
||||
else
|
||||
{
|
||||
qualityString += " Proper";
|
||||
}
|
||||
}
|
||||
|
||||
return qualityString;
|
||||
}
|
||||
|
||||
private bool ShouldHandleSeries(ProviderDefinition definition, Series series)
|
||||
{
|
||||
if (definition.Tags.Empty())
|
||||
@ -189,6 +209,91 @@ namespace NzbDrone.Core.Notifications
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(DownloadCompletedEvent message)
|
||||
{
|
||||
var series = message.TrackedDownload.RemoteEpisode.Series;
|
||||
var episodes = message.TrackedDownload.RemoteEpisode.Episodes;
|
||||
var parsedEpisodeInfo = message.TrackedDownload.RemoteEpisode.ParsedEpisodeInfo;
|
||||
|
||||
var downloadMessage = new ImportCompleteMessage
|
||||
{
|
||||
Message = parsedEpisodeInfo.FullSeason
|
||||
? GetFullSeasonMessage(series, episodes.First().SeasonNumber, parsedEpisodeInfo.Quality)
|
||||
: GetMessage(series, episodes, parsedEpisodeInfo.Quality),
|
||||
Series = series,
|
||||
Episodes = episodes,
|
||||
EpisodeFiles = message.EpisodeFiles,
|
||||
DownloadClientInfo = message.TrackedDownload.DownloadItem.DownloadClientInfo,
|
||||
DownloadId = message.TrackedDownload.DownloadItem.DownloadId,
|
||||
Release = message.Release,
|
||||
SourcePath = message.TrackedDownload.DownloadItem.OutputPath.FullPath,
|
||||
DestinationPath = message.EpisodeFiles.Select(e => Path.Join(series.Path, e.RelativePath)).ToList().GetLongestCommonPath(),
|
||||
ReleaseGroup = parsedEpisodeInfo.ReleaseGroup,
|
||||
ReleaseQuality = parsedEpisodeInfo.Quality
|
||||
};
|
||||
|
||||
foreach (var notification in _notificationFactory.OnImportCompleteEnabled())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ShouldHandleSeries(notification.Definition, series))
|
||||
{
|
||||
if (((NotificationDefinition)notification.Definition).OnImportComplete)
|
||||
{
|
||||
notification.OnImportComplete(downloadMessage);
|
||||
_notificationStatusService.RecordSuccess(notification.Definition.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_notificationStatusService.RecordFailure(notification.Definition.Id);
|
||||
_logger.Warn(ex, "Unable to send OnImportComplete notification to: " + notification.Definition.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(UntrackedDownloadCompletedEvent message)
|
||||
{
|
||||
var series = message.Series;
|
||||
var episodes = message.Episodes;
|
||||
var parsedEpisodeInfo = message.ParsedEpisodeInfo;
|
||||
|
||||
var downloadMessage = new ImportCompleteMessage
|
||||
{
|
||||
Message = parsedEpisodeInfo.FullSeason
|
||||
? GetFullSeasonMessage(series, episodes.First().SeasonNumber, parsedEpisodeInfo.Quality)
|
||||
: GetMessage(series, episodes, parsedEpisodeInfo.Quality),
|
||||
Series = series,
|
||||
Episodes = episodes,
|
||||
EpisodeFiles = message.EpisodeFiles,
|
||||
SourcePath = message.SourcePath,
|
||||
DestinationPath = message.EpisodeFiles.Select(e => Path.Join(series.Path, e.RelativePath)).ToList().GetLongestCommonPath(),
|
||||
ReleaseGroup = parsedEpisodeInfo.ReleaseGroup,
|
||||
ReleaseQuality = parsedEpisodeInfo.Quality
|
||||
};
|
||||
|
||||
foreach (var notification in _notificationFactory.OnImportCompleteEnabled())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ShouldHandleSeries(notification.Definition, series))
|
||||
{
|
||||
if (((NotificationDefinition)notification.Definition).OnImportComplete)
|
||||
{
|
||||
notification.OnImportComplete(downloadMessage);
|
||||
_notificationStatusService.RecordSuccess(notification.Definition.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_notificationStatusService.RecordFailure(notification.Definition.Id);
|
||||
_logger.Warn(ex, "Unable to send OnImportComplete notification to: " + notification.Definition.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(SeriesRenamedEvent message)
|
||||
{
|
||||
foreach (var notification in _notificationFactory.OnRenameEnabled())
|
||||
|
@ -28,6 +28,11 @@ namespace NzbDrone.Core.Notifications.Ntfy
|
||||
_proxy.SendNotification(EPISODE_DOWNLOADED_TITLE_BRANDED, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
_proxy.SendNotification(IMPORT_COMPLETE_TITLE_BRANDED, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
_proxy.SendNotification(EPISODE_DELETED_TITLE, deleteMessage.Message, Settings);
|
||||
|
@ -45,6 +45,11 @@ namespace NzbDrone.Core.Notifications.Plex.Server
|
||||
UpdateIfEnabled(message.Series);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
UpdateIfEnabled(message.Series);
|
||||
}
|
||||
|
||||
public override void OnRename(Series series, List<RenamedEpisodeFile> renamedFiles)
|
||||
{
|
||||
UpdateIfEnabled(series);
|
||||
|
@ -26,6 +26,11 @@ namespace NzbDrone.Core.Notifications.Prowl
|
||||
_prowlProxy.SendNotification(EPISODE_DOWNLOADED_TITLE, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
_prowlProxy.SendNotification(IMPORT_COMPLETE_TITLE, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
_prowlProxy.SendNotification(EPISODE_DELETED_TITLE, deleteMessage.Message, Settings);
|
||||
|
@ -29,6 +29,11 @@ namespace NzbDrone.Core.Notifications.PushBullet
|
||||
_proxy.SendNotification(EPISODE_DOWNLOADED_TITLE_BRANDED, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
_proxy.SendNotification(IMPORT_COMPLETE_TITLE_BRANDED, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
_proxy.SendNotification(EPISODE_DELETED_TITLE, deleteMessage.Message, Settings);
|
||||
|
@ -36,6 +36,11 @@ namespace NzbDrone.Core.Notifications.Pushcut
|
||||
_proxy.SendNotification(EPISODE_DOWNLOADED_TITLE, downloadMessage.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
_proxy.SendNotification(IMPORT_COMPLETE_TITLE, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
_proxy.SendNotification(EPISODE_DELETED_TITLE, deleteMessage.Message, Settings);
|
||||
|
@ -26,6 +26,11 @@ namespace NzbDrone.Core.Notifications.Pushover
|
||||
_proxy.SendNotification(EPISODE_DOWNLOADED_TITLE, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
_proxy.SendNotification(IMPORT_COMPLETE_TITLE, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
_proxy.SendNotification(EPISODE_DELETED_TITLE, deleteMessage.Message, Settings);
|
||||
|
@ -32,6 +32,11 @@ namespace NzbDrone.Core.Notifications.SendGrid
|
||||
_proxy.SendNotification(EPISODE_DOWNLOADED_TITLE, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
_proxy.SendNotification(IMPORT_COMPLETE_TITLE, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
_proxy.SendNotification(EPISODE_DELETED_TITLE, deleteMessage.Message, Settings);
|
||||
|
@ -26,6 +26,11 @@ namespace NzbDrone.Core.Notifications.Signal
|
||||
_proxy.SendNotification(EPISODE_DOWNLOADED_TITLE, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
_proxy.SendNotification(IMPORT_COMPLETE_TITLE, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
_proxy.SendNotification(EPISODE_DELETED_TITLE, deleteMessage.Message, Settings);
|
||||
|
@ -26,6 +26,11 @@ namespace NzbDrone.Core.Notifications.Simplepush
|
||||
_proxy.SendNotification(EPISODE_DOWNLOADED_TITLE, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
_proxy.SendNotification(IMPORT_COMPLETE_TITLE, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
_proxy.SendNotification(EPISODE_DELETED_TITLE, deleteMessage.Message, Settings);
|
||||
|
@ -59,6 +59,23 @@ namespace NzbDrone.Core.Notifications.Slack
|
||||
_proxy.SendPayload(payload, Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
var attachments = new List<Attachment>
|
||||
{
|
||||
new Attachment
|
||||
{
|
||||
Fallback = message.Message,
|
||||
Title = message.Series.Title,
|
||||
Text = message.Message,
|
||||
Color = "good"
|
||||
}
|
||||
};
|
||||
var payload = CreatePayload($"Imported all expected episodes: {message.Message}", attachments);
|
||||
|
||||
_proxy.SendPayload(payload, Settings);
|
||||
}
|
||||
|
||||
public override void OnRename(Series series, List<RenamedEpisodeFile> renamedFiles)
|
||||
{
|
||||
var attachments = new List<Attachment>
|
||||
|
@ -42,6 +42,14 @@ namespace NzbDrone.Core.Notifications.Synology
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
if (Settings.UpdateLibrary)
|
||||
{
|
||||
_indexerProxy.UpdateFolder(message.Series.Path);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnRename(Series series, List<RenamedEpisodeFile> renamedFiles)
|
||||
{
|
||||
if (Settings.UpdateLibrary)
|
||||
|
@ -30,6 +30,13 @@ namespace NzbDrone.Core.Notifications.Telegram
|
||||
_proxy.SendNotification(title, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
var title = Settings.IncludeAppNameInTitle ? EPISODE_DOWNLOADED_TITLE_BRANDED : EPISODE_DOWNLOADED_TITLE;
|
||||
|
||||
_proxy.SendNotification(title, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
var title = Settings.IncludeAppNameInTitle ? EPISODE_DELETED_TITLE_BRANDED : EPISODE_DELETED_TITLE;
|
||||
|
@ -39,6 +39,13 @@ namespace NzbDrone.Core.Notifications.Trakt
|
||||
AddEpisodeToCollection(Settings, message.Series, message.EpisodeFile);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
RefreshTokenIfNecessary();
|
||||
|
||||
message.EpisodeFiles.ForEach(f => AddEpisodeToCollection(Settings, message.Series, f));
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
RefreshTokenIfNecessary();
|
||||
|
@ -28,6 +28,11 @@ namespace NzbDrone.Core.Notifications.Twitter
|
||||
_twitterService.SendNotification($"Imported: {message.Message}", Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
_twitterService.SendNotification($"Imported: {message.Message}", Settings);
|
||||
}
|
||||
|
||||
public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
_twitterService.SendNotification($"Episode Deleted: {deleteMessage.Message}", Settings);
|
||||
|
@ -33,6 +33,11 @@ namespace NzbDrone.Core.Notifications.Webhook
|
||||
_proxy.SendWebhook(BuildOnDownloadPayload(message), Settings);
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
_proxy.SendWebhook(BuildOnImportCompletePayload(message), Settings);
|
||||
}
|
||||
|
||||
public override void OnRename(Series series, List<RenamedEpisodeFile> renamedFiles)
|
||||
{
|
||||
_proxy.SendWebhook(BuildOnRenamePayload(series, renamedFiles), Settings);
|
||||
|
@ -81,6 +81,29 @@ namespace NzbDrone.Core.Notifications.Webhook
|
||||
return payload;
|
||||
}
|
||||
|
||||
protected WebhookImportCompletePayload BuildOnImportCompletePayload(ImportCompleteMessage message)
|
||||
{
|
||||
var episodeFiles = message.EpisodeFiles;
|
||||
|
||||
var payload = new WebhookImportCompletePayload
|
||||
{
|
||||
EventType = WebhookEventType.Download,
|
||||
InstanceName = _configFileProvider.InstanceName,
|
||||
ApplicationUrl = _configService.ApplicationUrl,
|
||||
Series = GetSeries(message.Series),
|
||||
Episodes = message.Episodes.ConvertAll(x => new WebhookEpisode(x)),
|
||||
EpisodeFiles = episodeFiles.ConvertAll(e => new WebhookEpisodeFile(e)),
|
||||
Release = new WebhookGrabbedRelease(message.Release, episodeFiles.First().ReleaseType),
|
||||
DownloadClient = message.DownloadClientInfo?.Name,
|
||||
DownloadClientType = message.DownloadClientInfo?.Type,
|
||||
DownloadId = message.DownloadId,
|
||||
SourcePath = message.SourcePath,
|
||||
DestinationPath = message.DestinationPath
|
||||
};
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
protected WebhookEpisodeDeletePayload BuildOnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
|
||||
{
|
||||
return new WebhookEpisodeDeletePayload
|
||||
|
@ -18,10 +18,27 @@ namespace NzbDrone.Core.Notifications.Webhook
|
||||
ReleaseTitle = release.Title;
|
||||
Indexer = release.Indexer;
|
||||
Size = release.Size;
|
||||
ReleaseType = release.ReleaseType;
|
||||
}
|
||||
|
||||
public WebhookGrabbedRelease(GrabbedReleaseInfo release, ReleaseType releaseType)
|
||||
{
|
||||
if (release == null)
|
||||
{
|
||||
ReleaseType = releaseType;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ReleaseTitle = release.Title;
|
||||
Indexer = release.Indexer;
|
||||
Size = release.Size;
|
||||
ReleaseType = release.ReleaseType;
|
||||
}
|
||||
|
||||
public string ReleaseTitle { get; set; }
|
||||
public string Indexer { get; set; }
|
||||
public long Size { get; set; }
|
||||
public long? Size { get; set; }
|
||||
public ReleaseType ReleaseType { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Notifications.Webhook
|
||||
{
|
||||
public class WebhookImportCompletePayload : WebhookPayload
|
||||
{
|
||||
public WebhookSeries Series { get; set; }
|
||||
public List<WebhookEpisode> Episodes { get; set; }
|
||||
public List<WebhookEpisodeFile> EpisodeFiles { get; set; }
|
||||
public string DownloadClient { get; set; }
|
||||
public string DownloadClientType { get; set; }
|
||||
public string DownloadId { get; set; }
|
||||
public WebhookGrabbedRelease Release { get; set; }
|
||||
public int FileCount => EpisodeFiles.Count;
|
||||
public string SourcePath { get; set; }
|
||||
public string DestinationPath { get; set; }
|
||||
}
|
||||
}
|
@ -37,6 +37,14 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
||||
UpdateAndClean(message.Series, message.OldFiles.Any());
|
||||
}
|
||||
|
||||
public override void OnImportComplete(ImportCompleteMessage message)
|
||||
{
|
||||
const string header = "Sonarr - Imported";
|
||||
|
||||
Notify(Settings, header, message.Message);
|
||||
UpdateAndClean(message.Series);
|
||||
}
|
||||
|
||||
public override void OnRename(Series series, List<RenamedEpisodeFile> renamedFiles)
|
||||
{
|
||||
UpdateAndClean(series);
|
||||
|
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.History;
|
||||
@ -9,6 +10,7 @@ namespace NzbDrone.Core.Parser.Model
|
||||
public string Title { get; set; }
|
||||
public string Indexer { get; set; }
|
||||
public long Size { get; set; }
|
||||
public ReleaseType ReleaseType { get; set; }
|
||||
|
||||
public List<int> EpisodeIds { get; set; }
|
||||
|
||||
@ -19,12 +21,14 @@ namespace NzbDrone.Core.Parser.Model
|
||||
|
||||
grabbedHistory.Data.TryGetValue("indexer", out var indexer);
|
||||
grabbedHistory.Data.TryGetValue("size", out var sizeString);
|
||||
Enum.TryParse(grabbedHistory.Data.GetValueOrDefault("releaseType"), out ReleaseType releaseType);
|
||||
long.TryParse(sizeString, out var size);
|
||||
|
||||
Title = grabbedHistory.SourceTitle;
|
||||
Indexer = indexer;
|
||||
Size = size;
|
||||
EpisodeIds = episodeIds;
|
||||
ReleaseType = releaseType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ namespace Sonarr.Api.V3.Notifications
|
||||
public bool OnGrab { get; set; }
|
||||
public bool OnDownload { get; set; }
|
||||
public bool OnUpgrade { get; set; }
|
||||
public bool OnImportComplete { get; set; }
|
||||
public bool OnRename { get; set; }
|
||||
public bool OnSeriesAdd { get; set; }
|
||||
public bool OnSeriesDelete { get; set; }
|
||||
@ -21,6 +22,7 @@ namespace Sonarr.Api.V3.Notifications
|
||||
public bool SupportsOnGrab { get; set; }
|
||||
public bool SupportsOnDownload { get; set; }
|
||||
public bool SupportsOnUpgrade { get; set; }
|
||||
public bool SupportsOnImportComplete { get; set; }
|
||||
public bool SupportsOnRename { get; set; }
|
||||
public bool SupportsOnSeriesAdd { get; set; }
|
||||
public bool SupportsOnSeriesDelete { get; set; }
|
||||
@ -47,6 +49,7 @@ namespace Sonarr.Api.V3.Notifications
|
||||
resource.OnGrab = definition.OnGrab;
|
||||
resource.OnDownload = definition.OnDownload;
|
||||
resource.OnUpgrade = definition.OnUpgrade;
|
||||
resource.OnImportComplete = definition.OnImportComplete;
|
||||
resource.OnRename = definition.OnRename;
|
||||
resource.OnSeriesAdd = definition.OnSeriesAdd;
|
||||
resource.OnSeriesDelete = definition.OnSeriesDelete;
|
||||
@ -60,6 +63,7 @@ namespace Sonarr.Api.V3.Notifications
|
||||
resource.SupportsOnGrab = definition.SupportsOnGrab;
|
||||
resource.SupportsOnDownload = definition.SupportsOnDownload;
|
||||
resource.SupportsOnUpgrade = definition.SupportsOnUpgrade;
|
||||
resource.SupportsOnImportComplete = definition.SupportsOnImportComplete;
|
||||
resource.SupportsOnRename = definition.SupportsOnRename;
|
||||
resource.SupportsOnSeriesAdd = definition.SupportsOnSeriesAdd;
|
||||
resource.SupportsOnSeriesDelete = definition.SupportsOnSeriesDelete;
|
||||
@ -85,6 +89,7 @@ namespace Sonarr.Api.V3.Notifications
|
||||
definition.OnGrab = resource.OnGrab;
|
||||
definition.OnDownload = resource.OnDownload;
|
||||
definition.OnUpgrade = resource.OnUpgrade;
|
||||
definition.OnImportComplete = resource.OnImportComplete;
|
||||
definition.OnRename = resource.OnRename;
|
||||
definition.OnSeriesAdd = resource.OnSeriesAdd;
|
||||
definition.OnSeriesDelete = resource.OnSeriesDelete;
|
||||
@ -98,6 +103,7 @@ namespace Sonarr.Api.V3.Notifications
|
||||
definition.SupportsOnGrab = resource.SupportsOnGrab;
|
||||
definition.SupportsOnDownload = resource.SupportsOnDownload;
|
||||
definition.SupportsOnUpgrade = resource.SupportsOnUpgrade;
|
||||
definition.SupportsOnImportComplete = resource.SupportsOnImportComplete;
|
||||
definition.SupportsOnRename = resource.SupportsOnRename;
|
||||
definition.SupportsOnSeriesAdd = resource.SupportsOnSeriesAdd;
|
||||
definition.SupportsOnSeriesDelete = resource.SupportsOnSeriesDelete;
|
||||
|
Loading…
Reference in New Issue
Block a user