Files

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
}
}