mirror of
https://github.com/Sonarr/Sonarr.git
synced 2024-11-26 04:33:01 +01:00
parent
365a6e77a6
commit
9f1e215120
@ -68,27 +68,27 @@ class MediaManagement extends Component {
|
||||
<NamingConnector />
|
||||
|
||||
{
|
||||
isFetching &&
|
||||
isFetching ?
|
||||
<FieldSet legend="Naming Settings">
|
||||
<LoadingIndicator />
|
||||
</FieldSet>
|
||||
</FieldSet> : null
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && error &&
|
||||
!isFetching && error ?
|
||||
<FieldSet legend="Naming Settings">
|
||||
<div>Unable to load Media Management settings</div>
|
||||
</FieldSet>
|
||||
</FieldSet> : null
|
||||
}
|
||||
|
||||
{
|
||||
hasSettings && !isFetching && !error &&
|
||||
hasSettings && !isFetching && !error ?
|
||||
<Form
|
||||
id="mediaManagementSettings"
|
||||
{...otherProps}
|
||||
>
|
||||
{
|
||||
advancedSettings &&
|
||||
advancedSettings ?
|
||||
<FieldSet legend="Folders">
|
||||
<FormGroup
|
||||
advancedSettings={advancedSettings}
|
||||
@ -121,11 +121,11 @@ class MediaManagement extends Component {
|
||||
{...settings.deleteEmptyFolders}
|
||||
/>
|
||||
</FormGroup>
|
||||
</FieldSet>
|
||||
</FieldSet> : null
|
||||
}
|
||||
|
||||
{
|
||||
advancedSettings &&
|
||||
advancedSettings ?
|
||||
<FieldSet
|
||||
legend="Importing"
|
||||
>
|
||||
@ -200,6 +200,41 @@ class MediaManagement extends Component {
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
size={sizes.MEDIUM}
|
||||
>
|
||||
<FormLabel>Import Using Script</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="useScriptImport"
|
||||
helpText="Copy files for importing using a script (ex. for transcoding)"
|
||||
onChange={onInputChange}
|
||||
{...settings.useScriptImport}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
{
|
||||
settings.useScriptImport.value ?
|
||||
<FormGroup
|
||||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
>
|
||||
<FormLabel>Import Script Path</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.PATH}
|
||||
includeFiles={true}
|
||||
name="scriptImportPath"
|
||||
helpText="The path to the script to use for importing"
|
||||
onChange={onInputChange}
|
||||
{...settings.scriptImportPath}
|
||||
/>
|
||||
</FormGroup> : null
|
||||
}
|
||||
|
||||
<FormGroup size={sizes.MEDIUM}>
|
||||
<FormLabel>Import Extra Files</FormLabel>
|
||||
|
||||
@ -213,7 +248,7 @@ class MediaManagement extends Component {
|
||||
</FormGroup>
|
||||
|
||||
{
|
||||
settings.importExtraFiles.value &&
|
||||
settings.importExtraFiles.value ?
|
||||
<FormGroup
|
||||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
@ -230,9 +265,9 @@ class MediaManagement extends Component {
|
||||
onChange={onInputChange}
|
||||
{...settings.extraFileExtensions}
|
||||
/>
|
||||
</FormGroup>
|
||||
</FormGroup> : null
|
||||
}
|
||||
</FieldSet>
|
||||
</FieldSet> : null
|
||||
}
|
||||
|
||||
<FieldSet
|
||||
@ -358,7 +393,7 @@ class MediaManagement extends Component {
|
||||
</FieldSet>
|
||||
|
||||
{
|
||||
advancedSettings && !isWindows &&
|
||||
advancedSettings && !isWindows ?
|
||||
<FieldSet
|
||||
legend="Permissions"
|
||||
>
|
||||
@ -411,9 +446,9 @@ class MediaManagement extends Component {
|
||||
{...settings.chownGroup}
|
||||
/>
|
||||
</FormGroup>
|
||||
</FieldSet>
|
||||
</FieldSet> : null
|
||||
}
|
||||
</Form>
|
||||
</Form> : null
|
||||
}
|
||||
|
||||
<FieldSet legend="Root Folders">
|
||||
|
@ -207,6 +207,20 @@ namespace NzbDrone.Core.Configuration
|
||||
set { SetValue("EnableMediaInfo", value); }
|
||||
}
|
||||
|
||||
public bool UseScriptImport
|
||||
{
|
||||
get { return GetValueBoolean("UseScriptImport", false); }
|
||||
|
||||
set { SetValue("UseScriptImport", value); }
|
||||
}
|
||||
|
||||
public string ScriptImportPath
|
||||
{
|
||||
get { return GetValue("ScriptImportPath"); }
|
||||
|
||||
set { SetValue("ScriptImportPath", value); }
|
||||
}
|
||||
|
||||
public bool ImportExtraFiles
|
||||
{
|
||||
get { return GetValueBoolean("ImportExtraFiles", false); }
|
||||
|
@ -33,6 +33,8 @@ namespace NzbDrone.Core.Configuration
|
||||
int MinimumFreeSpaceWhenImporting { get; set; }
|
||||
bool CopyUsingHardlinks { get; set; }
|
||||
bool EnableMediaInfo { get; set; }
|
||||
bool UseScriptImport { get; set; }
|
||||
string ScriptImportPath { get; set; }
|
||||
bool ImportExtraFiles { get; set; }
|
||||
string ExtraFileExtensions { get; set; }
|
||||
RescanAfterRefreshType RescanAfterRefresh { get; set; }
|
||||
|
@ -31,6 +31,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
private readonly IDiskTransferService _diskTransferService;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IMediaFileAttributeService _mediaFileAttributeService;
|
||||
private readonly IImportScript _scriptImportDecider;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly Logger _logger;
|
||||
@ -41,6 +42,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
IDiskTransferService diskTransferService,
|
||||
IDiskProvider diskProvider,
|
||||
IMediaFileAttributeService mediaFileAttributeService,
|
||||
IImportScript scriptImportDecider,
|
||||
IEventAggregator eventAggregator,
|
||||
IConfigService configService,
|
||||
Logger logger)
|
||||
@ -51,6 +53,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
_diskTransferService = diskTransferService;
|
||||
_diskProvider = diskProvider;
|
||||
_mediaFileAttributeService = mediaFileAttributeService;
|
||||
_scriptImportDecider = scriptImportDecider;
|
||||
_eventAggregator = eventAggregator;
|
||||
_configService = configService;
|
||||
_logger = logger;
|
||||
@ -59,6 +62,11 @@ namespace NzbDrone.Core.MediaFiles
|
||||
public EpisodeFile MoveEpisodeFile(EpisodeFile episodeFile, Series series)
|
||||
{
|
||||
var episodes = _episodeService.GetEpisodesByFileId(episodeFile.Id);
|
||||
return MoveEpisodeFile(episodeFile, series, episodes);
|
||||
}
|
||||
|
||||
private EpisodeFile MoveEpisodeFile(EpisodeFile episodeFile, Series series, List<Episode> episodes)
|
||||
{
|
||||
var filePath = _buildFileNames.BuildFilePath(episodes, series, episodeFile, Path.GetExtension(episodeFile.RelativePath));
|
||||
|
||||
EnsureEpisodeFolder(episodeFile, series, episodes.Select(v => v.SeasonNumber).First(), filePath);
|
||||
@ -76,7 +84,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
|
||||
_logger.Debug("Moving episode file: {0} to {1}", episodeFile.Path, filePath);
|
||||
|
||||
return TransferFile(episodeFile, localEpisode.Series, localEpisode.Episodes, filePath, TransferMode.Move);
|
||||
return TransferFile(episodeFile, localEpisode.Series, localEpisode.Episodes, filePath, TransferMode.Move, localEpisode);
|
||||
}
|
||||
|
||||
public EpisodeFile CopyEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode)
|
||||
@ -88,14 +96,14 @@ namespace NzbDrone.Core.MediaFiles
|
||||
if (_configService.CopyUsingHardlinks)
|
||||
{
|
||||
_logger.Debug("Hardlinking episode file: {0} to {1}", episodeFile.Path, filePath);
|
||||
return TransferFile(episodeFile, localEpisode.Series, localEpisode.Episodes, filePath, TransferMode.HardLinkOrCopy);
|
||||
return TransferFile(episodeFile, localEpisode.Series, localEpisode.Episodes, filePath, TransferMode.HardLinkOrCopy, localEpisode);
|
||||
}
|
||||
|
||||
_logger.Debug("Copying episode file: {0} to {1}", episodeFile.Path, filePath);
|
||||
return TransferFile(episodeFile, localEpisode.Series, localEpisode.Episodes, filePath, TransferMode.Copy);
|
||||
return TransferFile(episodeFile, localEpisode.Series, localEpisode.Episodes, filePath, TransferMode.Copy, localEpisode);
|
||||
}
|
||||
|
||||
private EpisodeFile TransferFile(EpisodeFile episodeFile, Series series, List<Episode> episodes, string destinationFilePath, TransferMode mode)
|
||||
private EpisodeFile TransferFile(EpisodeFile episodeFile, Series series, List<Episode> episodes, string destinationFilePath, TransferMode mode, LocalEpisode localEpisode = null)
|
||||
{
|
||||
Ensure.That(episodeFile, () => episodeFile).IsNotNull();
|
||||
Ensure.That(series, () => series).IsNotNull();
|
||||
@ -113,10 +121,33 @@ namespace NzbDrone.Core.MediaFiles
|
||||
throw new SameFilenameException("File not moved, source and destination are the same", episodeFilePath);
|
||||
}
|
||||
|
||||
_diskTransferService.TransferFile(episodeFilePath, destinationFilePath, mode);
|
||||
var transfer = true;
|
||||
|
||||
episodeFile.RelativePath = series.Path.GetRelativePath(destinationFilePath);
|
||||
|
||||
if (localEpisode is not null)
|
||||
{
|
||||
var scriptImportDecision = _scriptImportDecider.TryImport(episodeFilePath, destinationFilePath, localEpisode, episodeFile, mode);
|
||||
|
||||
switch (scriptImportDecision)
|
||||
{
|
||||
case ScriptImportDecision.DeferMove:
|
||||
break;
|
||||
case ScriptImportDecision.RenameRequested:
|
||||
MoveEpisodeFile(episodeFile, series, episodeFile.Episodes);
|
||||
transfer = false;
|
||||
break;
|
||||
case ScriptImportDecision.MoveComplete:
|
||||
transfer = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (transfer)
|
||||
{
|
||||
_diskTransferService.TransferFile(episodeFilePath, destinationFilePath, mode);
|
||||
}
|
||||
|
||||
_updateEpisodeFileService.ChangeFileDateForFile(episodeFile, series, episodes);
|
||||
|
||||
try
|
||||
|
@ -9,6 +9,7 @@ using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Extras;
|
||||
using NzbDrone.Core.MediaFiles.Commands;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
@ -110,8 +111,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
episodeFile.SceneName = localEpisode.SceneName;
|
||||
episodeFile.OriginalFilePath = GetOriginalFilePath(downloadClientItem, localEpisode);
|
||||
|
||||
var moveResult = _episodeFileUpgrader.UpgradeEpisodeFile(episodeFile, localEpisode, copyOnly);
|
||||
oldFiles = moveResult.OldFiles;
|
||||
oldFiles = _episodeFileUpgrader.UpgradeEpisodeFile(episodeFile, localEpisode, copyOnly).OldFiles;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -89,6 +89,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
{
|
||||
Series = series,
|
||||
DownloadClientEpisodeInfo = downloadClientItemInfo,
|
||||
DownloadItem = downloadClientItem,
|
||||
FolderEpisodeInfo = folderInfo,
|
||||
Path = file,
|
||||
SceneSource = sceneSource,
|
||||
|
@ -161,6 +161,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
||||
localEpisode.Episodes = _episodeService.GetEpisodes(episodeIds);
|
||||
localEpisode.FileEpisodeInfo = Parser.Parser.ParsePath(path);
|
||||
localEpisode.DownloadClientEpisodeInfo = downloadClientItem == null ? null : Parser.Parser.ParseTitle(downloadClientItem.Title);
|
||||
localEpisode.DownloadItem = downloadClientItem;
|
||||
localEpisode.Path = path;
|
||||
localEpisode.SceneSource = SceneSource(series, rootFolder);
|
||||
localEpisode.ExistingFile = series.Path.IsParentPath(path);
|
||||
@ -187,6 +188,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
||||
DownloadClientEpisodeInfo = downloadClientItem == null
|
||||
? null
|
||||
: Parser.Parser.ParseTitle(downloadClientItem.Title),
|
||||
DownloadItem = downloadClientItem,
|
||||
Path = path,
|
||||
SceneSource = SceneSource(series, rootFolder),
|
||||
ExistingFile = series.Path.IsParentPath(path),
|
||||
@ -479,6 +481,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
||||
{
|
||||
trackedDownload = _trackedDownloadService.Find(file.DownloadId);
|
||||
localEpisode.DownloadClientEpisodeInfo = trackedDownload?.RemoteEpisode?.ParsedEpisodeInfo;
|
||||
localEpisode.DownloadItem = trackedDownload?.DownloadItem;
|
||||
}
|
||||
|
||||
if (file.FolderName.IsNotNullOrWhiteSpace())
|
||||
|
@ -12,6 +12,7 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
||||
public interface IUpdateMediaInfo
|
||||
{
|
||||
bool Update(EpisodeFile episodeFile, Series series);
|
||||
bool UpdateMediaInfo(EpisodeFile episodeFile, Series series);
|
||||
}
|
||||
|
||||
public class UpdateMediaInfoService : IUpdateMediaInfo, IHandle<SeriesScannedEvent>
|
||||
@ -65,7 +66,7 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
||||
return UpdateMediaInfo(episodeFile, series);
|
||||
}
|
||||
|
||||
private bool UpdateMediaInfo(EpisodeFile episodeFile, Series series)
|
||||
public bool UpdateMediaInfo(EpisodeFile episodeFile, Series series)
|
||||
{
|
||||
var path = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
|
||||
|
129
src/NzbDrone.Core/MediaFiles/ScriptImportDecider.cs
Normal file
129
src/NzbDrone.Core/MediaFiles/ScriptImportDecider.cs
Normal file
@ -0,0 +1,129 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Processes;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
public interface IImportScript
|
||||
{
|
||||
public ScriptImportDecision TryImport(string sourcePath, string destinationFilePath, LocalEpisode localEpisode, EpisodeFile episodeFile, TransferMode mode);
|
||||
}
|
||||
|
||||
public class ImportScriptService : IImportScript
|
||||
{
|
||||
private readonly IConfigFileProvider _configFileProvider;
|
||||
private readonly IVideoFileInfoReader _videoFileInfoReader;
|
||||
private readonly IProcessProvider _processProvider;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public ImportScriptService(IProcessProvider processProvider,
|
||||
IVideoFileInfoReader videoFileInfoReader,
|
||||
IConfigService configService,
|
||||
IConfigFileProvider configFileProvider,
|
||||
Logger logger)
|
||||
{
|
||||
_processProvider = processProvider;
|
||||
_videoFileInfoReader = videoFileInfoReader;
|
||||
_configService = configService;
|
||||
_configFileProvider = configFileProvider;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public ScriptImportDecision TryImport(string sourcePath, string destinationFilePath, LocalEpisode localEpisode, EpisodeFile episodeFile, TransferMode mode)
|
||||
{
|
||||
var series = localEpisode.Series;
|
||||
var oldFiles = localEpisode.OldFiles;
|
||||
var downloadClientInfo = localEpisode.DownloadItem?.DownloadClientInfo;
|
||||
var downloadId = localEpisode.DownloadItem?.DownloadId;
|
||||
|
||||
if (!_configService.UseScriptImport)
|
||||
{
|
||||
return ScriptImportDecision.DeferMove;
|
||||
}
|
||||
|
||||
var environmentVariables = new StringDictionary();
|
||||
|
||||
environmentVariables.Add("Sonarr_SourcePath", sourcePath);
|
||||
environmentVariables.Add("Sonarr_DestinationPath", destinationFilePath);
|
||||
|
||||
environmentVariables.Add("Sonarr_InstanceName", _configFileProvider.InstanceName);
|
||||
environmentVariables.Add("Sonarr_ApplicationUrl", _configService.ApplicationUrl);
|
||||
environmentVariables.Add("Sonarr_TransferMode", mode.ToString());
|
||||
|
||||
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_ImdbId", series.ImdbId ?? string.Empty);
|
||||
environmentVariables.Add("Sonarr_Series_Type", series.SeriesType.ToString());
|
||||
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeCount", localEpisode.Episodes.Count.ToString());
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeIds", string.Join(",", localEpisode.Episodes.Select(e => e.Id)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_SeasonNumber", localEpisode.SeasonNumber.ToString());
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeNumbers", string.Join(",", localEpisode.Episodes.Select(e => e.EpisodeNumber)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeAirDates", string.Join(",", localEpisode.Episodes.Select(e => e.AirDate)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeAirDatesUtc", string.Join(",", localEpisode.Episodes.Select(e => e.AirDateUtc)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeTitles", string.Join("|", localEpisode.Episodes.Select(e => e.Title)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeOverviews", string.Join("|", localEpisode.Episodes.Select(e => e.Overview)));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_Quality", localEpisode.Quality.Quality.Name);
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_QualityVersion", localEpisode.Quality.Revision.Version.ToString());
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_ReleaseGroup", localEpisode.ReleaseGroup ?? string.Empty);
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_SceneName", localEpisode.SceneName ?? string.Empty);
|
||||
|
||||
environmentVariables.Add("Sonarr_Download_Client", downloadClientInfo?.Name ?? string.Empty);
|
||||
environmentVariables.Add("Sonarr_Download_Client_Type", downloadClientInfo?.Type ?? string.Empty);
|
||||
environmentVariables.Add("Sonarr_Download_Id", downloadId ?? string.Empty);
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_MediaInfo_AudioChannels", MediaInfoFormatter.FormatAudioChannels(localEpisode.MediaInfo).ToString());
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_MediaInfo_AudioCodec", MediaInfoFormatter.FormatAudioCodec(localEpisode.MediaInfo, null));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_MediaInfo_AudioLanguages", localEpisode.MediaInfo.AudioLanguages.Distinct().ConcatToString(" / "));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_MediaInfo_Languages", localEpisode.MediaInfo.AudioLanguages.ConcatToString(" / "));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_MediaInfo_Height", localEpisode.MediaInfo.Height.ToString());
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_MediaInfo_Width", localEpisode.MediaInfo.Width.ToString());
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_MediaInfo_Subtitles", localEpisode.MediaInfo.Subtitles.ConcatToString(" / "));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_MediaInfo_VideoCodec", MediaInfoFormatter.FormatVideoCodec(localEpisode.MediaInfo, null));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_MediaInfo_VideoDynamicRangeType", MediaInfoFormatter.FormatVideoDynamicRangeType(localEpisode.MediaInfo));
|
||||
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_CustomFormat", string.Join("|", localEpisode.CustomFormats));
|
||||
environmentVariables.Add("Sonarr_EpisodeFile_CustomFormatScore", localEpisode.CustomFormatScore.ToString());
|
||||
|
||||
if (oldFiles.Any())
|
||||
{
|
||||
environmentVariables.Add("Sonarr_DeletedRelativePaths", string.Join("|", oldFiles.Select(e => e.RelativePath)));
|
||||
environmentVariables.Add("Sonarr_DeletedPaths", string.Join("|", oldFiles.Select(e => Path.Combine(series.Path, e.RelativePath))));
|
||||
environmentVariables.Add("Sonarr_DeletedDateAdded", string.Join("|", oldFiles.Select(e => e.DateAdded)));
|
||||
}
|
||||
|
||||
_logger.Debug("Executing external script: {0}", _configService.ScriptImportPath);
|
||||
|
||||
var processOutput = _processProvider.StartAndCapture(_configService.ScriptImportPath, $"\"{sourcePath}\" \"{destinationFilePath}\"", environmentVariables);
|
||||
|
||||
_logger.Debug("Executed external script: {0} - Status: {1}", _configService.ScriptImportPath, processOutput.ExitCode);
|
||||
_logger.Debug("Script Output: \r\n{0}", string.Join("\r\n", processOutput.Lines));
|
||||
|
||||
switch (processOutput.ExitCode)
|
||||
{
|
||||
case 0: // Copy complete
|
||||
return ScriptImportDecision.MoveComplete;
|
||||
case 2: // Copy complete, file potentially changed, should try renaming again
|
||||
episodeFile.MediaInfo = _videoFileInfoReader.GetMediaInfo(destinationFilePath);
|
||||
episodeFile.Path = null;
|
||||
return ScriptImportDecision.RenameRequested;
|
||||
case 3: // Let Sonarr handle it
|
||||
return ScriptImportDecision.DeferMove;
|
||||
default: // Error, fail to import
|
||||
throw new ScriptImportException("Moving with script failed! Exit code {0}", processOutput.ExitCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
src/NzbDrone.Core/MediaFiles/ScriptImportDecision.cs
Normal file
10
src/NzbDrone.Core/MediaFiles/ScriptImportDecision.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
public enum ScriptImportDecision
|
||||
{
|
||||
MoveComplete,
|
||||
RenameRequested,
|
||||
RejectExtra,
|
||||
DeferMove
|
||||
}
|
||||
}
|
23
src/NzbDrone.Core/MediaFiles/ScriptImportException.cs
Normal file
23
src/NzbDrone.Core/MediaFiles/ScriptImportException.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using NzbDrone.Common.Exceptions;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
public class ScriptImportException : NzbDroneException
|
||||
{
|
||||
public ScriptImportException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ScriptImportException(string message, params object[] args)
|
||||
: base(message, args)
|
||||
{
|
||||
}
|
||||
|
||||
public ScriptImportException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
@ -68,6 +69,8 @@ namespace NzbDrone.Core.MediaFiles
|
||||
_mediaFileService.Delete(file, DeleteMediaFileReason.Upgrade);
|
||||
}
|
||||
|
||||
localEpisode.OldFiles = moveFileResult.OldFiles;
|
||||
|
||||
if (copyOnly)
|
||||
{
|
||||
moveFileResult.EpisodeFile = _episodeFileMover.CopyEpisodeFile(episodeFile, localEpisode);
|
||||
|
@ -2,7 +2,9 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
@ -22,9 +24,11 @@ namespace NzbDrone.Core.Parser.Model
|
||||
public long Size { get; set; }
|
||||
public ParsedEpisodeInfo FileEpisodeInfo { get; set; }
|
||||
public ParsedEpisodeInfo DownloadClientEpisodeInfo { get; set; }
|
||||
public DownloadClientItem DownloadItem { get; set; }
|
||||
public ParsedEpisodeInfo FolderEpisodeInfo { get; set; }
|
||||
public Series Series { get; set; }
|
||||
public List<Episode> Episodes { get; set; }
|
||||
public List<EpisodeFile> OldFiles { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public List<Language> Languages { get; set; }
|
||||
public MediaInfoModel MediaInfo { get; set; }
|
||||
|
@ -34,6 +34,8 @@ namespace Sonarr.Api.V3.Config
|
||||
.SetValidator(seriesPathValidator)
|
||||
.When(c => !string.IsNullOrWhiteSpace(c.RecycleBin));
|
||||
|
||||
SharedValidator.RuleFor(c => c.ScriptImportPath).IsValidPath().When(c => c.UseScriptImport);
|
||||
|
||||
SharedValidator.RuleFor(c => c.MinimumFreeSpaceWhenImporting).GreaterThanOrEqualTo(100);
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,8 @@ namespace Sonarr.Api.V3.Config
|
||||
public bool SkipFreeSpaceCheckWhenImporting { get; set; }
|
||||
public int MinimumFreeSpaceWhenImporting { get; set; }
|
||||
public bool CopyUsingHardlinks { get; set; }
|
||||
public bool UseScriptImport { get; set; }
|
||||
public string ScriptImportPath { get; set; }
|
||||
public bool ImportExtraFiles { get; set; }
|
||||
public string ExtraFileExtensions { get; set; }
|
||||
public bool EnableMediaInfo { get; set; }
|
||||
@ -53,6 +55,8 @@ namespace Sonarr.Api.V3.Config
|
||||
SkipFreeSpaceCheckWhenImporting = model.SkipFreeSpaceCheckWhenImporting,
|
||||
MinimumFreeSpaceWhenImporting = model.MinimumFreeSpaceWhenImporting,
|
||||
CopyUsingHardlinks = model.CopyUsingHardlinks,
|
||||
UseScriptImport = model.UseScriptImport,
|
||||
ScriptImportPath = model.ScriptImportPath,
|
||||
ImportExtraFiles = model.ImportExtraFiles,
|
||||
ExtraFileExtensions = model.ExtraFileExtensions,
|
||||
EnableMediaInfo = model.EnableMediaInfo
|
||||
|
@ -9177,6 +9177,12 @@
|
||||
"copyUsingHardlinks": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"useScriptImport": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"scriptImportPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"importExtraFiles": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user