455 lines
13 KiB
C#
455 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Threading;
|
|
using System.Windows.Forms;
|
|
using Autofac;
|
|
using BitFactory.Logging;
|
|
using MusicMetaTagger.Client.AllMusicGuide.RemoteDataAccess;
|
|
using MusicMetaTagger.Client.AllMusicGuide.Services;
|
|
using MusicMetaTagger.Core.Model;
|
|
using MusicMetaTagger.Core.Services;
|
|
using IContainer = Autofac.IContainer;
|
|
|
|
namespace MusicMetaTagger.UI
|
|
{
|
|
public partial class Interface : Form, IProgressCallback
|
|
{
|
|
#region Private members
|
|
|
|
private const string LogFilename = "tagger.log";
|
|
|
|
private readonly Logger _logger;
|
|
|
|
private readonly BindingList<TrackQueryStatus> _trackQueryStatuses;
|
|
|
|
private CancellationTokenSource _cancellationTokenSource;
|
|
|
|
private bool _exitClicked;
|
|
private IMusicGuide _musicGuide;
|
|
private ITrackSearcher _trackSearcher;
|
|
private IMusicLibraryInterface _musicLibraryInterface;
|
|
private ITrackRater _trackRater;
|
|
|
|
private Options _options;
|
|
private readonly IContainer _container;
|
|
private ITrackOriginalRelease _trackOriginalRelease;
|
|
|
|
#endregion
|
|
|
|
#region Form Event Handlers
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref = "Interface" /> class.
|
|
/// </summary>
|
|
public Interface()
|
|
{
|
|
InitializeComponent();
|
|
_trackQueryStatuses = new BindingList<TrackQueryStatus>();
|
|
logDataGridView.DataSource = _trackQueryStatuses;
|
|
_logger = new FileLogger(LogFilename);
|
|
_cancellationTokenSource = new CancellationTokenSource();
|
|
|
|
var builder = new ContainerBuilder();
|
|
builder
|
|
.RegisterAssemblyTypes(typeof(MusicGuideScraper).Assembly)
|
|
.AsImplementedInterfaces()
|
|
.Except<MusicGuideScraper>()
|
|
.Except<MusicGuideCache>();
|
|
builder.RegisterType<TrackSearcher>().As<ITrackSearcher>();
|
|
builder.RegisterType<MusicGuideScraper>().Named<IMusicGuide>("MusicGuideScraper");
|
|
builder.RegisterDecorator<IMusicGuide>((c, inner) => new MusicGuideCache(inner), fromKey: "MusicGuideScraper");
|
|
_container = builder.Build();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles the Load event of the Interface control.
|
|
/// </summary>
|
|
/// <param name = "sender">The source of the event.</param>
|
|
/// <param name = "e">The <see cref = "System.EventArgs" /> instance containing the event data.</param>
|
|
private void Interface_Load(object sender, EventArgs e)
|
|
{
|
|
_options = new Options();
|
|
components.Add(_options);
|
|
optionsLabel.Text = _options.LibraryQuery.ToString();
|
|
var t = new Thread(OpenOrCreateAllMusicGuide);
|
|
t.Start();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles the Click event of the startButton control.
|
|
/// </summary>
|
|
/// <param name = "sender">The source of the event.</param>
|
|
/// <param name = "e">The <see cref = "System.EventArgs" /> instance containing the event data.</param>
|
|
private void startButton_Click(object sender, EventArgs e)
|
|
{
|
|
librarySelector.Enabled = false;
|
|
startButton.Enabled = false;
|
|
optionsButton.Enabled = false;
|
|
_musicLibraryInterface = librarySelector.SelectedLibrary;
|
|
|
|
var t = new Thread(LibraryProcess);
|
|
t.Start();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles the Click event of the cancelButton control.
|
|
/// </summary>
|
|
/// <param name = "sender">The source of the event.</param>
|
|
/// <param name = "e">The <see cref = "System.EventArgs" /> instance containing the event data.</param>
|
|
private void cancelButton_Click(object sender, EventArgs e)
|
|
{
|
|
UiInvoke(() => { toolStripStatusLabel.Text = "Cancelling..."; });
|
|
cancelButton.Enabled = false;
|
|
_cancellationTokenSource.Cancel();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Handles the FormClosing event of the Interface control.
|
|
/// </summary>
|
|
/// <param name = "sender">The source of the event.</param>
|
|
/// <param name = "e">The <see cref = "System.Windows.Forms.FormClosingEventArgs" /> instance containing the event data.</param>
|
|
private void Interface_FormClosing(object sender, FormClosingEventArgs e)
|
|
{
|
|
if (!exitButton.Enabled)
|
|
{
|
|
_exitClicked = true;
|
|
_cancellationTokenSource.Cancel();
|
|
e.Cancel = true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles the Click event of the exitButton control.
|
|
/// </summary>
|
|
/// <param name = "sender">The source of the event.</param>
|
|
/// <param name = "e">The <see cref = "System.EventArgs" /> instance containing the event data.</param>
|
|
private void exitButton_Click(object sender, EventArgs e)
|
|
{
|
|
Close();
|
|
}
|
|
|
|
private void optionsButton_Click(object sender, EventArgs e)
|
|
{
|
|
_options.ShowDialog();
|
|
optionsLabel.Text = _options.LibraryQuery.ToString();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Music Guide threaded methods
|
|
|
|
private void OpenOrCreateAllMusicGuide()
|
|
{
|
|
UiInvoke(() => { startButton.Enabled = false; });
|
|
UiInvoke(() => { exitButton.Enabled = false; });
|
|
UiInvoke(() => { toolStripStatusLabel.Text = "Loading DataLayer..."; });
|
|
UiInvoke(() => { toolStripStatusLabel.Text = "Loading Complete."; });
|
|
UiInvoke(() => { startButton.Enabled = true; });
|
|
UiInvoke(() => { exitButton.Enabled = true; });
|
|
|
|
_musicGuide = _container.Resolve<IMusicGuide>();
|
|
_trackSearcher = _container.Resolve<ITrackSearcher>();
|
|
_trackRater = _container.Resolve<ITrackRater>();
|
|
_trackOriginalRelease = _container.Resolve<ITrackOriginalRelease>();
|
|
|
|
if (_exitClicked)
|
|
{
|
|
UiInvoke(() => { toolStripStatusLabel.Text = "Exiting..."; });
|
|
UiInvoke(() => exitButton_Click(this, new EventArgs()));
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Utility Methods
|
|
|
|
private void LogStatusUpdate(StatusEventArgs data)
|
|
{
|
|
_logger.LogInfo(data.Status);
|
|
}
|
|
|
|
private static string ConcatToString(string original, string additional)
|
|
{
|
|
return !string.IsNullOrEmpty(original) ? string.Join(", ", additional, original) : additional;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Library Process methods
|
|
|
|
private Track SearchTrack(TrackQueryStatus trackQuery)
|
|
{
|
|
_trackSearcher.SearchStatusUpdate += trackQuery.UpdateStatus;
|
|
_trackSearcher.SearchStatusUpdate += LogStatusUpdate;
|
|
var result = _trackSearcher.SearchTrack(trackQuery, _cancellationTokenSource.Token);
|
|
_trackSearcher.SearchStatusUpdate -= trackQuery.UpdateStatus;
|
|
_trackSearcher.SearchStatusUpdate -= LogStatusUpdate;
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the track information to the library.
|
|
/// </summary>
|
|
/// <param name = "trackQuery">The track query.</param>
|
|
/// <param name = "track">The track info.</param>
|
|
private void UpdateTrack(TrackQueryStatus trackQuery, Track track)
|
|
{
|
|
var updateText = "";
|
|
|
|
var albumInfo = string.IsNullOrEmpty(track.AlbumId)
|
|
? null
|
|
: _musicGuide.GetAlbum(track.AlbumId);
|
|
var artistInfo = string.IsNullOrEmpty(track.PerformerIds[0])
|
|
? null
|
|
: _musicGuide.GetArtist(track.PerformerIds[0]);
|
|
|
|
// If Track is not null, update ActualTrack from Track
|
|
if (albumInfo != null)
|
|
{
|
|
// set album artwork
|
|
if (!string.IsNullOrEmpty(albumInfo.CoverUrl))
|
|
{
|
|
try
|
|
{
|
|
// TODO: Cover Art Reimplementation
|
|
|
|
//var fileInfo = albumInfo.DownloadCoverArt();
|
|
//if (fileInfo != null)
|
|
//{
|
|
// if (_musicLibraryInterface.UpdateAlbumArt(trackQuery, fileInfo, _options.LibraryUpdate.AlbumArtOverwrite))
|
|
// {
|
|
// updateText = ConcatToString(updateText, "Added artwork");
|
|
// trackQuery.SetText(updateText);
|
|
// }
|
|
// if (mp3FileInfo != null)
|
|
// _mp3Interface.UpdateAlbumArt(mp3FileInfo, fileInfo, _options.LibraryUpdate.AlbumArtOverwrite);
|
|
//}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex.ToString());
|
|
updateText = ConcatToString(updateText, "Artwork error: " + ex.Message);
|
|
trackQuery.Status = updateText;
|
|
}
|
|
}
|
|
|
|
if (artistInfo != null)
|
|
{
|
|
if (_options.LibraryUpdate.GenreUpdate)
|
|
{
|
|
// set genre
|
|
string genre;
|
|
if (artistInfo.Genre == "Rock" && albumInfo.Styles != null && albumInfo.Styles.Count > 0)
|
|
genre = albumInfo.Styles[0];
|
|
else
|
|
genre = artistInfo.Genre;
|
|
if (_musicLibraryInterface.UpdateGenre(trackQuery, genre, _options.LibraryUpdate.GenreOverwrite))
|
|
{
|
|
updateText = ConcatToString(updateText, "Genre: " + genre);
|
|
trackQuery.Status = updateText;
|
|
}
|
|
}
|
|
}
|
|
|
|
// set year
|
|
if (_options.LibraryUpdate.YearUpdate && !string.IsNullOrEmpty(albumInfo.ReleaseDate))
|
|
{
|
|
var year = albumInfo.GetReleaseYear();
|
|
if (_musicLibraryInterface.UpdateYear(trackQuery, year, _options.LibraryUpdate.YearOverwrite))
|
|
{
|
|
updateText = ConcatToString(updateText, "Year: " + year);
|
|
trackQuery.Status = updateText;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_options.LibraryUpdate.RatingUpdate)
|
|
{
|
|
// update rating
|
|
var rating = _trackRater.RateTrack(track);
|
|
|
|
if (!rating.HasValue)
|
|
{
|
|
updateText = ConcatToString(updateText, "Track has no rating");
|
|
trackQuery.Status = updateText;
|
|
}
|
|
else
|
|
{
|
|
if (track.Pick)
|
|
_musicLibraryInterface.AddComment(trackQuery, "-AMG Pick-");
|
|
|
|
var ratingInt = Convert.ToInt32(rating.Value*10);
|
|
if (_musicLibraryInterface.UpdateRating(trackQuery, ratingInt, _options.LibraryUpdate.RatingOverwrite))
|
|
{
|
|
updateText = ConcatToString(updateText, "Rating: " + ratingInt + " / 100");
|
|
trackQuery.Status = updateText;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UiInvoke(Action action)
|
|
{
|
|
BeginInvoke(new MethodInvoker(action));
|
|
}
|
|
|
|
private void LibraryProcess()
|
|
{
|
|
UiInvoke(
|
|
() =>
|
|
{
|
|
cancelButton.Enabled = true;
|
|
cancelButton.Visible = true;
|
|
exitButton.Enabled = false;
|
|
});
|
|
|
|
Begin();
|
|
|
|
// Use LibraryQuery to build a list of trackQueries
|
|
List<TrackQueryStatus> trackQueries;
|
|
try
|
|
{
|
|
trackQueries = _musicLibraryInterface.GetTrackQueries(_options.LibraryQuery, this);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex.ToString());
|
|
trackQueries = new List<TrackQueryStatus>();
|
|
UiInvoke(() => MessageBox.Show(ex.Message));
|
|
}
|
|
|
|
End();
|
|
SetRange(0, trackQueries.Count);
|
|
StepTo(0);
|
|
|
|
// Search for TrackQuery
|
|
var i = 1;
|
|
foreach (var trackQuery in trackQueries)
|
|
{
|
|
Increment(1);
|
|
SetText(string.Format("{0} / {1}", i++, trackQueries.Count));
|
|
|
|
if (_cancellationTokenSource.IsCancellationRequested)
|
|
break;
|
|
|
|
try
|
|
{
|
|
// add the row to the dataview
|
|
var trackQueryStatus = trackQuery;
|
|
UiInvoke(() => _trackQueryStatuses.Add(trackQueryStatus));
|
|
|
|
// scroll the row if it's at the bottom
|
|
UiInvoke(
|
|
() =>
|
|
{
|
|
if (logDataGridView.RowCount > 2
|
|
&& logDataGridView.Rows[logDataGridView.RowCount - 2].Displayed)
|
|
{
|
|
logDataGridView.FirstDisplayedScrollingRowIndex = logDataGridView.RowCount - 1;
|
|
}
|
|
});
|
|
|
|
// run the track query
|
|
var track = SearchTrack(trackQuery);
|
|
|
|
if (_cancellationTokenSource.IsCancellationRequested)
|
|
break;
|
|
|
|
// no results, continue on to the next track
|
|
if (track == null)
|
|
{
|
|
trackQuery.Status = "Track not found";
|
|
continue;
|
|
}
|
|
|
|
// check that this is not a compilation track
|
|
if (_options.LibraryUpdate.FindCompilationTrackOrigins)
|
|
{
|
|
track = _trackOriginalRelease.
|
|
GetTrackOriginalRelease(track) ?? track;
|
|
}
|
|
|
|
UpdateTrack(trackQuery, track);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex.ToString());
|
|
trackQuery.Status = ex.Message;
|
|
}
|
|
}
|
|
|
|
if (_cancellationTokenSource.IsCancellationRequested)
|
|
{
|
|
SetText("Cancel complete.");
|
|
_cancellationTokenSource = new CancellationTokenSource();
|
|
}
|
|
|
|
UiInvoke(
|
|
() =>
|
|
{
|
|
exitButton.Enabled = true;
|
|
cancelButton.Enabled = false;
|
|
cancelButton.Visible = false;
|
|
startButton.Enabled = true;
|
|
librarySelector.Enabled = true;
|
|
optionsButton.Enabled = true;
|
|
});
|
|
|
|
if (_exitClicked)
|
|
{
|
|
SetText("Exiting...");
|
|
UiInvoke(() => exitButton_Click(this, new EventArgs()));
|
|
}
|
|
}
|
|
|
|
private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
var a = new About();
|
|
a.ShowDialog(this);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IProgressCallback
|
|
|
|
public void Begin()
|
|
{
|
|
UiInvoke(() => toolStripProgressBar.Value = toolStripProgressBar.Minimum);
|
|
}
|
|
|
|
public void SetRange(int minimum, int maximum)
|
|
{
|
|
UiInvoke(() => toolStripProgressBar.Minimum = minimum);
|
|
UiInvoke(() => toolStripProgressBar.Maximum = maximum);
|
|
}
|
|
|
|
public void SetText(string text)
|
|
{
|
|
UiInvoke(() => toolStripStatusLabel.Text = text);
|
|
}
|
|
|
|
public void StepTo(int val)
|
|
{
|
|
UiInvoke(() => toolStripProgressBar.Value = val);
|
|
}
|
|
|
|
public void Increment(int val)
|
|
{
|
|
UiInvoke(() => toolStripProgressBar.Value += val);
|
|
}
|
|
|
|
public bool IsAborting
|
|
{
|
|
get { return _cancellationTokenSource.IsCancellationRequested; }
|
|
}
|
|
|
|
public void End()
|
|
{
|
|
StepTo(toolStripProgressBar.Maximum);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |