New: Update DB to store all releases for an album (#517)
* New: Store all releases for an album and track artists * Add Overview, links and release date by release * Tidy up * Fix metadata refresh errors following musicbrainz editspull/573/head
parent
24bdb5a891
commit
c392569a63
@ -0,0 +1,13 @@
|
|||||||
|
.links {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.linkLabel {
|
||||||
|
composes: label from 'Components/Label.css';
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import { kinds, sizes } from 'Helpers/Props';
|
||||||
|
import Label from 'Components/Label';
|
||||||
|
import Link from 'Components/Link/Link';
|
||||||
|
import styles from './AlbumDetailsLinks.css';
|
||||||
|
|
||||||
|
function AlbumDetailsLinks(props) {
|
||||||
|
const {
|
||||||
|
foreignAlbumId,
|
||||||
|
links
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.links}>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
className={styles.link}
|
||||||
|
to={`https://musicbrainz.org/release-group/${foreignAlbumId}`}
|
||||||
|
>
|
||||||
|
<Label
|
||||||
|
className={styles.linkLabel}
|
||||||
|
kind={kinds.INFO}
|
||||||
|
size={sizes.LARGE}
|
||||||
|
>
|
||||||
|
Musicbrainz
|
||||||
|
</Label>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{links.map((link, index) => {
|
||||||
|
return (
|
||||||
|
<span key={index}>
|
||||||
|
<Link className={styles.link}
|
||||||
|
to={link.url}
|
||||||
|
key={index}
|
||||||
|
>
|
||||||
|
<Label
|
||||||
|
className={styles.linkLabel}
|
||||||
|
kind={kinds.INFO}
|
||||||
|
size={sizes.LARGE}
|
||||||
|
>
|
||||||
|
{link.name}
|
||||||
|
</Label>
|
||||||
|
</Link>
|
||||||
|
{(index > 0 && index % 5 === 0) &&
|
||||||
|
<br />
|
||||||
|
}
|
||||||
|
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
AlbumDetailsLinks.propTypes = {
|
||||||
|
foreignAlbumId: PropTypes.string.isRequired,
|
||||||
|
links: PropTypes.arrayOf(PropTypes.object).isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AlbumDetailsLinks;
|
@ -0,0 +1,247 @@
|
|||||||
|
using FluentMigrator;
|
||||||
|
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||||
|
using NzbDrone.Common.Serializer;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
using System.Data;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
{
|
||||||
|
[Migration(023)]
|
||||||
|
public class add_release_groups_etc : NzbDroneMigrationBase
|
||||||
|
{
|
||||||
|
protected override void MainDbUpgrade()
|
||||||
|
{
|
||||||
|
// ARTISTS TABLE
|
||||||
|
|
||||||
|
Create.TableForModel("ArtistMetadata")
|
||||||
|
.WithColumn("ForeignArtistId").AsString().Unique()
|
||||||
|
.WithColumn("Name").AsString()
|
||||||
|
.WithColumn("Overview").AsString().Nullable()
|
||||||
|
.WithColumn("Disambiguation").AsString().Nullable()
|
||||||
|
.WithColumn("Type").AsString().Nullable()
|
||||||
|
.WithColumn("Status").AsInt32()
|
||||||
|
.WithColumn("Images").AsString()
|
||||||
|
.WithColumn("Links").AsString().Nullable()
|
||||||
|
.WithColumn("Genres").AsString().Nullable()
|
||||||
|
.WithColumn("Ratings").AsString().Nullable()
|
||||||
|
.WithColumn("Members").AsString().Nullable();
|
||||||
|
|
||||||
|
// we want to preserve the artist ID. Shove all the metadata into the metadata table.
|
||||||
|
Execute.Sql(@"INSERT INTO ArtistMetadata (ForeignArtistId, Name, Overview, Disambiguation, Type, Status, Images, Links, Genres, Ratings, Members)
|
||||||
|
SELECT ForeignArtistId, Name, Overview, Disambiguation, ArtistType, Status, Images, Links, Genres, Ratings, Members
|
||||||
|
FROM Artists");
|
||||||
|
|
||||||
|
// Add an ArtistMetadataId column to Artists
|
||||||
|
Alter.Table("Artists").AddColumn("ArtistMetadataId").AsInt32().WithDefaultValue(0);
|
||||||
|
|
||||||
|
// Update artistmetadataId
|
||||||
|
Execute.Sql(@"UPDATE Artists
|
||||||
|
SET ArtistMetadataId = (SELECT ArtistMetadata.Id
|
||||||
|
FROM ArtistMetadata
|
||||||
|
WHERE ArtistMetadata.ForeignArtistId = Artists.ForeignArtistId)");
|
||||||
|
|
||||||
|
// ALBUM RELEASES TABLE - Do this before we mess with the Albums table
|
||||||
|
|
||||||
|
Create.TableForModel("AlbumReleases")
|
||||||
|
.WithColumn("ForeignReleaseId").AsString().Unique()
|
||||||
|
.WithColumn("AlbumId").AsInt32().Indexed()
|
||||||
|
.WithColumn("Title").AsString()
|
||||||
|
.WithColumn("Status").AsString()
|
||||||
|
.WithColumn("Duration").AsInt32().WithDefaultValue(0)
|
||||||
|
.WithColumn("Label").AsString().Nullable()
|
||||||
|
.WithColumn("Disambiguation").AsString().Nullable()
|
||||||
|
.WithColumn("Country").AsString().Nullable()
|
||||||
|
.WithColumn("ReleaseDate").AsDateTime().Nullable()
|
||||||
|
.WithColumn("Media").AsString().Nullable()
|
||||||
|
.WithColumn("TrackCount").AsInt32().Nullable()
|
||||||
|
.WithColumn("Monitored").AsBoolean();
|
||||||
|
|
||||||
|
Execute.WithConnection(PopulateReleases);
|
||||||
|
|
||||||
|
// ALBUMS TABLE
|
||||||
|
|
||||||
|
// Add in the extra columns and update artist metadata id
|
||||||
|
Alter.Table("Albums").AddColumn("ArtistMetadataId").AsInt32().WithDefaultValue(0);
|
||||||
|
Alter.Table("Albums").AddColumn("AnyReleaseOk").AsBoolean().WithDefaultValue(true);
|
||||||
|
Alter.Table("Albums").AddColumn("Links").AsString().Nullable();
|
||||||
|
|
||||||
|
// Set metadata ID
|
||||||
|
Execute.Sql(@"UPDATE Albums
|
||||||
|
SET ArtistMetadataId = (SELECT ArtistMetadata.Id
|
||||||
|
FROM ArtistMetadata
|
||||||
|
JOIN Artists ON ArtistMetadata.Id = Artists.ArtistMetadataId
|
||||||
|
WHERE Albums.ArtistId = Artists.Id)");
|
||||||
|
|
||||||
|
// TRACKS TABLE
|
||||||
|
Alter.Table("Tracks").AddColumn("ForeignRecordingId").AsString().WithDefaultValue("0");
|
||||||
|
Alter.Table("Tracks").AddColumn("AlbumReleaseId").AsInt32().WithDefaultValue(0);
|
||||||
|
Alter.Table("Tracks").AddColumn("ArtistMetadataId").AsInt32().WithDefaultValue(0);
|
||||||
|
|
||||||
|
// Set track release to the only release we've bothered populating
|
||||||
|
Execute.Sql(@"UPDATE Tracks
|
||||||
|
SET AlbumReleaseId = (SELECT AlbumReleases.Id
|
||||||
|
FROM AlbumReleases
|
||||||
|
JOIN Albums ON AlbumReleases.AlbumId = Albums.Id
|
||||||
|
WHERE Albums.Id = Tracks.AlbumId)");
|
||||||
|
|
||||||
|
// CLEAR OUT OLD COLUMNS
|
||||||
|
|
||||||
|
// Remove the columns in Artists now in ArtistMetadata
|
||||||
|
Delete.Column("ForeignArtistId")
|
||||||
|
.Column("Name")
|
||||||
|
.Column("Overview")
|
||||||
|
.Column("Disambiguation")
|
||||||
|
.Column("ArtistType")
|
||||||
|
.Column("Status")
|
||||||
|
.Column("Images")
|
||||||
|
.Column("Links")
|
||||||
|
.Column("Genres")
|
||||||
|
.Column("Ratings")
|
||||||
|
.Column("Members")
|
||||||
|
// as well as the ones no longer used
|
||||||
|
.Column("MBId")
|
||||||
|
.Column("AMId")
|
||||||
|
.Column("TADBId")
|
||||||
|
.Column("DiscogsId")
|
||||||
|
.Column("NameSlug")
|
||||||
|
.Column("LastDiskSync")
|
||||||
|
.Column("DateFormed")
|
||||||
|
.FromTable("Artists");
|
||||||
|
|
||||||
|
// Remove old columns from Albums
|
||||||
|
Delete.Column("ArtistId")
|
||||||
|
.Column("MBId")
|
||||||
|
.Column("AMId")
|
||||||
|
.Column("TADBId")
|
||||||
|
.Column("DiscogsId")
|
||||||
|
.Column("TitleSlug")
|
||||||
|
.Column("Label")
|
||||||
|
.Column("SortTitle")
|
||||||
|
.Column("Tags")
|
||||||
|
.Column("Duration")
|
||||||
|
.Column("Media")
|
||||||
|
.Column("Releases")
|
||||||
|
.Column("CurrentRelease")
|
||||||
|
.Column("LastDiskSync")
|
||||||
|
.FromTable("Albums");
|
||||||
|
|
||||||
|
// Remove old columns from Tracks
|
||||||
|
Delete.Column("ArtistId")
|
||||||
|
.Column("AlbumId")
|
||||||
|
.Column("Compilation")
|
||||||
|
.Column("DiscNumber")
|
||||||
|
.Column("Monitored")
|
||||||
|
.FromTable("Tracks");
|
||||||
|
|
||||||
|
// Remove old columns from TrackFiles
|
||||||
|
Delete.Column("ArtistId").FromTable("TrackFiles");
|
||||||
|
|
||||||
|
// Add indices
|
||||||
|
Create.Index().OnTable("Artists").OnColumn("ArtistMetadataId").Ascending();
|
||||||
|
Create.Index().OnTable("Artists").OnColumn("Monitored").Ascending();
|
||||||
|
Create.Index().OnTable("Albums").OnColumn("ArtistMetadataId").Ascending();
|
||||||
|
Create.Index().OnTable("Tracks").OnColumn("ArtistMetadataId").Ascending();
|
||||||
|
Create.Index().OnTable("Tracks").OnColumn("AlbumReleaseId").Ascending();
|
||||||
|
Create.Index().OnTable("Tracks").OnColumn("ForeignRecordingId").Ascending();
|
||||||
|
|
||||||
|
// Force a metadata refresh
|
||||||
|
Update.Table("Artists").Set(new { LastInfoSync = new System.DateTime(2018, 1, 1, 0, 0, 1)}).AllRows();
|
||||||
|
Update.Table("Albums").Set(new { LastInfoSync = new System.DateTime(2018, 1, 1, 0, 0, 1)}).AllRows();
|
||||||
|
Update.Table("ScheduledTasks")
|
||||||
|
.Set(new { LastExecution = new System.DateTime(2018, 1, 1, 0, 0, 1)})
|
||||||
|
.Where(new { TypeName = "NzbDrone.Core.Music.Commands.RefreshArtistCommand" });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PopulateReleases(IDbConnection conn, IDbTransaction tran)
|
||||||
|
{
|
||||||
|
var releases = ReadReleasesFromAlbums(conn, tran);
|
||||||
|
WriteReleasesToReleases(releases,conn, tran);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LegacyAlbumRelease : IEmbeddedDocument
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public DateTime? ReleaseDate { get; set; }
|
||||||
|
public int TrackCount { get; set; }
|
||||||
|
public int MediaCount { get; set; }
|
||||||
|
public string Disambiguation { get; set; }
|
||||||
|
public List<string> Country { get; set; }
|
||||||
|
public string Format { get; set; }
|
||||||
|
public List<string> Label { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<AlbumRelease> ReadReleasesFromAlbums(IDbConnection conn, IDbTransaction tran)
|
||||||
|
{
|
||||||
|
|
||||||
|
// need to get all the old albums
|
||||||
|
var releases = new List<AlbumRelease>();
|
||||||
|
|
||||||
|
using (var getReleasesCmd = conn.CreateCommand())
|
||||||
|
{
|
||||||
|
getReleasesCmd.Transaction = tran;
|
||||||
|
getReleasesCmd.CommandText = @"SELECT Id, CurrentRelease FROM Albums";
|
||||||
|
|
||||||
|
using (var releaseReader = getReleasesCmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (releaseReader.Read())
|
||||||
|
{
|
||||||
|
int rgId = releaseReader.GetInt32(0);
|
||||||
|
var albumRelease = Json.Deserialize<LegacyAlbumRelease>(releaseReader.GetString(1));
|
||||||
|
var media = new List<Medium>();
|
||||||
|
for (var i = 1; i <= albumRelease.MediaCount; i++)
|
||||||
|
{
|
||||||
|
media.Add(new Medium { Number = i, Name = "", Format = albumRelease.Format } );
|
||||||
|
}
|
||||||
|
|
||||||
|
releases.Add(new AlbumRelease {
|
||||||
|
AlbumId = rgId,
|
||||||
|
ForeignReleaseId = albumRelease.Id,
|
||||||
|
Title = albumRelease.Title,
|
||||||
|
Status = "",
|
||||||
|
Duration = 0,
|
||||||
|
Label = albumRelease.Label,
|
||||||
|
Disambiguation = albumRelease.Disambiguation,
|
||||||
|
Country = albumRelease.Country,
|
||||||
|
Media=media,
|
||||||
|
TrackCount = albumRelease.TrackCount,
|
||||||
|
Monitored = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return releases;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteReleasesToReleases(List<AlbumRelease> releases, IDbConnection conn, IDbTransaction tran)
|
||||||
|
{
|
||||||
|
foreach (var release in releases)
|
||||||
|
{
|
||||||
|
using (var writeReleaseCmd = conn.CreateCommand())
|
||||||
|
{
|
||||||
|
writeReleaseCmd.Transaction = tran;
|
||||||
|
writeReleaseCmd.CommandText =
|
||||||
|
"INSERT INTO AlbumReleases (AlbumId, ForeignReleaseId, Title, Status, Duration, Label, Disambiguation, Country, Media, TrackCount, Monitored) " +
|
||||||
|
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
|
writeReleaseCmd.AddParameter(release.AlbumId);
|
||||||
|
writeReleaseCmd.AddParameter(release.ForeignReleaseId);
|
||||||
|
writeReleaseCmd.AddParameter(release.Title);
|
||||||
|
writeReleaseCmd.AddParameter(release.Status);
|
||||||
|
writeReleaseCmd.AddParameter(release.Duration);
|
||||||
|
writeReleaseCmd.AddParameter(release.Label.ToJson());
|
||||||
|
writeReleaseCmd.AddParameter(release.Disambiguation);
|
||||||
|
writeReleaseCmd.AddParameter(release.Country.ToJson());
|
||||||
|
writeReleaseCmd.AddParameter(release.Media.ToJson());
|
||||||
|
writeReleaseCmd.AddParameter(release.TrackCount);
|
||||||
|
writeReleaseCmd.AddParameter(release.Monitored);
|
||||||
|
|
||||||
|
writeReleaseCmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||||
|
{
|
||||||
|
public class CleanupOrphanedArtistMetadata : IHousekeepingTask
|
||||||
|
{
|
||||||
|
private readonly IMainDatabase _database;
|
||||||
|
|
||||||
|
public CleanupOrphanedArtistMetadata(IMainDatabase database)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clean()
|
||||||
|
{
|
||||||
|
var mapper = _database.GetDataMapper();
|
||||||
|
|
||||||
|
mapper.ExecuteNonQuery(@"DELETE FROM ArtistMetadata
|
||||||
|
WHERE Id IN (
|
||||||
|
SELECT ArtistMetadata.Id FROM ArtistMetadata
|
||||||
|
LEFT OUTER JOIN Albums ON Albums.ArtistMetadataId = ArtistMetadata.Id
|
||||||
|
LEFT OUTER JOIN Tracks ON Tracks.ArtistMetadataId = ArtistMetadata.Id
|
||||||
|
WHERE Albums.Id IS NULL AND Tracks.Id IS NULL)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||||
|
{
|
||||||
|
public class CleanupOrphanedReleases : IHousekeepingTask
|
||||||
|
{
|
||||||
|
private readonly IMainDatabase _database;
|
||||||
|
|
||||||
|
public CleanupOrphanedReleases(IMainDatabase database)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clean()
|
||||||
|
{
|
||||||
|
var mapper = _database.GetDataMapper();
|
||||||
|
|
||||||
|
mapper.ExecuteNonQuery(@"DELETE FROM AlbumReleases
|
||||||
|
WHERE Id IN (
|
||||||
|
SELECT AlbumReleases.Id FROM AlbumReleases
|
||||||
|
LEFT OUTER JOIN Albums
|
||||||
|
ON AlbumReleases.AlbumId = Albums.Id
|
||||||
|
WHERE Albums.Id IS NULL)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.MetadataSource.SkyHook.Resource
|
|
||||||
{
|
|
||||||
public class AlbumArtistResource
|
|
||||||
{
|
|
||||||
public string Id { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
namespace NzbDrone.Core.MetadataSource.SkyHook.Resource
|
|
||||||
{
|
|
||||||
public class MemberResource
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
public string Instrument { get; set; }
|
|
||||||
public string Image { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
namespace NzbDrone.Core.MetadataSource.SkyHook.Resource
|
|
||||||
{
|
|
||||||
public class TimeOfDayResource
|
|
||||||
{
|
|
||||||
public int Hours { get; set; }
|
|
||||||
public int Minutes { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue