mirror of
https://github.com/Lidarr/Lidarr
synced 2026-05-08 12:33:04 +02:00
New: Add SpotifySavedTracks import list
This commit is contained in:
parent
f6a3e73705
commit
3533c49a16
3 changed files with 327 additions and 0 deletions
|
|
@ -0,0 +1,222 @@
|
|||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.ImportLists.Spotify;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using SpotifyAPI.Web;
|
||||
using SpotifyAPI.Web.Models;
|
||||
|
||||
namespace NzbDrone.Core.Test.ImportListTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class SpotifySavedTracksFixture : CoreTest<SpotifySavedTracks>
|
||||
{
|
||||
[Test]
|
||||
public void should_not_throw_if_saved_tracks_is_null()
|
||||
{
|
||||
var paging = default(Paging<SavedTrack>);
|
||||
|
||||
Mocker.GetMock<ISpotifyProxy>().
|
||||
Setup(x => x.GetSavedTracks(It.IsAny<SpotifySavedTracks>(),
|
||||
It.IsAny<SpotifyWebAPI>()))
|
||||
.Returns(paging);
|
||||
|
||||
var result = Subject.Fetch(null);
|
||||
|
||||
result.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_throw_if_saved_track_items_is_null()
|
||||
{
|
||||
var savedTracks = new Paging<SavedTrack>
|
||||
{
|
||||
Items = null
|
||||
};
|
||||
|
||||
Mocker.GetMock<ISpotifyProxy>().
|
||||
Setup(x => x.GetSavedTracks(It.IsAny<SpotifySavedTracks>(),
|
||||
It.IsAny<SpotifyWebAPI>()))
|
||||
.Returns(savedTracks);
|
||||
|
||||
var result = Subject.Fetch(null);
|
||||
|
||||
result.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_throw_if_saved_track_is_null()
|
||||
{
|
||||
var savedTracks = new Paging<SavedTrack>
|
||||
{
|
||||
Items = new List<SavedTrack>
|
||||
{
|
||||
null
|
||||
}
|
||||
};
|
||||
|
||||
Mocker.GetMock<ISpotifyProxy>().
|
||||
Setup(x => x.GetSavedTracks(It.IsAny<SpotifySavedTracks>(),
|
||||
It.IsAny<SpotifyWebAPI>()))
|
||||
.Returns(savedTracks);
|
||||
|
||||
var result = Subject.Fetch(null);
|
||||
|
||||
result.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_throw_if_saved_track_track_is_null()
|
||||
{
|
||||
var savedTracks = new Paging<SavedTrack>
|
||||
{
|
||||
Items = new List<SavedTrack>
|
||||
{
|
||||
new SavedTrack
|
||||
{
|
||||
Track = null
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Mocker.GetMock<ISpotifyProxy>().
|
||||
Setup(x => x.GetSavedTracks(It.IsAny<SpotifySavedTracks>(),
|
||||
It.IsAny<SpotifyWebAPI>()))
|
||||
.Returns(savedTracks);
|
||||
|
||||
var result = Subject.Fetch(null);
|
||||
|
||||
result.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[TestCase("Artist", "Album")]
|
||||
public void should_parse_saved_track(string artistName, string albumName)
|
||||
{
|
||||
var savedTracks = new Paging<SavedTrack>
|
||||
{
|
||||
Items = new List<SavedTrack>
|
||||
{
|
||||
new SavedTrack
|
||||
{
|
||||
AddedAt = System.DateTime.Now,
|
||||
Track = new FullTrack
|
||||
{
|
||||
Album = new SimpleAlbum
|
||||
{
|
||||
Name = albumName,
|
||||
Artists = new List<SimpleArtist>
|
||||
{
|
||||
new SimpleArtist
|
||||
{
|
||||
Name = artistName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Mocker.GetMock<ISpotifyProxy>().
|
||||
Setup(x => x.GetSavedTracks(It.IsAny<SpotifySavedTracks>(),
|
||||
It.IsAny<SpotifyWebAPI>()))
|
||||
.Returns(savedTracks);
|
||||
|
||||
var result = Subject.Fetch(null);
|
||||
|
||||
result.Should().HaveCount(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_throw_if_get_next_page_returns_null()
|
||||
{
|
||||
var savedTracks = new Paging<SavedTrack>
|
||||
{
|
||||
Items = new List<SavedTrack>
|
||||
{
|
||||
new SavedTrack
|
||||
{
|
||||
AddedAt = System.DateTime.Now,
|
||||
Track = new FullTrack
|
||||
{
|
||||
Album = new SimpleAlbum
|
||||
{
|
||||
Name = "Album",
|
||||
Artists = new List<SimpleArtist>
|
||||
{
|
||||
new SimpleArtist
|
||||
{
|
||||
Name = "Artist"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Next = "DummyToMakeHasNextTrue"
|
||||
};
|
||||
|
||||
Mocker.GetMock<ISpotifyProxy>().
|
||||
Setup(x => x.GetSavedTracks(It.IsAny<SpotifySavedTracks>(),
|
||||
It.IsAny<SpotifyWebAPI>()))
|
||||
.Returns(savedTracks);
|
||||
|
||||
Mocker.GetMock<ISpotifyProxy>()
|
||||
.Setup(x => x.GetNextPage(It.IsAny<SpotifyFollowedArtists>(),
|
||||
It.IsAny<SpotifyWebAPI>(),
|
||||
It.IsAny<Paging<SavedTrack>>()))
|
||||
.Returns(default(Paging<SavedTrack>));
|
||||
|
||||
var result = Subject.Fetch(null);
|
||||
|
||||
result.Should().HaveCount(1);
|
||||
|
||||
Mocker.GetMock<ISpotifyProxy>()
|
||||
.Verify(x => x.GetNextPage(It.IsAny<SpotifySavedTracks>(),
|
||||
It.IsAny<SpotifyWebAPI>(),
|
||||
It.IsAny<Paging<SavedTrack>>()),
|
||||
Times.Once());
|
||||
}
|
||||
|
||||
[TestCase(null, "Album")]
|
||||
[TestCase("Artist", null)]
|
||||
[TestCase(null, null)]
|
||||
public void should_skip_bad_artist_or_album_names(string artistName, string albumName)
|
||||
{
|
||||
var savedTracks = new Paging<SavedTrack>
|
||||
{
|
||||
Items = new List<SavedTrack>
|
||||
{
|
||||
new SavedTrack
|
||||
{
|
||||
AddedAt = System.DateTime.Now,
|
||||
Track = new FullTrack
|
||||
{
|
||||
Album = new SimpleAlbum
|
||||
{
|
||||
Name = albumName,
|
||||
Artists = new List<SimpleArtist>
|
||||
{
|
||||
new SimpleArtist
|
||||
{
|
||||
Name = artistName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Mocker.GetMock<ISpotifyProxy>().
|
||||
Setup(x => x.GetSavedTracks(It.IsAny<SpotifySavedTracks>(),
|
||||
It.IsAny<SpotifyWebAPI>()))
|
||||
.Returns(savedTracks);
|
||||
|
||||
var result = Subject.Fetch(null);
|
||||
|
||||
result.Should().BeEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,8 @@ Paging<SavedAlbum> GetSavedAlbums<TSettings>(SpotifyImportListBase<TSettings> li
|
|||
where TSettings : SpotifySettingsBase<TSettings>, new();
|
||||
Paging<PlaylistTrack> GetPlaylistTracks<TSettings>(SpotifyImportListBase<TSettings> list, SpotifyWebAPI api, string id, string fields)
|
||||
where TSettings : SpotifySettingsBase<TSettings>, new();
|
||||
Paging<SavedTrack> GetSavedTracks<TSettings>(SpotifyImportListBase<TSettings> list, SpotifyWebAPI api)
|
||||
where TSettings : SpotifySettingsBase<TSettings>, new();
|
||||
Paging<T> GetNextPage<T, TSettings>(SpotifyImportListBase<TSettings> list, SpotifyWebAPI api, Paging<T> item)
|
||||
where TSettings : SpotifySettingsBase<TSettings>, new();
|
||||
FollowedArtists GetNextPage<TSettings>(SpotifyImportListBase<TSettings> list, SpotifyWebAPI api, FollowedArtists item)
|
||||
|
|
@ -63,6 +65,12 @@ public Paging<PlaylistTrack> GetPlaylistTracks<TSettings>(SpotifyImportListBase<
|
|||
return Execute(list, api, x => x.GetPlaylistTracks(id, fields: fields));
|
||||
}
|
||||
|
||||
public Paging<SavedTrack> GetSavedTracks<TSettings>(SpotifyImportListBase<TSettings> list, SpotifyWebAPI api)
|
||||
where TSettings : SpotifySettingsBase<TSettings>, new()
|
||||
{
|
||||
return Execute(list, api, x => x.GetSavedTracks());
|
||||
}
|
||||
|
||||
public Paging<T> GetNextPage<T, TSettings>(SpotifyImportListBase<TSettings> list, SpotifyWebAPI api, Paging<T> item)
|
||||
where TSettings : SpotifySettingsBase<TSettings>, new()
|
||||
{
|
||||
|
|
|
|||
97
src/NzbDrone.Core/ImportLists/Spotify/SpotifySavedTracks.cs
Normal file
97
src/NzbDrone.Core/ImportLists/Spotify/SpotifySavedTracks.cs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.Parser;
|
||||
using SpotifyAPI.Web;
|
||||
using SpotifyAPI.Web.Models;
|
||||
|
||||
namespace NzbDrone.Core.ImportLists.Spotify
|
||||
{
|
||||
public class SpotifySavedTracksSettings : SpotifySettingsBase<SpotifySavedTracksSettings>
|
||||
{
|
||||
public override string Scope => "user-library-read";
|
||||
}
|
||||
|
||||
public class SpotifySavedTracks : SpotifyImportListBase<SpotifySavedTracksSettings>
|
||||
{
|
||||
public SpotifySavedTracks(ISpotifyProxy spotifyProxy,
|
||||
IMetadataRequestBuilder requestBuilder,
|
||||
IImportListStatusService importListStatusService,
|
||||
IImportListRepository importListRepository,
|
||||
IConfigService configService,
|
||||
IParsingService parsingService,
|
||||
IHttpClient httpClient,
|
||||
Logger logger)
|
||||
: base(spotifyProxy, requestBuilder, importListStatusService, importListRepository, configService, parsingService, httpClient, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Name => "Spotify Saved Tracks";
|
||||
|
||||
public override IList<SpotifyImportListItemInfo> Fetch(SpotifyWebAPI api)
|
||||
{
|
||||
var result = new List<SpotifyImportListItemInfo>();
|
||||
|
||||
var savedTracks = _spotifyProxy.GetSavedTracks(this, api);
|
||||
|
||||
// savedTracks may be null if the spotify proxy returns nothing (e.g. user has no saved tracks)
|
||||
if (savedTracks == null)
|
||||
{
|
||||
_logger.Trace("No saved tracks returned");
|
||||
return result;
|
||||
}
|
||||
|
||||
_logger.Trace($"Got {savedTracks.Total} saved tracks");
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (savedTracks?.Items == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
foreach (var savedTrack in savedTracks.Items)
|
||||
{
|
||||
result.AddIfNotNull(ParseSavedTrack(savedTrack));
|
||||
}
|
||||
|
||||
if (!savedTracks.HasNextPage())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
savedTracks = _spotifyProxy.GetNextPage(this, api, savedTracks);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private SpotifyImportListItemInfo ParseSavedTrack(SavedTrack savedTrack)
|
||||
{
|
||||
// From spotify docs: "Note, a track object may be null. This can happen if a track is no longer available."
|
||||
if (savedTrack?.Track?.Album != null)
|
||||
{
|
||||
var album = savedTrack.Track.Album;
|
||||
var albumName = album.Name;
|
||||
var artistName = album.Artists?.FirstOrDefault()?.Name ?? savedTrack.Track?.Artists?.FirstOrDefault()?.Name;
|
||||
|
||||
if (albumName.IsNotNullOrWhiteSpace() && artistName.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
return new SpotifyImportListItemInfo
|
||||
{
|
||||
Artist = artistName,
|
||||
Album = album.Name,
|
||||
AlbumSpotifyId = album.Id,
|
||||
ReleaseDate = ParseSpotifyDate(album.ReleaseDate, album.ReleaseDatePrecision)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue