mirror of https://github.com/lidarr/Lidarr
New: Manual import refreshes decisions when artist/album updated (#540)
This commit is contained in:
parent
d62b4e49f9
commit
32c75cfcbc
|
@ -224,6 +224,16 @@ class SignalRConnector extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
handleManualimport = (body) => {
|
||||
if (body.action === 'updated') {
|
||||
this.props.dispatchUpdateItem({
|
||||
section: 'interactiveImport',
|
||||
updateOnly: true,
|
||||
...body.resource
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleQueue = () => {
|
||||
if (this.props.isQueuePopulated) {
|
||||
this.props.dispatchFetchQueue();
|
||||
|
|
|
@ -5,6 +5,7 @@ import { connect } from 'react-redux';
|
|||
import { createSelector } from 'reselect';
|
||||
import {
|
||||
updateInteractiveImportItem,
|
||||
saveInteractiveImportItem,
|
||||
fetchInteractiveImportAlbums,
|
||||
setInteractiveImportAlbumsSort,
|
||||
clearInteractiveImportAlbums
|
||||
|
@ -25,7 +26,8 @@ const mapDispatchToProps = {
|
|||
fetchInteractiveImportAlbums,
|
||||
setInteractiveImportAlbumsSort,
|
||||
clearInteractiveImportAlbums,
|
||||
updateInteractiveImportItem
|
||||
updateInteractiveImportItem,
|
||||
saveInteractiveImportItem
|
||||
};
|
||||
|
||||
class SelectAlbumModalContentConnector extends Component {
|
||||
|
@ -61,8 +63,10 @@ class SelectAlbumModalContentConnector extends Component {
|
|||
this.props.updateInteractiveImportItem({
|
||||
id,
|
||||
album,
|
||||
tracks: []
|
||||
tracks: [],
|
||||
rejections: []
|
||||
});
|
||||
this.props.saveInteractiveImportItem({ id });
|
||||
});
|
||||
|
||||
this.props.onModalClose(true);
|
||||
|
|
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
|||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { updateInteractiveImportItem } from 'Store/Actions/interactiveImportActions';
|
||||
import { updateInteractiveImportItem, saveInteractiveImportItem } from 'Store/Actions/interactiveImportActions';
|
||||
import createAllArtistSelector from 'Store/Selectors/createAllArtistSelector';
|
||||
import SelectArtistModalContent from './SelectArtistModalContent';
|
||||
|
||||
|
@ -29,7 +29,8 @@ function createMapStateToProps() {
|
|||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
updateInteractiveImportItem
|
||||
updateInteractiveImportItem,
|
||||
saveInteractiveImportItem
|
||||
};
|
||||
|
||||
class SelectArtistModalContentConnector extends Component {
|
||||
|
@ -45,8 +46,10 @@ class SelectArtistModalContentConnector extends Component {
|
|||
id,
|
||||
artist,
|
||||
album: undefined,
|
||||
tracks: []
|
||||
tracks: [],
|
||||
rejections: []
|
||||
});
|
||||
this.props.saveInteractiveImportItem({ id });
|
||||
});
|
||||
|
||||
this.props.onModalClose(true);
|
||||
|
|
|
@ -324,6 +324,7 @@ class InteractiveImportRow extends Component {
|
|||
id={id}
|
||||
artistId={artist && artist.id}
|
||||
albumId={album && album.id}
|
||||
filename={relativePath}
|
||||
onModalClose={this.onSelectTrackModalClose}
|
||||
/>
|
||||
|
||||
|
|
|
@ -87,7 +87,8 @@ class SelectTrackModalContent extends Component {
|
|||
sortKey,
|
||||
sortDirection,
|
||||
onSortPress,
|
||||
onModalClose
|
||||
onModalClose,
|
||||
filename
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
|
@ -96,12 +97,13 @@ class SelectTrackModalContent extends Component {
|
|||
selectedState
|
||||
} = this.state;
|
||||
|
||||
const title = `Manual Import - Select Track(s): ${filename}`;
|
||||
const errorMessage = getErrorMessage(error, 'Unable to load tracks');
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
Manual Import - Select Track(s)
|
||||
{title}
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
|
@ -179,7 +181,8 @@ SelectTrackModalContent.propTypes = {
|
|||
sortDirection: PropTypes.string,
|
||||
onSortPress: PropTypes.func.isRequired,
|
||||
onTracksSelect: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
onModalClose: PropTypes.func.isRequired,
|
||||
filename: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default SelectTrackModalContent;
|
||||
|
|
|
@ -8,6 +8,7 @@ import { sortDirections } from 'Helpers/Props';
|
|||
import createSetClientSideCollectionSortReducer from './Creators/Reducers/createSetClientSideCollectionSortReducer';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import createSaveProviderHandler from './Creators/createSaveProviderHandler';
|
||||
import { set, update } from './baseActions';
|
||||
|
||||
//
|
||||
|
@ -25,6 +26,7 @@ export const defaultState = {
|
|||
isPopulated: false,
|
||||
error: null,
|
||||
items: [],
|
||||
pendingChanges: {},
|
||||
sortKey: 'quality',
|
||||
sortDirection: sortDirections.DESCENDING,
|
||||
recentFolders: [],
|
||||
|
@ -67,6 +69,7 @@ export const persistState = [
|
|||
|
||||
export const FETCH_INTERACTIVE_IMPORT_ITEMS = 'FETCH_INTERACTIVE_IMPORT_ITEMS';
|
||||
export const UPDATE_INTERACTIVE_IMPORT_ITEM = 'UPDATE_INTERACTIVE_IMPORT_ITEM';
|
||||
export const SAVE_INTERACTIVE_IMPORT_ITEM = 'SAVE_INTERACTIVE_IMPORT_ITEM';
|
||||
export const SET_INTERACTIVE_IMPORT_SORT = 'SET_INTERACTIVE_IMPORT_SORT';
|
||||
export const CLEAR_INTERACTIVE_IMPORT = 'CLEAR_INTERACTIVE_IMPORT';
|
||||
export const ADD_RECENT_FOLDER = 'ADD_RECENT_FOLDER';
|
||||
|
@ -83,6 +86,7 @@ export const CLEAR_INTERACTIVE_IMPORT_ALBUMS = 'CLEAR_INTERACTIVE_IMPORT_ALBUMS'
|
|||
export const fetchInteractiveImportItems = createThunk(FETCH_INTERACTIVE_IMPORT_ITEMS);
|
||||
export const setInteractiveImportSort = createAction(SET_INTERACTIVE_IMPORT_SORT);
|
||||
export const updateInteractiveImportItem = createAction(UPDATE_INTERACTIVE_IMPORT_ITEM);
|
||||
export const saveInteractiveImportItem = createThunk(SAVE_INTERACTIVE_IMPORT_ITEM);
|
||||
export const clearInteractiveImport = createAction(CLEAR_INTERACTIVE_IMPORT);
|
||||
export const addRecentFolder = createAction(ADD_RECENT_FOLDER);
|
||||
export const removeRecentFolder = createAction(REMOVE_RECENT_FOLDER);
|
||||
|
@ -131,6 +135,8 @@ export const actionHandlers = handleThunks({
|
|||
});
|
||||
},
|
||||
|
||||
[SAVE_INTERACTIVE_IMPORT_ITEM]: createSaveProviderHandler(section, '/manualimport'),
|
||||
|
||||
[FETCH_INTERACTIVE_IMPORT_ALBUMS]: createFetchHandler('interactiveImport.albums', '/album')
|
||||
});
|
||||
|
||||
|
|
|
@ -115,6 +115,7 @@
|
|||
<Compile Include="Parse\ParseModule.cs" />
|
||||
<Compile Include="Parse\ParseResource.cs" />
|
||||
<Compile Include="ManualImport\ManualImportModule.cs" />
|
||||
<Compile Include="ManualImport\ManualImportModuleWithSignalR.cs" />
|
||||
<Compile Include="ManualImport\ManualImportResource.cs" />
|
||||
<Compile Include="Profiles\Delay\DelayProfileModule.cs" />
|
||||
<Compile Include="Profiles\Delay\DelayProfileResource.cs" />
|
||||
|
|
|
@ -4,20 +4,30 @@ using NzbDrone.Core.MediaFiles.TrackImport.Manual;
|
|||
using NzbDrone.Core.Qualities;
|
||||
using Lidarr.Http;
|
||||
using Lidarr.Http.Extensions;
|
||||
|
||||
using NzbDrone.SignalR;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
using NzbDrone.Core.Music;
|
||||
using NLog;
|
||||
|
||||
namespace Lidarr.Api.V1.ManualImport
|
||||
{
|
||||
public class ManualImportModule : LidarrRestModule<ManualImportResource>
|
||||
public class ManualImportModule : ManualImportModuleWithSignalR
|
||||
{
|
||||
private readonly IManualImportService _manualImportService;
|
||||
private readonly IArtistService _artistService;
|
||||
private readonly IAlbumService _albumService;
|
||||
|
||||
public ManualImportModule(IManualImportService manualImportService)
|
||||
: base("/manualimport")
|
||||
public ManualImportModule(IManualImportService manualImportService,
|
||||
IArtistService artistService,
|
||||
IAlbumService albumService,
|
||||
IBroadcastSignalRMessage signalRBroadcaster,
|
||||
Logger logger)
|
||||
: base(manualImportService, signalRBroadcaster, logger)
|
||||
{
|
||||
_manualImportService = manualImportService;
|
||||
_albumService = albumService;
|
||||
_artistService = artistService;
|
||||
|
||||
GetResourceAll = GetMediaFiles;
|
||||
UpdateResource = UpdateImportItem;
|
||||
}
|
||||
|
||||
private List<ManualImportResource> GetMediaFiles()
|
||||
|
@ -40,5 +50,26 @@ namespace Lidarr.Api.V1.ManualImport
|
|||
|
||||
return item;
|
||||
}
|
||||
|
||||
private void UpdateImportItem(ManualImportResource resource)
|
||||
{
|
||||
var item = new ManualImportItem{
|
||||
Id = resource.Id,
|
||||
Path = resource.Path,
|
||||
RelativePath = resource.RelativePath,
|
||||
FolderName = resource.FolderName,
|
||||
Name = resource.Name,
|
||||
Size = resource.Size,
|
||||
Artist = resource.Artist == null ? null : _artistService.GetArtist(resource.Artist.Id),
|
||||
Album = resource.Album == null ? null : _albumService.GetAlbum(resource.Album.Id),
|
||||
Quality = resource.Quality,
|
||||
Language = resource.Language,
|
||||
DownloadId = resource.DownloadId
|
||||
};
|
||||
|
||||
//recalculate import and broadcast
|
||||
_manualImportService.UpdateItem(item);
|
||||
BroadcastResourceChange(ModelAction.Updated, item.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport.Manual;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using Lidarr.Http;
|
||||
using Lidarr.Http.Extensions;
|
||||
using NzbDrone.SignalR;
|
||||
using NLog;
|
||||
|
||||
namespace Lidarr.Api.V1.ManualImport
|
||||
{
|
||||
public abstract class ManualImportModuleWithSignalR : LidarrRestModuleWithSignalR<ManualImportResource, ManualImportItem>
|
||||
{
|
||||
protected readonly IManualImportService _manualImportService;
|
||||
protected readonly Logger _logger;
|
||||
|
||||
protected ManualImportModuleWithSignalR(IManualImportService manualImportService,
|
||||
IBroadcastSignalRMessage signalRBroadcaster,
|
||||
Logger logger)
|
||||
: base(signalRBroadcaster)
|
||||
{
|
||||
_manualImportService = manualImportService;
|
||||
_logger = logger;
|
||||
|
||||
GetResourceById = GetManualImportItem;
|
||||
}
|
||||
|
||||
protected ManualImportModuleWithSignalR(IManualImportService manualImportService,
|
||||
IBroadcastSignalRMessage signalRBroadcaster,
|
||||
Logger logger,
|
||||
string resource)
|
||||
: base(signalRBroadcaster, resource)
|
||||
{
|
||||
_manualImportService = manualImportService;
|
||||
_logger = logger;
|
||||
|
||||
GetResourceById = GetManualImportItem;
|
||||
}
|
||||
|
||||
protected ManualImportResource GetManualImportItem(int id)
|
||||
{
|
||||
return _manualImportService.Find(id).ToResource();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,7 +37,7 @@ namespace Lidarr.Api.V1.ManualImport
|
|||
|
||||
return new ManualImportResource
|
||||
{
|
||||
Id = HashConverter.GetHashInt31(model.Path),
|
||||
Id = model.Id,
|
||||
Path = model.Path,
|
||||
RelativePath = model.RelativePath,
|
||||
FolderName = model.FolderName,
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
};
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Setup(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<ParsedTrackInfo>()))
|
||||
.Setup(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<Album>(), It.IsAny<ParsedTrackInfo>()))
|
||||
.Returns(_localTrack);
|
||||
|
||||
GivenVideoFiles(new List<string> { @"C:\Test\Unsorted\The.Office.S03E115.DVDRip.Spanish.XviD-OSiTV.avi".AsOsAgnostic() });
|
||||
|
@ -151,7 +151,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
GivenSpecifications(_pass1);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Setup(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<ParsedTrackInfo>()))
|
||||
.Setup(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<Album>(), It.IsAny<ParsedTrackInfo>()))
|
||||
.Throws<TestException>();
|
||||
|
||||
_audioFiles = new List<string>
|
||||
|
@ -166,7 +166,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
Subject.GetImportDecisions(_audioFiles, _artist);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<ParsedTrackInfo>()), Times.Exactly(_audioFiles.Count));
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<Album>(), It.IsAny<ParsedTrackInfo>()), Times.Exactly(_audioFiles.Count));
|
||||
|
||||
ExceptionVerification.ExpectedErrors(3);
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
GivenSpecifications(_pass1);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Setup(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<ParsedTrackInfo>()))
|
||||
.Setup(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<Album>(), It.IsAny<ParsedTrackInfo>()))
|
||||
.Returns(new LocalTrack() { Path = "test" });
|
||||
|
||||
_audioFiles = new List<string>
|
||||
|
@ -275,7 +275,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
var decisions = Subject.GetImportDecisions(_audioFiles, _artist);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<ParsedTrackInfo>()), Times.Exactly(_audioFiles.Count));
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<Album>(), It.IsAny<ParsedTrackInfo>()), Times.Exactly(_audioFiles.Count));
|
||||
|
||||
decisions.Should().HaveCount(3);
|
||||
decisions.First().Rejections.Should().NotBeEmpty();
|
||||
|
@ -299,10 +299,10 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
Subject.GetImportDecisions(_audioFiles, _artist, folderInfo);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), null), Times.Exactly(3));
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<Album>(), null), Times.Exactly(3));
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.Is<ParsedTrackInfo>(p => p != null)), Times.Never());
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<Album>(), It.Is<ParsedTrackInfo>(p => p != null)), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -322,10 +322,10 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
Subject.GetImportDecisions(_audioFiles, _artist, folderInfo);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), null), Times.Exactly(2));
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<Album>(), null), Times.Exactly(2));
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.Is<ParsedTrackInfo>(p => p != null)), Times.Never());
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<Album>(), It.Is<ParsedTrackInfo>(p => p != null)), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -344,10 +344,10 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
Subject.GetImportDecisions(_audioFiles, _artist, folderInfo);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<ParsedTrackInfo>()), Times.Exactly(1));
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<Album>(), It.IsAny<ParsedTrackInfo>()), Times.Exactly(1));
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), null), Times.Never());
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<Album>(), null), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -366,10 +366,10 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
Subject.GetImportDecisions(_audioFiles, _artist, folderInfo);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), null), Times.Exactly(1));
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<Album>(), null), Times.Exactly(1));
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.Is<ParsedTrackInfo>(p => p != null)), Times.Never());
|
||||
.Verify(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<Album>(), It.Is<ParsedTrackInfo>(p => p != null)), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -394,7 +394,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
public void should_return_a_decision_when_exception_is_caught()
|
||||
{
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Setup(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<ParsedTrackInfo>()))
|
||||
.Setup(c => c.GetLocalTrack(It.IsAny<string>(), It.IsAny<Artist>(), It.IsAny<Album>(), It.IsAny<ParsedTrackInfo>()))
|
||||
.Throws<TestException>();
|
||||
|
||||
_audioFiles = new List<string>
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
|
|||
List<ImportDecision> GetImportDecisions(List<string> musicFiles, Artist artist);
|
||||
List<ImportDecision> GetImportDecisions(List<string> musicFiles, Artist artist, ParsedTrackInfo folderInfo);
|
||||
List<ImportDecision> GetImportDecisions(List<string> musicFiles, Artist artist, ParsedTrackInfo folderInfo, bool filterExistingFiles);
|
||||
|
||||
ImportDecision GetImportDecision(string musicFile, Artist artist, Album album);
|
||||
}
|
||||
|
||||
public class ImportDecisionMaker : IMakeImportDecision
|
||||
|
@ -68,19 +68,24 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
|
|||
|
||||
foreach (var file in files)
|
||||
{
|
||||
decisions.AddIfNotNull(GetDecision(file, artist, folderInfo, shouldUseFolderName));
|
||||
decisions.AddIfNotNull(GetDecision(file, artist, null, folderInfo, shouldUseFolderName));
|
||||
}
|
||||
|
||||
return decisions;
|
||||
}
|
||||
|
||||
private ImportDecision GetDecision(string file, Artist artist, ParsedTrackInfo folderInfo, bool shouldUseFolderName)
|
||||
public ImportDecision GetImportDecision(string file, Artist artist, Album album)
|
||||
{
|
||||
return GetDecision(file, artist, album, null, false);
|
||||
}
|
||||
|
||||
private ImportDecision GetDecision(string file, Artist artist, Album album, ParsedTrackInfo folderInfo, bool shouldUseFolderName)
|
||||
{
|
||||
ImportDecision decision = null;
|
||||
|
||||
try
|
||||
{
|
||||
var localTrack = _parsingService.GetLocalTrack(file, artist, shouldUseFolderName ? folderInfo : null);
|
||||
var localTrack = _parsingService.GetLocalTrack(file, artist, album, shouldUseFolderName ? folderInfo : null);
|
||||
|
||||
if (localTrack != null)
|
||||
{
|
||||
|
|
|
@ -3,10 +3,11 @@ using NzbDrone.Core.DecisionEngine;
|
|||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
||||
{
|
||||
public class ManualImportItem
|
||||
public class ManualImportItem : ModelBase
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public string RelativePath { get; set; }
|
||||
|
|
|
@ -15,12 +15,16 @@ using NzbDrone.Core.Messaging.Events;
|
|||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Common.Crypto;
|
||||
using NzbDrone.Common.Cache;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
||||
{
|
||||
public interface IManualImportService
|
||||
{
|
||||
List<ManualImportItem> GetMediaFiles(string path, string downloadId, bool filterExistingFiles);
|
||||
void UpdateItem(ManualImportItem item);
|
||||
ManualImportItem Find(int id);
|
||||
}
|
||||
|
||||
public class ManualImportService : IExecute<ManualImportCommand>, IManualImportService
|
||||
|
@ -35,7 +39,8 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
|||
private readonly IVideoFileInfoReader _videoFileInfoReader;
|
||||
private readonly IImportApprovedTracks _importApprovedTracks;
|
||||
private readonly ITrackedDownloadService _trackedDownloadService;
|
||||
private readonly IDownloadedTracksImportService _downloadedEpisodesImportService;
|
||||
private readonly IDownloadedTracksImportService _downloadedTracksImportService;
|
||||
private readonly ICached<ManualImportItem> _cache;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
|
@ -49,7 +54,8 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
|||
IVideoFileInfoReader videoFileInfoReader,
|
||||
IImportApprovedTracks importApprovedTracks,
|
||||
ITrackedDownloadService trackedDownloadService,
|
||||
IDownloadedTracksImportService downloadedEpisodesImportService,
|
||||
IDownloadedTracksImportService downloadedTracksImportService,
|
||||
ICacheManager cacheManager,
|
||||
IEventAggregator eventAggregator,
|
||||
Logger logger)
|
||||
{
|
||||
|
@ -63,13 +69,21 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
|||
_videoFileInfoReader = videoFileInfoReader;
|
||||
_importApprovedTracks = importApprovedTracks;
|
||||
_trackedDownloadService = trackedDownloadService;
|
||||
_downloadedEpisodesImportService = downloadedEpisodesImportService;
|
||||
_downloadedTracksImportService = downloadedTracksImportService;
|
||||
_cache = cacheManager.GetCache<ManualImportItem>(GetType());
|
||||
_eventAggregator = eventAggregator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public ManualImportItem Find(int id)
|
||||
{
|
||||
return _cache.Find(id.ToString());
|
||||
}
|
||||
|
||||
public List<ManualImportItem> GetMediaFiles(string path, string downloadId, bool filterExistingFiles)
|
||||
{
|
||||
_cache.Clear();
|
||||
|
||||
if (downloadId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var trackedDownload = _trackedDownloadService.Find(downloadId);
|
||||
|
@ -89,10 +103,19 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
|||
return new List<ManualImportItem>();
|
||||
}
|
||||
|
||||
return new List<ManualImportItem> { ProcessFile(path, downloadId) };
|
||||
var decision = ProcessFile(path, downloadId);
|
||||
_cache.Set(decision.Id.ToString(), decision);
|
||||
|
||||
return new List<ManualImportItem> { decision };
|
||||
}
|
||||
|
||||
return ProcessFolder(path, downloadId, filterExistingFiles);
|
||||
var items = ProcessFolder(path, downloadId, filterExistingFiles);
|
||||
foreach (var item in items)
|
||||
{
|
||||
_cache.Set(item.Id.ToString(), item);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private List<ManualImportItem> ProcessFolder(string folder, string downloadId, bool filterExistingFiles)
|
||||
|
@ -120,6 +143,30 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
|||
return decisions.Select(decision => MapItem(decision, folder, downloadId)).ToList();
|
||||
}
|
||||
|
||||
public void UpdateItem(ManualImportItem item)
|
||||
{
|
||||
var decision = _importDecisionMaker.GetImportDecision(item.Path, item.Artist, item.Album);
|
||||
|
||||
if (decision.LocalTrack.Artist != null)
|
||||
{
|
||||
item.Artist = decision.LocalTrack.Artist;
|
||||
}
|
||||
|
||||
if (decision.LocalTrack.Album != null)
|
||||
{
|
||||
item.Album = decision.LocalTrack.Album;
|
||||
}
|
||||
|
||||
if (decision.LocalTrack.Tracks.Any())
|
||||
{
|
||||
item.Tracks = decision.LocalTrack.Tracks;
|
||||
}
|
||||
|
||||
item.Rejections = decision.Rejections;
|
||||
|
||||
_cache.Set(item.Id.ToString(), item);
|
||||
}
|
||||
|
||||
private ManualImportItem ProcessFile(string file, string downloadId, string folder = null)
|
||||
{
|
||||
if (folder.IsNullOrWhiteSpace())
|
||||
|
@ -158,6 +205,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
|||
|
||||
return importDecisions.Any() ? MapItem(importDecisions.First(), folder, downloadId) : new ManualImportItem
|
||||
{
|
||||
Id = HashConverter.GetHashInt31(file),
|
||||
DownloadId = downloadId,
|
||||
Path = file,
|
||||
RelativePath = folder.GetRelativePath(file),
|
||||
|
@ -178,6 +226,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
|||
{
|
||||
var item = new ManualImportItem();
|
||||
|
||||
item.Id = HashConverter.GetHashInt31(decision.LocalTrack.Path);
|
||||
item.Path = decision.LocalTrack.Path;
|
||||
item.RelativePath = folder.GetRelativePath(decision.LocalTrack.Path);
|
||||
item.Name = Path.GetFileNameWithoutExtension(decision.LocalTrack.Path);
|
||||
|
@ -271,7 +320,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
|||
|
||||
if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath.FullPath))
|
||||
{
|
||||
if (_downloadedEpisodesImportService.ShouldDeleteFolder(
|
||||
if (_downloadedTracksImportService.ShouldDeleteFolder(
|
||||
new DirectoryInfo(trackedDownload.DownloadItem.OutputPath.FullPath),
|
||||
trackedDownload.RemoteAlbum.Artist) && trackedDownload.DownloadItem.CanMoveFiles)
|
||||
{
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace NzbDrone.Core.Parser
|
|||
Album GetLocalAlbum(string filename, Artist artist);
|
||||
LocalTrack GetLocalTrack(string filename, Artist artist);
|
||||
LocalTrack GetLocalTrack(string filename, Artist artist, ParsedTrackInfo folderInfo);
|
||||
|
||||
LocalTrack GetLocalTrack(string filename, Artist artist, Album album, ParsedTrackInfo folderInfo);
|
||||
}
|
||||
|
||||
public class ParsingService : IParsingService
|
||||
|
@ -245,6 +245,11 @@ namespace NzbDrone.Core.Parser
|
|||
}
|
||||
|
||||
public LocalTrack GetLocalTrack(string filename, Artist artist, ParsedTrackInfo folderInfo)
|
||||
{
|
||||
return GetLocalTrack(filename, artist, null, folderInfo);
|
||||
}
|
||||
|
||||
public LocalTrack GetLocalTrack(string filename, Artist artist, Album album, ParsedTrackInfo folderInfo)
|
||||
{
|
||||
ParsedTrackInfo parsedTrackInfo;
|
||||
|
||||
|
@ -258,7 +263,7 @@ namespace NzbDrone.Core.Parser
|
|||
parsedTrackInfo = Parser.ParseMusicPath(filename);
|
||||
}
|
||||
|
||||
if (parsedTrackInfo == null || (parsedTrackInfo.AlbumTitle.IsNullOrWhiteSpace()) && parsedTrackInfo.ReleaseMBId.IsNullOrWhiteSpace())
|
||||
if (parsedTrackInfo == null || (parsedTrackInfo.AlbumTitle.IsNullOrWhiteSpace()) && parsedTrackInfo.ReleaseMBId.IsNullOrWhiteSpace() && album == null)
|
||||
{
|
||||
if (MediaFileExtensions.Extensions.Contains(Path.GetExtension(filename)))
|
||||
{
|
||||
|
@ -268,7 +273,11 @@ namespace NzbDrone.Core.Parser
|
|||
return null;
|
||||
}
|
||||
|
||||
var album = GetAlbum(artist, parsedTrackInfo);
|
||||
if (album == null)
|
||||
{
|
||||
album = GetAlbum(artist, parsedTrackInfo);
|
||||
}
|
||||
|
||||
var tracks = new List<Track>();
|
||||
if (album != null)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue