mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-20 13:33:34 -07:00
Merge conflicts
This commit is contained in:
commit
ee90d8021a
28 changed files with 834 additions and 64 deletions
|
@ -20,6 +20,10 @@ namespace NzbDrone.Api.Music
|
||||||
//View Only
|
//View Only
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string ForeignArtistId { get; set; }
|
public string ForeignArtistId { get; set; }
|
||||||
|
public string MBId { get; set; }
|
||||||
|
public int TADBId { get; set; }
|
||||||
|
public int DiscogsId { get; set; }
|
||||||
|
public string AMId { get; set; }
|
||||||
public string Overview { get; set; }
|
public string Overview { get; set; }
|
||||||
|
|
||||||
public int AlbumCount
|
public int AlbumCount
|
||||||
|
@ -53,7 +57,7 @@ namespace NzbDrone.Api.Music
|
||||||
public bool Monitored { get; set; }
|
public bool Monitored { get; set; }
|
||||||
|
|
||||||
public string RootFolderPath { get; set; }
|
public string RootFolderPath { get; set; }
|
||||||
public string Certification { get; set; }
|
//public string Certification { get; set; }
|
||||||
public List<string> Genres { get; set; }
|
public List<string> Genres { get; set; }
|
||||||
public HashSet<int> Tags { get; set; }
|
public HashSet<int> Tags { get; set; }
|
||||||
public DateTime Added { get; set; }
|
public DateTime Added { get; set; }
|
||||||
|
@ -71,7 +75,10 @@ namespace NzbDrone.Api.Music
|
||||||
return new ArtistResource
|
return new ArtistResource
|
||||||
{
|
{
|
||||||
Id = model.Id,
|
Id = model.Id,
|
||||||
|
MBId = model.MBId,
|
||||||
|
TADBId = model.TADBId,
|
||||||
|
DiscogsId = model.DiscogsId,
|
||||||
|
AMId = model.AMId,
|
||||||
Name = model.Name,
|
Name = model.Name,
|
||||||
//AlternateTitles
|
//AlternateTitles
|
||||||
//SortTitle = resource.SortTitle,
|
//SortTitle = resource.SortTitle,
|
||||||
|
@ -127,7 +134,10 @@ namespace NzbDrone.Api.Music
|
||||||
Name = resource.Name,
|
Name = resource.Name,
|
||||||
//AlternateTitles
|
//AlternateTitles
|
||||||
//SortTitle = resource.SortTitle,
|
//SortTitle = resource.SortTitle,
|
||||||
|
MBId = resource.MBId,
|
||||||
|
TADBId = resource.TADBId,
|
||||||
|
DiscogsId = resource.DiscogsId,
|
||||||
|
AMId = resource.AMId,
|
||||||
//TotalEpisodeCount
|
//TotalEpisodeCount
|
||||||
//EpisodeCount
|
//EpisodeCount
|
||||||
//EpisodeFileCount
|
//EpisodeFileCount
|
||||||
|
|
|
@ -104,6 +104,13 @@
|
||||||
<Compile Include="ClientSchema\SelectOption.cs" />
|
<Compile Include="ClientSchema\SelectOption.cs" />
|
||||||
<Compile Include="Commands\CommandModule.cs" />
|
<Compile Include="Commands\CommandModule.cs" />
|
||||||
<Compile Include="Commands\CommandResource.cs" />
|
<Compile Include="Commands\CommandResource.cs" />
|
||||||
|
<Compile Include="TrackFiles\TrackFileModule.cs" />
|
||||||
|
<Compile Include="TrackFiles\TrackFileResource.cs" />
|
||||||
|
<Compile Include="Tracks\TrackModule.cs" />
|
||||||
|
<Compile Include="Tracks\TrackModuleWithSignalR.cs" />
|
||||||
|
<Compile Include="Tracks\TrackResource.cs" />
|
||||||
|
<Compile Include="Tracks\RenameTrackModule.cs" />
|
||||||
|
<Compile Include="Tracks\RenameTrackResource.cs" />
|
||||||
<Compile Include="Extensions\AccessControlHeaders.cs" />
|
<Compile Include="Extensions\AccessControlHeaders.cs" />
|
||||||
<Compile Include="Extensions\Pipelines\CorsPipeline.cs" />
|
<Compile Include="Extensions\Pipelines\CorsPipeline.cs" />
|
||||||
<Compile Include="Extensions\Pipelines\RequestLoggingPipeline.cs" />
|
<Compile Include="Extensions\Pipelines\RequestLoggingPipeline.cs" />
|
||||||
|
|
101
src/NzbDrone.Api/TrackFiles/TrackFileModule.cs
Normal file
101
src/NzbDrone.Api/TrackFiles/TrackFileModule.cs
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Api.REST;
|
||||||
|
using NzbDrone.Common.Disk;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Core.Datastore.Events;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.MediaFiles.Events;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
using NzbDrone.Core.DecisionEngine;
|
||||||
|
using NzbDrone.SignalR;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.TrackFiles
|
||||||
|
{
|
||||||
|
public class TrackFileModule : NzbDroneRestModuleWithSignalR<TrackFileResource, TrackFile>,
|
||||||
|
IHandle<TrackFileAddedEvent>
|
||||||
|
{
|
||||||
|
private readonly IMediaFileService _mediaFileService;
|
||||||
|
private readonly IDiskProvider _diskProvider;
|
||||||
|
private readonly IRecycleBinProvider _recycleBinProvider;
|
||||||
|
private readonly ISeriesService _seriesService;
|
||||||
|
private readonly IArtistService _artistService;
|
||||||
|
private readonly IQualityUpgradableSpecification _qualityUpgradableSpecification;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public TrackFileModule(IBroadcastSignalRMessage signalRBroadcaster,
|
||||||
|
IMediaFileService mediaFileService,
|
||||||
|
IDiskProvider diskProvider,
|
||||||
|
IRecycleBinProvider recycleBinProvider,
|
||||||
|
ISeriesService seriesService,
|
||||||
|
IArtistService artistService,
|
||||||
|
IQualityUpgradableSpecification qualityUpgradableSpecification,
|
||||||
|
Logger logger)
|
||||||
|
: base(signalRBroadcaster)
|
||||||
|
{
|
||||||
|
_mediaFileService = mediaFileService;
|
||||||
|
_diskProvider = diskProvider;
|
||||||
|
_recycleBinProvider = recycleBinProvider;
|
||||||
|
_seriesService = seriesService;
|
||||||
|
_artistService = artistService;
|
||||||
|
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||||
|
_logger = logger;
|
||||||
|
GetResourceById = GetTrackFile;
|
||||||
|
GetResourceAll = GetTrackFiles;
|
||||||
|
UpdateResource = SetQuality;
|
||||||
|
DeleteResource = DeleteTrackFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TrackFileResource GetTrackFile(int id)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
//var episodeFile = _mediaFileService.Get(id);
|
||||||
|
//var series = _seriesService.GetSeries(episodeFile.SeriesId);
|
||||||
|
|
||||||
|
//return episodeFile.ToResource(series, _qualityUpgradableSpecification);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TrackFileResource> GetTrackFiles()
|
||||||
|
{
|
||||||
|
if (!Request.Query.ArtistId.HasValue)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("artistId is missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
var artistId = (int)Request.Query.ArtistId;
|
||||||
|
|
||||||
|
var artist = _artistService.GetArtist(artistId);
|
||||||
|
|
||||||
|
return _mediaFileService.GetFilesByArtist(artistId).ConvertAll(f => f.ToResource(artist, _qualityUpgradableSpecification));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetQuality(TrackFileResource trackFileResource)
|
||||||
|
{
|
||||||
|
var trackFile = _mediaFileService.Get(trackFileResource.Id);
|
||||||
|
trackFile.Quality = trackFileResource.Quality;
|
||||||
|
_mediaFileService.Update(trackFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeleteTrackFile(int id)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
//var episodeFile = _mediaFileService.Get(id);
|
||||||
|
//var series = _seriesService.GetSeries(episodeFile.SeriesId);
|
||||||
|
//var fullPath = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||||
|
//var subfolder = _diskProvider.GetParentFolder(series.Path).GetRelativePath(_diskProvider.GetParentFolder(fullPath));
|
||||||
|
|
||||||
|
//_logger.Info("Deleting episode file: {0}", fullPath);
|
||||||
|
//_recycleBinProvider.DeleteFile(fullPath, subfolder);
|
||||||
|
//_mediaFileService.Delete(episodeFile, DeleteMediaFileReason.Manual);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(TrackFileAddedEvent message)
|
||||||
|
{
|
||||||
|
BroadcastResourceChange(ModelAction.Updated, message.TrackFile.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
64
src/NzbDrone.Api/TrackFiles/TrackFileResource.cs
Normal file
64
src/NzbDrone.Api/TrackFiles/TrackFileResource.cs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using NzbDrone.Api.REST;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.TrackFiles
|
||||||
|
{
|
||||||
|
public class TrackFileResource : RestResource
|
||||||
|
{
|
||||||
|
public int ArtistId { get; set; }
|
||||||
|
public int AlbumId { get; set; }
|
||||||
|
public string RelativePath { get; set; }
|
||||||
|
public string Path { get; set; }
|
||||||
|
public long Size { get; set; }
|
||||||
|
public DateTime DateAdded { get; set; }
|
||||||
|
//public string SceneName { get; set; }
|
||||||
|
public QualityModel Quality { get; set; }
|
||||||
|
|
||||||
|
public bool QualityCutoffNotMet { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TrackFileResourceMapper
|
||||||
|
{
|
||||||
|
private static TrackFileResource ToResource(this Core.MediaFiles.TrackFile model)
|
||||||
|
{
|
||||||
|
if (model == null) return null;
|
||||||
|
|
||||||
|
return new TrackFileResource
|
||||||
|
{
|
||||||
|
Id = model.Id,
|
||||||
|
|
||||||
|
ArtistId = model.ArtistId,
|
||||||
|
AlbumId = model.AlbumId,
|
||||||
|
RelativePath = model.RelativePath,
|
||||||
|
//Path
|
||||||
|
Size = model.Size,
|
||||||
|
DateAdded = model.DateAdded,
|
||||||
|
//SceneName = model.SceneName,
|
||||||
|
Quality = model.Quality,
|
||||||
|
//QualityCutoffNotMet
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TrackFileResource ToResource(this Core.MediaFiles.TrackFile model, Core.Music.Artist artist, Core.DecisionEngine.IQualityUpgradableSpecification qualityUpgradableSpecification)
|
||||||
|
{
|
||||||
|
if (model == null) return null;
|
||||||
|
|
||||||
|
return new TrackFileResource
|
||||||
|
{
|
||||||
|
Id = model.Id,
|
||||||
|
|
||||||
|
ArtistId = model.ArtistId,
|
||||||
|
AlbumId = model.AlbumId,
|
||||||
|
RelativePath = model.RelativePath,
|
||||||
|
Path = Path.Combine(artist.Path, model.RelativePath),
|
||||||
|
Size = model.Size,
|
||||||
|
DateAdded = model.DateAdded,
|
||||||
|
//SceneName = model.SceneName,
|
||||||
|
Quality = model.Quality,
|
||||||
|
QualityCutoffNotMet = qualityUpgradableSpecification.CutoffNotMet(artist.Profile.Value, model.Quality)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
src/NzbDrone.Api/Tracks/RenameTrackModule.cs
Normal file
37
src/NzbDrone.Api/Tracks/RenameTrackModule.cs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Api.REST;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Tracks
|
||||||
|
{
|
||||||
|
public class RenameTrackModule : NzbDroneRestModule<RenameTrackResource>
|
||||||
|
{
|
||||||
|
private readonly IRenameTrackFileService _renameTrackFileService;
|
||||||
|
|
||||||
|
public RenameTrackModule(IRenameTrackFileService renameTrackFileService)
|
||||||
|
: base("rename")
|
||||||
|
{
|
||||||
|
_renameTrackFileService = renameTrackFileService;
|
||||||
|
|
||||||
|
GetResourceAll = GetTracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<RenameTrackResource> GetTracks()
|
||||||
|
{
|
||||||
|
if (!Request.Query.ArtistId.HasValue)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("artistId is missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
var artistId = (int)Request.Query.ArtistId;
|
||||||
|
|
||||||
|
if (Request.Query.AlbumId.HasValue)
|
||||||
|
{
|
||||||
|
var albumId = (int)Request.Query.AlbumId;
|
||||||
|
return _renameTrackFileService.GetRenamePreviews(artistId, albumId).ToResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _renameTrackFileService.GetRenamePreviews(artistId).ToResource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
src/NzbDrone.Api/Tracks/RenameTrackResource.cs
Normal file
39
src/NzbDrone.Api/Tracks/RenameTrackResource.cs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NzbDrone.Api.REST;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Tracks
|
||||||
|
{
|
||||||
|
public class RenameTrackResource : RestResource
|
||||||
|
{
|
||||||
|
public int ArtistId { get; set; }
|
||||||
|
public int AlbumId { get; set; }
|
||||||
|
public List<int> TrackNumbers { get; set; }
|
||||||
|
public int TrackFileId { get; set; }
|
||||||
|
public string ExistingPath { get; set; }
|
||||||
|
public string NewPath { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RenameTrackResourceMapper
|
||||||
|
{
|
||||||
|
public static RenameTrackResource ToResource(this Core.MediaFiles.RenameTrackFilePreview model)
|
||||||
|
{
|
||||||
|
if (model == null) return null;
|
||||||
|
|
||||||
|
return new RenameTrackResource
|
||||||
|
{
|
||||||
|
ArtistId = model.ArtistId,
|
||||||
|
AlbumId = model.AlbumId,
|
||||||
|
TrackNumbers = model.TrackNumbers.ToList(),
|
||||||
|
TrackFileId = model.TrackFileId,
|
||||||
|
ExistingPath = model.ExistingPath,
|
||||||
|
NewPath = model.NewPath
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<RenameTrackResource> ToResource(this IEnumerable<Core.MediaFiles.RenameTrackFilePreview> models)
|
||||||
|
{
|
||||||
|
return models.Select(ToResource).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
src/NzbDrone.Api/Tracks/TrackModule.cs
Normal file
40
src/NzbDrone.Api/Tracks/TrackModule.cs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Api.REST;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
using NzbDrone.Core.DecisionEngine;
|
||||||
|
using NzbDrone.SignalR;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Tracks
|
||||||
|
{
|
||||||
|
public class TrackModule : TrackModuleWithSignalR
|
||||||
|
{
|
||||||
|
public TrackModule(IArtistService artistService,
|
||||||
|
ITrackService trackService,
|
||||||
|
IQualityUpgradableSpecification qualityUpgradableSpecification,
|
||||||
|
IBroadcastSignalRMessage signalRBroadcaster)
|
||||||
|
: base(trackService, artistService, qualityUpgradableSpecification, signalRBroadcaster)
|
||||||
|
{
|
||||||
|
GetResourceAll = GetTracks;
|
||||||
|
UpdateResource = SetMonitored;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TrackResource> GetTracks()
|
||||||
|
{
|
||||||
|
if (!Request.Query.ArtistId.HasValue)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("artistId is missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
var artistId = (int)Request.Query.ArtistId;
|
||||||
|
|
||||||
|
var resources = MapToResource(_trackService.GetTracksByArtist(artistId), false, true);
|
||||||
|
|
||||||
|
return resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetMonitored(TrackResource trackResource)
|
||||||
|
{
|
||||||
|
_trackService.SetTrackMonitored(trackResource.Id, trackResource.Monitored);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
126
src/NzbDrone.Api/Tracks/TrackModuleWithSignalR.cs
Normal file
126
src/NzbDrone.Api/Tracks/TrackModuleWithSignalR.cs
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Api.TrackFiles;
|
||||||
|
using NzbDrone.Api.Music;
|
||||||
|
using NzbDrone.Core.Datastore.Events;
|
||||||
|
using NzbDrone.Core.DecisionEngine;
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
|
using NzbDrone.Core.MediaFiles.Events;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
using NzbDrone.SignalR;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Tracks
|
||||||
|
{
|
||||||
|
public abstract class TrackModuleWithSignalR : NzbDroneRestModuleWithSignalR<TrackResource, Track>,
|
||||||
|
IHandle<TrackDownloadedEvent>
|
||||||
|
{
|
||||||
|
protected readonly ITrackService _trackService;
|
||||||
|
protected readonly IArtistService _artistService;
|
||||||
|
protected readonly IQualityUpgradableSpecification _qualityUpgradableSpecification;
|
||||||
|
|
||||||
|
protected TrackModuleWithSignalR(ITrackService trackService,
|
||||||
|
IArtistService artistService,
|
||||||
|
IQualityUpgradableSpecification qualityUpgradableSpecification,
|
||||||
|
IBroadcastSignalRMessage signalRBroadcaster)
|
||||||
|
: base(signalRBroadcaster)
|
||||||
|
{
|
||||||
|
_trackService = trackService;
|
||||||
|
_artistService = artistService;
|
||||||
|
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||||
|
|
||||||
|
GetResourceById = GetTrack;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TrackModuleWithSignalR(ITrackService trackService,
|
||||||
|
IArtistService artistService,
|
||||||
|
IQualityUpgradableSpecification qualityUpgradableSpecification,
|
||||||
|
IBroadcastSignalRMessage signalRBroadcaster,
|
||||||
|
string resource)
|
||||||
|
: base(signalRBroadcaster, resource)
|
||||||
|
{
|
||||||
|
_trackService = trackService;
|
||||||
|
_artistService = artistService;
|
||||||
|
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||||
|
|
||||||
|
GetResourceById = GetTrack;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TrackResource GetTrack(int id)
|
||||||
|
{
|
||||||
|
var track = _trackService.GetTrack(id);
|
||||||
|
var resource = MapToResource(track, true, true);
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TrackResource MapToResource(Track track, bool includeArtist, bool includeTrackFile)
|
||||||
|
{
|
||||||
|
var resource = track.ToResource();
|
||||||
|
|
||||||
|
if (includeArtist || includeTrackFile)
|
||||||
|
{
|
||||||
|
var artist = track.Artist ?? _artistService.GetArtist(track.ArtistId);
|
||||||
|
|
||||||
|
if (includeArtist)
|
||||||
|
{
|
||||||
|
resource.Artist = artist.ToResource();
|
||||||
|
}
|
||||||
|
if (includeTrackFile && track.TrackFileId != 0)
|
||||||
|
{
|
||||||
|
resource.TrackFile = track.TrackFile.Value.ToResource(artist, _qualityUpgradableSpecification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<TrackResource> MapToResource(List<Track> tracks, bool includeArtist, bool includeTrackFile)
|
||||||
|
{
|
||||||
|
var result = tracks.ToResource();
|
||||||
|
|
||||||
|
if (includeArtist || includeTrackFile)
|
||||||
|
{
|
||||||
|
var artistDict = new Dictionary<int, Core.Music.Artist>();
|
||||||
|
for (var i = 0; i < tracks.Count; i++)
|
||||||
|
{
|
||||||
|
var track = tracks[i];
|
||||||
|
var resource = result[i];
|
||||||
|
|
||||||
|
var artist = track.Artist ?? artistDict.GetValueOrDefault(tracks[i].ArtistId) ?? _artistService.GetArtist(tracks[i].ArtistId);
|
||||||
|
artistDict[artist.Id] = artist;
|
||||||
|
|
||||||
|
if (includeArtist)
|
||||||
|
{
|
||||||
|
resource.Artist = artist.ToResource();
|
||||||
|
}
|
||||||
|
if (includeTrackFile && tracks[i].TrackFileId != 0)
|
||||||
|
{
|
||||||
|
resource.TrackFile = tracks[i].TrackFile.Value.ToResource(artist, _qualityUpgradableSpecification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//public void Handle(TrackGrabbedEvent message)
|
||||||
|
//{
|
||||||
|
// foreach (var track in message.Track.Tracks)
|
||||||
|
// {
|
||||||
|
// var resource = track.ToResource();
|
||||||
|
// resource.Grabbed = true;
|
||||||
|
|
||||||
|
// BroadcastResourceChange(ModelAction.Updated, resource);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
public void Handle(TrackDownloadedEvent message)
|
||||||
|
{
|
||||||
|
foreach (var track in message.Track.Tracks)
|
||||||
|
{
|
||||||
|
BroadcastResourceChange(ModelAction.Updated, track.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
78
src/NzbDrone.Api/Tracks/TrackResource.cs
Normal file
78
src/NzbDrone.Api/Tracks/TrackResource.cs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using NzbDrone.Api.TrackFiles;
|
||||||
|
using NzbDrone.Api.REST;
|
||||||
|
using NzbDrone.Api.Music;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Tracks
|
||||||
|
{
|
||||||
|
public class TrackResource : RestResource
|
||||||
|
{
|
||||||
|
public int ArtistId { get; set; }
|
||||||
|
public int TrackFileId { get; set; }
|
||||||
|
public int AlbumId { get; set; }
|
||||||
|
//public int EpisodeNumber { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
//public string AirDate { get; set; }
|
||||||
|
//public DateTime? AirDateUtc { get; set; }
|
||||||
|
//public string Overview { get; set; }
|
||||||
|
public TrackFileResource TrackFile { get; set; }
|
||||||
|
|
||||||
|
public bool HasFile { get; set; }
|
||||||
|
public bool Monitored { get; set; }
|
||||||
|
//public int? AbsoluteEpisodeNumber { get; set; }
|
||||||
|
//public int? SceneAbsoluteEpisodeNumber { get; set; }
|
||||||
|
//public int? SceneEpisodeNumber { get; set; }
|
||||||
|
//public int? SceneSeasonNumber { get; set; }
|
||||||
|
//public bool UnverifiedSceneNumbering { get; set; }
|
||||||
|
//public string SeriesTitle { get; set; }
|
||||||
|
public ArtistResource Artist { get; set; }
|
||||||
|
|
||||||
|
//Hiding this so people don't think its usable (only used to set the initial state)
|
||||||
|
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||||
|
public bool Grabbed { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TrackResourceMapper
|
||||||
|
{
|
||||||
|
public static TrackResource ToResource(this Track model)
|
||||||
|
{
|
||||||
|
if (model == null) return null;
|
||||||
|
|
||||||
|
return new TrackResource
|
||||||
|
{
|
||||||
|
Id = model.Id,
|
||||||
|
|
||||||
|
ArtistId = model.ArtistId,
|
||||||
|
TrackFileId = model.TrackFileId,
|
||||||
|
AlbumId = model.AlbumId,
|
||||||
|
//EpisodeNumber = model.EpisodeNumber,
|
||||||
|
Title = model.Title,
|
||||||
|
//AirDate = model.AirDate,
|
||||||
|
//AirDateUtc = model.AirDateUtc,
|
||||||
|
//Overview = model.Overview,
|
||||||
|
//EpisodeFile
|
||||||
|
|
||||||
|
HasFile = model.HasFile,
|
||||||
|
Monitored = model.Monitored,
|
||||||
|
//AbsoluteEpisodeNumber = model.AbsoluteEpisodeNumber,
|
||||||
|
//SceneAbsoluteEpisodeNumber = model.SceneAbsoluteEpisodeNumber,
|
||||||
|
//SceneEpisodeNumber = model.SceneEpisodeNumber,
|
||||||
|
//SceneSeasonNumber = model.SceneSeasonNumber,
|
||||||
|
//UnverifiedSceneNumbering = model.UnverifiedSceneNumbering,
|
||||||
|
//SeriesTitle = model.SeriesTitle,
|
||||||
|
//Series = model.Series.MapToResource(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TrackResource> ToResource(this IEnumerable<Track> models)
|
||||||
|
{
|
||||||
|
if (models == null) return null;
|
||||||
|
|
||||||
|
return models.Select(ToResource).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/NzbDrone.Core/MediaFiles/Commands/RenameArtistCommand.cs
Normal file
16
src/NzbDrone.Core/MediaFiles/Commands/RenameArtistCommand.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.Commands
|
||||||
|
{
|
||||||
|
public class RenameArtistCommand : Command
|
||||||
|
{
|
||||||
|
public List<int> ArtistIds { get; set; }
|
||||||
|
|
||||||
|
public override bool SendUpdatesToClient => true;
|
||||||
|
|
||||||
|
public RenameArtistCommand()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
void Update(TrackFile trackFile);
|
void Update(TrackFile trackFile);
|
||||||
void Delete(TrackFile trackFile, DeleteMediaFileReason reason);
|
void Delete(TrackFile trackFile, DeleteMediaFileReason reason);
|
||||||
List<TrackFile> GetFilesByArtist(int artistId);
|
List<TrackFile> GetFilesByArtist(int artistId);
|
||||||
|
List<TrackFile> GetFilesByAlbum(int artistId, int albumId);
|
||||||
List<TrackFile> GetFilesWithoutMediaInfo();
|
List<TrackFile> GetFilesWithoutMediaInfo();
|
||||||
List<string> FilterExistingFiles(List<string> files, Artist artist);
|
List<string> FilterExistingFiles(List<string> files, Artist artist);
|
||||||
TrackFile Get(int id);
|
TrackFile Get(int id);
|
||||||
|
@ -98,5 +99,10 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
{
|
{
|
||||||
return _mediaFileRepository.GetFilesByArtist(artistId);
|
return _mediaFileRepository.GetFilesByArtist(artistId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<TrackFile> GetFilesByAlbum(int artistId, int albumId)
|
||||||
|
{
|
||||||
|
return _mediaFileRepository.GetFilesByArtist(artistId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
14
src/NzbDrone.Core/MediaFiles/RenameTrackFilePreview.cs
Normal file
14
src/NzbDrone.Core/MediaFiles/RenameTrackFilePreview.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles
|
||||||
|
{
|
||||||
|
public class RenameTrackFilePreview
|
||||||
|
{
|
||||||
|
public int ArtistId { get; set; }
|
||||||
|
public int AlbumId { get; set; }
|
||||||
|
public List<int> TrackNumbers { get; set; }
|
||||||
|
public int TrackFileId { get; set; }
|
||||||
|
public string ExistingPath { get; set; }
|
||||||
|
public string NewPath { get; set; }
|
||||||
|
}
|
||||||
|
}
|
185
src/NzbDrone.Core/MediaFiles/RenameTrackFileService.cs
Normal file
185
src/NzbDrone.Core/MediaFiles/RenameTrackFileService.cs
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Disk;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Instrumentation.Extensions;
|
||||||
|
using NzbDrone.Core.MediaFiles.Commands;
|
||||||
|
using NzbDrone.Core.MediaFiles.Events;
|
||||||
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.Organizer;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles
|
||||||
|
{
|
||||||
|
public interface IRenameTrackFileService
|
||||||
|
{
|
||||||
|
List<RenameTrackFilePreview> GetRenamePreviews(int artistId);
|
||||||
|
List<RenameTrackFilePreview> GetRenamePreviews(int artistId, int albumId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RenameTrackFileService : IRenameTrackFileService,
|
||||||
|
IExecute<RenameFilesCommand>,
|
||||||
|
IExecute<RenameArtistCommand>
|
||||||
|
{
|
||||||
|
private readonly IArtistService _artistService;
|
||||||
|
private readonly IAlbumService _albumService;
|
||||||
|
private readonly IMediaFileService _mediaFileService;
|
||||||
|
private readonly IMoveTrackFiles _trackFileMover;
|
||||||
|
private readonly IEventAggregator _eventAggregator;
|
||||||
|
private readonly ITrackService _trackService;
|
||||||
|
private readonly IBuildFileNames _filenameBuilder;
|
||||||
|
private readonly IDiskProvider _diskProvider;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public RenameTrackFileService(IArtistService artistService,
|
||||||
|
IAlbumService albumService,
|
||||||
|
IMediaFileService mediaFileService,
|
||||||
|
IMoveTrackFiles trackFileMover,
|
||||||
|
IEventAggregator eventAggregator,
|
||||||
|
ITrackService trackService,
|
||||||
|
IBuildFileNames filenameBuilder,
|
||||||
|
IDiskProvider diskProvider,
|
||||||
|
Logger logger)
|
||||||
|
{
|
||||||
|
_artistService = artistService;
|
||||||
|
_albumService = albumService;
|
||||||
|
_mediaFileService = mediaFileService;
|
||||||
|
_trackFileMover = trackFileMover;
|
||||||
|
_eventAggregator = eventAggregator;
|
||||||
|
_trackService = trackService;
|
||||||
|
_filenameBuilder = filenameBuilder;
|
||||||
|
_diskProvider = diskProvider;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<RenameTrackFilePreview> GetRenamePreviews(int artistId)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
throw new NotImplementedException();
|
||||||
|
//var artist = _artistService.GetArtist(artistId);
|
||||||
|
//var tracks = _trackService.GetTracksByArtist(artistId);
|
||||||
|
//var files = _mediaFileService.GetFilesByArtist(artistId);
|
||||||
|
|
||||||
|
//return GetPreviews(artist, tracks, files)
|
||||||
|
// .OrderByDescending(e => e.SeasonNumber)
|
||||||
|
// .ThenByDescending(e => e.TrackNumbers.First())
|
||||||
|
// .ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<RenameTrackFilePreview> GetRenamePreviews(int artistId, int albumId)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
var artist = _artistService.GetArtist(artistId);
|
||||||
|
var album = _albumService.GetAlbum(albumId);
|
||||||
|
var tracks = _trackService.GetTracksByAlbum(artistId, albumId);
|
||||||
|
var files = _mediaFileService.GetFilesByAlbum(artistId, albumId);
|
||||||
|
|
||||||
|
return GetPreviews(artist, album, tracks, files)
|
||||||
|
.OrderByDescending(e => e.TrackNumbers.First()).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<RenameTrackFilePreview> GetPreviews(Artist artist, Album album, List<Track> tracks, List<TrackFile> files)
|
||||||
|
{
|
||||||
|
foreach (var f in files)
|
||||||
|
{
|
||||||
|
var file = f;
|
||||||
|
var tracksInFile = tracks.Where(e => e.TrackFileId == file.Id).ToList();
|
||||||
|
var trackFilePath = Path.Combine(artist.Path, file.RelativePath);
|
||||||
|
|
||||||
|
if (!tracksInFile.Any())
|
||||||
|
{
|
||||||
|
_logger.Warn("File ({0}) is not linked to any tracks", trackFilePath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var albumId = tracksInFile.First().AlbumId;
|
||||||
|
var newName = _filenameBuilder.BuildTrackFileName(tracksInFile, artist, album, file);
|
||||||
|
var newPath = _filenameBuilder.BuildTrackFilePath(artist, album, newName, Path.GetExtension(trackFilePath));
|
||||||
|
|
||||||
|
if (!trackFilePath.PathEquals(newPath, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
yield return new RenameTrackFilePreview
|
||||||
|
{
|
||||||
|
ArtistId = artist.Id,
|
||||||
|
AlbumId = albumId,
|
||||||
|
TrackNumbers = tracksInFile.Select(e => e.TrackNumber).ToList(),
|
||||||
|
TrackFileId = file.Id,
|
||||||
|
ExistingPath = file.RelativePath,
|
||||||
|
NewPath = artist.Path.GetRelativePath(newPath)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenameFiles(List<TrackFile> trackFiles, Artist artist)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
throw new NotImplementedException();
|
||||||
|
//var renamed = new List<TrackFile>();
|
||||||
|
|
||||||
|
//foreach (var trackFile in trackFiles)
|
||||||
|
//{
|
||||||
|
// var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||||
|
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// _logger.Debug("Renaming track file: {0}", trackFile);
|
||||||
|
// _trackFileMover.MoveTrackFile(trackFile, artist);
|
||||||
|
|
||||||
|
// _mediaFileService.Update(trackFile);
|
||||||
|
// renamed.Add(trackFile);
|
||||||
|
|
||||||
|
// _logger.Debug("Renamed track file: {0}", trackFile);
|
||||||
|
// }
|
||||||
|
// catch (SameFilenameException ex)
|
||||||
|
// {
|
||||||
|
// _logger.Debug("File not renamed, source and destination are the same: {0}", ex.Filename);
|
||||||
|
// }
|
||||||
|
// catch (Exception ex)
|
||||||
|
// {
|
||||||
|
// _logger.Error(ex, "Failed to rename file {0}", trackFilePath);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//if (renamed.Any())
|
||||||
|
//{
|
||||||
|
// _diskProvider.RemoveEmptySubfolders(artist.Path);
|
||||||
|
|
||||||
|
// _eventAggregator.PublishEvent(new ArtistRenamedEvent(artist));
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(RenameFilesCommand message)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
throw new NotImplementedException();
|
||||||
|
//var artist = _artistService.GetArtist(message.ArtistId);
|
||||||
|
//var trackFiles = _mediaFileService.Get(message.Files);
|
||||||
|
|
||||||
|
//_logger.ProgressInfo("Renaming {0} files for {1}", trackFiles.Count, artist.Title);
|
||||||
|
//RenameFiles(trackFiles, artist);
|
||||||
|
//_logger.ProgressInfo("Selected track files renamed for {0}", artist.Title);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(RenameArtistCommand message)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
throw new NotImplementedException();
|
||||||
|
//_logger.Debug("Renaming all files for selected artist");
|
||||||
|
//var artistToRename = _artistService.GetArtist(message.ArtistIds);
|
||||||
|
|
||||||
|
//foreach (var artist in artistToRename)
|
||||||
|
//{
|
||||||
|
// var trackFiles = _mediaFileService.GetFilesByArtist(artist.Id);
|
||||||
|
// _logger.ProgressInfo("Renaming all files in artist: {0}", artist.Title);
|
||||||
|
// RenameFiles(trackFiles, artist);
|
||||||
|
// _logger.ProgressInfo("All track files renamed for {0}", artist.Title);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,10 @@ namespace NzbDrone.Core.Music
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ForeignArtistId { get; set; }
|
public string ForeignArtistId { get; set; }
|
||||||
|
public string MBId { get; set; }
|
||||||
|
public int TADBId { get; set; }
|
||||||
|
public int DiscogsId { get; set; }
|
||||||
|
public string AMId { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string NameSlug { get; set; }
|
public string NameSlug { get; set; }
|
||||||
public string CleanName { get; set; }
|
public string CleanName { get; set; }
|
||||||
|
@ -52,6 +56,10 @@ namespace NzbDrone.Core.Music
|
||||||
{
|
{
|
||||||
|
|
||||||
ForeignArtistId = otherArtist.ForeignArtistId;
|
ForeignArtistId = otherArtist.ForeignArtistId;
|
||||||
|
MBId = otherArtist.MBId;
|
||||||
|
TADBId = otherArtist.TADBId;
|
||||||
|
DiscogsId = otherArtist.DiscogsId;
|
||||||
|
AMId = otherArtist.AMId;
|
||||||
Name = otherArtist.Name;
|
Name = otherArtist.Name;
|
||||||
NameSlug = otherArtist.NameSlug;
|
NameSlug = otherArtist.NameSlug;
|
||||||
CleanName = otherArtist.CleanName;
|
CleanName = otherArtist.CleanName;
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace NzbDrone.Core.Music
|
||||||
|
|
||||||
public string ForeignTrackId { get; set; }
|
public string ForeignTrackId { get; set; }
|
||||||
public int AlbumId { get; set; }
|
public int AlbumId { get; set; }
|
||||||
public LazyLoaded<Artist> Artist { get; set; }
|
public Artist Artist { get; set; }
|
||||||
|
|
||||||
public int ArtistId { get; set; } // This is the DB Id of the Artist, not the SpotifyId
|
public int ArtistId { get; set; } // This is the DB Id of the Artist, not the SpotifyId
|
||||||
//public int CompilationId { get; set; }
|
//public int CompilationId { get; set; }
|
||||||
|
|
|
@ -724,7 +724,10 @@
|
||||||
<Compile Include="MediaFiles\Commands\BackendCommandAttribute.cs" />
|
<Compile Include="MediaFiles\Commands\BackendCommandAttribute.cs" />
|
||||||
<Compile Include="MediaFiles\Commands\CleanUpRecycleBinCommand.cs" />
|
<Compile Include="MediaFiles\Commands\CleanUpRecycleBinCommand.cs" />
|
||||||
<Compile Include="MediaFiles\Commands\DownloadedEpisodesScanCommand.cs" />
|
<Compile Include="MediaFiles\Commands\DownloadedEpisodesScanCommand.cs" />
|
||||||
|
<Compile Include="MediaFiles\Commands\RenameArtistCommand.cs" />
|
||||||
<Compile Include="MediaFiles\Events\TrackDownloadedEvent.cs" />
|
<Compile Include="MediaFiles\Events\TrackDownloadedEvent.cs" />
|
||||||
|
<Compile Include="MediaFiles\RenameTrackFilePreview.cs" />
|
||||||
|
<Compile Include="MediaFiles\RenameTrackFileService.cs" />
|
||||||
<Compile Include="MediaFiles\TrackFileMovingService.cs" />
|
<Compile Include="MediaFiles\TrackFileMovingService.cs" />
|
||||||
<Compile Include="MediaFiles\TrackFileMoveResult.cs" />
|
<Compile Include="MediaFiles\TrackFileMoveResult.cs" />
|
||||||
<Compile Include="MediaFiles\TrackImport\ImportMode.cs" />
|
<Compile Include="MediaFiles\TrackImport\ImportMode.cs" />
|
||||||
|
|
|
@ -20,7 +20,9 @@ namespace NzbDrone.Core.Organizer
|
||||||
string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig namingConfig = null);
|
string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig namingConfig = null);
|
||||||
string BuildTrackFileName(List<Track> tracks, Artist artist, Album album, TrackFile trackFile, NamingConfig namingConfig = null);
|
string BuildTrackFileName(List<Track> tracks, Artist artist, Album album, TrackFile trackFile, NamingConfig namingConfig = null);
|
||||||
string BuildFilePath(Series series, int seasonNumber, string fileName, string extension);
|
string BuildFilePath(Series series, int seasonNumber, string fileName, string extension);
|
||||||
|
string BuildTrackFilePath(Artist artist, Album album, string fileName, string extension);
|
||||||
string BuildSeasonPath(Series series, int seasonNumber);
|
string BuildSeasonPath(Series series, int seasonNumber);
|
||||||
|
string BuildAlbumPath(Artist artist, Album album);
|
||||||
BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec);
|
BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec);
|
||||||
string GetSeriesFolder(Series series, NamingConfig namingConfig = null);
|
string GetSeriesFolder(Series series, NamingConfig namingConfig = null);
|
||||||
string GetArtistFolder(Artist artist, NamingConfig namingConfig = null);
|
string GetArtistFolder(Artist artist, NamingConfig namingConfig = null);
|
||||||
|
@ -202,6 +204,15 @@ namespace NzbDrone.Core.Organizer
|
||||||
return Path.Combine(path, fileName + extension);
|
return Path.Combine(path, fileName + extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string BuildTrackFilePath(Artist artist, Album album, string fileName, string extension)
|
||||||
|
{
|
||||||
|
Ensure.That(extension, () => extension).IsNotNullOrWhiteSpace();
|
||||||
|
|
||||||
|
var path = BuildAlbumPath(artist, album);
|
||||||
|
|
||||||
|
return Path.Combine(path, fileName + extension);
|
||||||
|
}
|
||||||
|
|
||||||
public string BuildSeasonPath(Series series, int seasonNumber)
|
public string BuildSeasonPath(Series series, int seasonNumber)
|
||||||
{
|
{
|
||||||
var path = series.Path;
|
var path = series.Path;
|
||||||
|
@ -225,6 +236,24 @@ namespace NzbDrone.Core.Organizer
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string BuildAlbumPath(Artist artist, Album album)
|
||||||
|
{
|
||||||
|
var path = artist.Path;
|
||||||
|
|
||||||
|
if (artist.AlbumFolder)
|
||||||
|
{
|
||||||
|
|
||||||
|
var albumFolder = GetAlbumFolder(artist, album);
|
||||||
|
|
||||||
|
albumFolder = CleanFileName(albumFolder);
|
||||||
|
|
||||||
|
path = Path.Combine(path, albumFolder);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
public BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec)
|
public BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec)
|
||||||
{
|
{
|
||||||
var episodeFormat = GetEpisodeFormat(nameSpec.StandardEpisodeFormat).LastOrDefault();
|
var episodeFormat = GetEpisodeFormat(nameSpec.StandardEpisodeFormat).LastOrDefault();
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row new-artist-overview x-overview">
|
<!--<div class="row new-artist-overview x-overview">
|
||||||
<div class="col-md-12 overview-internal">
|
<div class="col-md-12 overview-internal">
|
||||||
{{overview}}
|
{{overview}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>-->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{#unless existing}}
|
{{#unless existing}}
|
||||||
{{#unless path}}
|
{{#unless path}}
|
||||||
|
|
|
@ -29,20 +29,18 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<span class="artist-info-links">
|
<span class="artist-info-links">
|
||||||
<a href="{{traktUrl}}" class="label label-info">Trakt</a>
|
<a href="{{MBUrl}}" class="label label-info">MusicBrainz</a>
|
||||||
|
|
||||||
<a href="{{tvdbUrl}}" class="label label-info">The TVDB</a>
|
{{#if tadbId}}
|
||||||
|
<a href="{{TADBUrl}}" class="label label-info">The AudioDB</a>
|
||||||
{{#if imdbId}}
|
|
||||||
<a href="{{imdbUrl}}" class="label label-info">IMDB</a>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if tvRageId}}
|
{{#if discogsId}}
|
||||||
<a href="{{tvRageUrl}}" class="label label-info">TV Rage</a>
|
<a href="{{discogsUrl}}" class="label label-info">Discogs</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if tvMazeId}}
|
{{#if amId}}
|
||||||
<a href="{{tvMazeUrl}}" class="label label-info">TV Maze</a>
|
<a href="{{allMusicUrl}}" class="label label-info">AllMusic</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -321,15 +321,17 @@ module.exports = Marionette.Layout.extend({
|
||||||
_showFooter : function() {
|
_showFooter : function() {
|
||||||
var footerModel = new FooterModel();
|
var footerModel = new FooterModel();
|
||||||
var artist = this.artistCollection.models.length;
|
var artist = this.artistCollection.models.length;
|
||||||
var episodes = 0;
|
var albums = 0;
|
||||||
var episodeFiles = 0;
|
var tracks = 0;
|
||||||
|
var trackFiles = 0;
|
||||||
var ended = 0;
|
var ended = 0;
|
||||||
var continuing = 0;
|
var continuing = 0;
|
||||||
var monitored = 0;
|
var monitored = 0;
|
||||||
|
|
||||||
_.each(this.artistCollection.models, function(model) {
|
_.each(this.artistCollection.models, function(model) {
|
||||||
episodes += model.get('episodeCount'); // TODO: Refactor to Seasons and Tracks
|
albums += model.get('albumCount');
|
||||||
episodeFiles += model.get('episodeFileCount');
|
tracks += model.get('episodeCount'); // TODO: Refactor to Seasons and Tracks
|
||||||
|
trackFiles += model.get('episodeFileCount');
|
||||||
|
|
||||||
/*if (model.get('status').toLowerCase() === 'ended') {
|
/*if (model.get('status').toLowerCase() === 'ended') {
|
||||||
ended++;
|
ended++;
|
||||||
|
@ -348,8 +350,9 @@ module.exports = Marionette.Layout.extend({
|
||||||
continuing : continuing,
|
continuing : continuing,
|
||||||
monitored : monitored,
|
monitored : monitored,
|
||||||
unmonitored : artist - monitored,
|
unmonitored : artist - monitored,
|
||||||
episodes : episodes,
|
albums : albums,
|
||||||
episodeFiles : episodeFiles
|
tracks : tracks,
|
||||||
|
trackFiles : trackFiles
|
||||||
});
|
});
|
||||||
|
|
||||||
this.footer.show(new FooterView({ model : footerModel }));
|
this.footer.show(new FooterView({ model : footerModel }));
|
||||||
|
|
|
@ -34,11 +34,14 @@
|
||||||
|
|
||||||
<div class="artist-stats col-sm-4">
|
<div class="artist-stats col-sm-4">
|
||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
|
<dt>Albums</dt>
|
||||||
|
<dd>{{albums}}</dd>
|
||||||
|
|
||||||
<dt>Tracks</dt>
|
<dt>Tracks</dt>
|
||||||
<dd>{{episodes}}</dd>
|
<dd>{{tracks}}</dd>
|
||||||
|
|
||||||
<dt>Files</dt>
|
<dt>Files</dt>
|
||||||
<dd>{{episodeFiles}}</dd>
|
<dd>{{trackFiles}}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="progress episode-progress">
|
<div class="progress track-progress">
|
||||||
<span class="progressbar-back-text">{{episodeFileCount}} / {{episodeCount}}</span>
|
<span class="progressbar-back-text">{{trackFileCount}} / {{trackCount}}</span>
|
||||||
<div class="progress-bar {{EpisodeProgressClass}} episode-progress" style="width:{{percentOfEpisodes}}%"><span class="progressbar-front-text">{{episodeFileCount}} / {{episodeCount}}</span></div>
|
<div class="progress-bar {{TrackProgressClass}} track-progress" style="width:{{percentOfTracks}}%"><span class="progressbar-front-text">{{trackFileCount}} / {{trackCount}}</span></div>
|
||||||
</div>
|
</div>
|
|
@ -4,11 +4,11 @@ var TrackModel = require('./TrackModel');
|
||||||
require('./TrackCollection');
|
require('./TrackCollection');
|
||||||
|
|
||||||
module.exports = PageableCollection.extend({
|
module.exports = PageableCollection.extend({
|
||||||
url : window.NzbDrone.ApiRoot + '/episode',
|
url : window.NzbDrone.ApiRoot + '/track',
|
||||||
model : TrackModel,
|
model : TrackModel,
|
||||||
|
|
||||||
state : {
|
state : {
|
||||||
sortKey : 'episodeNumber',
|
sortKey : 'trackNumber',
|
||||||
order : 1,
|
order : 1,
|
||||||
pageSize : 100000
|
pageSize : 100000
|
||||||
},
|
},
|
||||||
|
@ -18,28 +18,28 @@ module.exports = PageableCollection.extend({
|
||||||
originalFetch : Backbone.Collection.prototype.fetch,
|
originalFetch : Backbone.Collection.prototype.fetch,
|
||||||
|
|
||||||
initialize : function(options) {
|
initialize : function(options) {
|
||||||
this.seriesId = options.seriesId;
|
this.artistId = options.artistId;
|
||||||
},
|
},
|
||||||
|
|
||||||
bySeason : function(season) {
|
bySeason : function(album) {
|
||||||
var filtered = this.filter(function(episode) {
|
var filtered = this.filter(function(track) {
|
||||||
return episode.get('seasonNumber') === season;
|
return track.get('albumId') === album;
|
||||||
});
|
});
|
||||||
|
|
||||||
var EpisodeCollection = require('./TrackCollection');
|
var TrackCollection = require('./TrackCollection');
|
||||||
|
|
||||||
return new EpisodeCollection(filtered);
|
return new TrackCollection(filtered);
|
||||||
},
|
},
|
||||||
|
|
||||||
comparator : function(model1, model2) {
|
comparator : function(model1, model2) {
|
||||||
var episode1 = model1.get('episodeNumber');
|
var track1 = model1.get('trackNumber');
|
||||||
var episode2 = model2.get('episodeNumber');
|
var track2 = model2.get('trackNumber');
|
||||||
|
|
||||||
if (episode1 < episode2) {
|
if (track1 < track2) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (episode1 > episode2) {
|
if (track1 > track2) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,15 +47,15 @@ module.exports = PageableCollection.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
fetch : function(options) {
|
fetch : function(options) {
|
||||||
if (!this.seriesId) {
|
if (!this.artistId) {
|
||||||
throw 'seriesId is required';
|
throw 'artistId is required';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options) {
|
if (!options) {
|
||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
options.data = { seriesId : this.seriesId };
|
options.data = { artistId : this.artistId };
|
||||||
|
|
||||||
return this.originalFetch.call(this, options);
|
return this.originalFetch.call(this, options);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ var Backbone = require('backbone');
|
||||||
var TrackFileModel = require('./TrackFileModel');
|
var TrackFileModel = require('./TrackFileModel');
|
||||||
|
|
||||||
module.exports = Backbone.Collection.extend({
|
module.exports = Backbone.Collection.extend({
|
||||||
url : window.NzbDrone.ApiRoot + '/episodefile',
|
url : window.NzbDrone.ApiRoot + '/trackfile',
|
||||||
model : TrackFileModel,
|
model : TrackFileModel,
|
||||||
|
|
||||||
originalFetch : Backbone.Collection.prototype.fetch,
|
originalFetch : Backbone.Collection.prototype.fetch,
|
||||||
|
@ -21,7 +21,7 @@ module.exports = Backbone.Collection.extend({
|
||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
options.data = { seriesId : this.seriesId };
|
options.data = { artistId : this.artistId };
|
||||||
|
|
||||||
return this.originalFetch.call(this, options);
|
return this.originalFetch.call(this, options);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,12 @@ var Backbone = require('backbone');
|
||||||
|
|
||||||
module.exports = Backbone.Model.extend({
|
module.exports = Backbone.Model.extend({
|
||||||
defaults : {
|
defaults : {
|
||||||
seasonNumber : 0,
|
albumId : 0,
|
||||||
status : 0
|
status : 0
|
||||||
},
|
},
|
||||||
|
|
||||||
methodUrls : {
|
methodUrls : {
|
||||||
'update' : window.NzbDrone.ApiRoot + '/episode'
|
'update' : window.NzbDrone.ApiRoot + '/track'
|
||||||
},
|
},
|
||||||
|
|
||||||
sync : function(method, model, options) {
|
sync : function(method, model, options) {
|
||||||
|
|
|
@ -19,11 +19,6 @@ module.exports = NzbDroneController.extend({
|
||||||
this.showMainRegion(new AddArtistLayout({ action : action }));
|
this.showMainRegion(new AddArtistLayout({ action : action }));
|
||||||
},
|
},
|
||||||
|
|
||||||
artistDetails: function(query) {
|
|
||||||
this.setTitle('Artist Detail');
|
|
||||||
this.showMainRegion(new SeriesDetailsLayout());
|
|
||||||
},
|
|
||||||
|
|
||||||
calendar : function() {
|
calendar : function() {
|
||||||
this.setTitle('Calendar');
|
this.setTitle('Calendar');
|
||||||
this.showMainRegion(new CalendarLayout());
|
this.showMainRegion(new CalendarLayout());
|
||||||
|
|
|
@ -19,24 +19,20 @@ Handlebars.registerHelper('poster', function() {
|
||||||
return new Handlebars.SafeString('<img class="series-poster placeholder-image" src="{0}">'.format(placeholder));
|
return new Handlebars.SafeString('<img class="series-poster placeholder-image" src="{0}">'.format(placeholder));
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('traktUrl', function() {
|
Handlebars.registerHelper('MBUrl', function() {
|
||||||
return 'http://trakt.tv/search/tvdb/' + this.tvdbId + '?id_type=show';
|
return 'https://musicbrainz.org/artist/' + this.mbId;
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('imdbUrl', function() {
|
Handlebars.registerHelper('TADBUrl', function() {
|
||||||
return 'http://imdb.com/title/' + this.imdbId;
|
return 'http://www.theaudiodb.com/artist/' + this.tadbId;
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('tvdbUrl', function() {
|
Handlebars.registerHelper('discogsUrl', function() {
|
||||||
return 'http://www.thetvdb.com/?tab=series&id=' + this.tvdbId;
|
return 'https://www.discogs.com/artist/' + this.discogsId;
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('tvRageUrl', function() {
|
Handlebars.registerHelper('allMusicUrl', function() {
|
||||||
return 'http://www.tvrage.com/shows/id-' + this.tvRageId;
|
return 'http://www.allmusic.com/artist/' + this.amId;
|
||||||
});
|
|
||||||
|
|
||||||
Handlebars.registerHelper('tvMazeUrl', function() {
|
|
||||||
return 'http://www.tvmaze.com/shows/' + this.tvMazeId + '/_';
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('route', function() {
|
Handlebars.registerHelper('route', function() {
|
||||||
|
@ -56,6 +52,19 @@ Handlebars.registerHelper('percentOfEpisodes', function() {
|
||||||
return percent;
|
return percent;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Handlebars.registerHelper('percentOfTracks', function() {
|
||||||
|
var trackCount = this.trackCount;
|
||||||
|
var trackFileCount = this.trackFileCount;
|
||||||
|
|
||||||
|
var percent = 100;
|
||||||
|
|
||||||
|
if (trackCount > 0) {
|
||||||
|
percent = trackFileCount / trackCount * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
return percent;
|
||||||
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('seasonCountHelper', function() {
|
Handlebars.registerHelper('seasonCountHelper', function() {
|
||||||
var seasonCount = this.seasonCount;
|
var seasonCount = this.seasonCount;
|
||||||
var continuing = this.status === 'continuing';
|
var continuing = this.status === 'continuing';
|
||||||
|
@ -87,7 +96,7 @@ Handlebars.registerHelper('albumCountHelper', function() {
|
||||||
var albumCount = this.albumCount;
|
var albumCount = this.albumCount;
|
||||||
|
|
||||||
if (albumCount === 1) {
|
if (albumCount === 1) {
|
||||||
return new Handlebars.SafeString('<span class="label label-info">{0} Albums</span>'.format(albumCount));
|
return new Handlebars.SafeString('<span class="label label-info">{0} Album</span>'.format(albumCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Handlebars.SafeString('<span class="label label-info">{0} Albums</span>'.format(albumCount));
|
return new Handlebars.SafeString('<span class="label label-info">{0} Albums</span>'.format(albumCount));
|
||||||
|
|
|
@ -18,7 +18,6 @@ module.exports = Marionette.AppRouter.extend({
|
||||||
'rss' : 'rss',
|
'rss' : 'rss',
|
||||||
'system' : 'system',
|
'system' : 'system',
|
||||||
'system/:action' : 'system',
|
'system/:action' : 'system',
|
||||||
'artist/:query' : 'artistDetails',
|
|
||||||
'seasonpass' : 'seasonPass',
|
'seasonpass' : 'seasonPass',
|
||||||
'artisteditor' : 'artistEditor',
|
'artisteditor' : 'artistEditor',
|
||||||
':whatever' : 'showNotFound'
|
':whatever' : 'showNotFound'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue