-
Notifications
You must be signed in to change notification settings - Fork 0
/
SynchronizationPlugin.cs
779 lines (666 loc) · 23.5 KB
/
SynchronizationPlugin.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
using iTunesLib;
using MusicBeeITunesSyncPlugin;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace MusicBeePlugin
{
public partial class Plugin
{
private const int TagCount = 23;
public static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
public static readonly AssemblyName AssemblyName = Assembly.GetName();
public static readonly PluginInfo Info = new PluginInfo
{
PluginInfoVersion = Plugin.PluginInfoVersion,
Name = Text.L("iTunes Sync"),
Description = Text.L("Synchronizes the iTunes application with MusicBee"),
Author = "ehowarth",
TargetApplication = "iTunes", // current only applies to artwork, lyrics or instant messenger name that appears in the provider drop down selector or target Instant Messenger
Type = Plugin.PluginType.Storage,
VersionMajor = (short)AssemblyName.Version.Major, // .net version
VersionMinor = (short)AssemblyName.Version.Minor, // plugin version
Revision = (short)AssemblyName.Version.Build, // number of days since 2000-01-01 at build time
MinInterfaceVersion = 28,
MinApiRevision = 32,
ReceiveNotifications = Plugin.ReceiveNotificationFlags.StartupOnly,
ConfigurationPanelHeight = 0, // height in pixels that musicbee should reserve in a panel for config settings. When set, a handle to an empty panel will be passed to the Configure function
};
public static MusicBeeApiInterface MbApiInterface;
private DeviceProperties Device = new DeviceProperties
{
ShowCategoryNodes = true,
AudiobooksSupported = false,
PodcastsSupported = false,
VideoSupported = false,
SyncExternalArtwork = false,
SyncAllowFileRemoval = false, // This plugin always removes non-sync-ed files from iTunes. It doesn't ask for permission.
SyncAllowRating2Way = false, // This plugin always syncs plays from iTunes. It doesn't ask for permission.
SyncAllowPlayCount2Way = false, // This plugin always syncs plays from iTunes. It doesn't ask for permission.
SyncAllowPlaylists2Way = false,
SupportedFormats =
SynchronisationSupportedFormats.SyncMp3Supported |
SynchronisationSupportedFormats.SyncAacSupported |
SynchronisationSupportedFormats.SyncAlacSupported |
SynchronisationSupportedFormats.SyncWavSupported,
DeviceIcon64 = (Bitmap)MusicBeeITunesSyncPlugin.Properties.Resources.ResourceManager.GetObject("iTunes64"),
};
private bool uninstalled = false;
private Form MbForm;
private ToolStripItem OpenMenu;
private string ReencodedFilesStorage;
private bool? ReadyForSync = false;
private iTunesApp iTunes;
private Exception lastEx = null;
private bool SynchronizationInProgress = false;
private bool AbortSynchronization = false;
private readonly Dictionary<string, long> SelectedPlaylistLocationsToPersistentIds = new Dictionary<string, long>();
/// <summary>
/// Called by MusicBee whenever it is loading the plugin whether at startup or when enabling the plugin.
/// The pointer parameter should be copied to a <c>MusicBeeApiInterface</c> structure.
/// </summary>
/// <param name="apiInterfacePtr">Pointer to a <c>MusicBeeApiInterface</c> object</param>
/// <returns></returns>
public PluginInfo Initialise(IntPtr apiInterfacePtr)
{
MbApiInterface = new MusicBeeApiInterface();
MbApiInterface.Initialise(apiInterfacePtr);
ReencodedFilesStorage = MbApiInterface.Setting_GetPersistentStoragePath() + "iTunesSync";
if (!Directory.Exists(ReencodedFilesStorage))
{
Directory.CreateDirectory(ReencodedFilesStorage);
}
MbForm = (Form)Form.FromHandle(MbApiInterface.MB_GetWindowHandle());
OpenMenu = MbApiInterface.MB_AddMenuItem(
"mnuTools/" + Text.L("Open iTunes Sync"),
Text.L("Opens iTunes to begin sync"),
ToggleItunesOpenedAndClosed);
return Info;
}
private void ToggleItunesOpenedAndClosed(object sender, EventArgs e)
{
while (ReadyForSync == null) ; // Wait if already being toggled open
if (ReadyForSync == false)
{
Backgrounding.RunInBackground(StartITunes);
}
OpenMenu.Enabled = false;
}
// save any persistent settings in a sub-folder of this path
// string dataPath = mbApiInterface.Setting_GetPersistentStoragePath();
// panelHandle will only be set if you set about.ConfigurationPanelHeight to a non-zero value
// keep in mind the panel width is scaled according to the font the user has selected
// if about.ConfigurationPanelHeight is set to 0, you can display your own popup window
public bool Configure(IntPtr panelHandle)
{
var choice = MessageBox.Show(
MbForm,
Text.L("Clear All Sync Data?"),
Info.Name + ' ' + AssemblyName.Version,
MessageBoxButtons.YesNo
);
if (choice == DialogResult.Yes)
{
RemoveSyncTagsFrommAllLibraryFiles();
DeleteAllReencodedFiles();
}
return true;
}
private static void RemoveSyncTagsFrommAllLibraryFiles()
{
foreach (var file in MusicBeeFile.AllFiles())
{
file.ClearPluginTags();
}
}
private void DeleteAllReencodedFiles()
{
if (!Directory.Exists(ReencodedFilesStorage))
{
Directory.Delete(ReencodedFilesStorage, true);
Directory.CreateDirectory(ReencodedFilesStorage);
}
}
// called by MusicBee when the user clicks Apply or Save in the MusicBee Preferences screen.
// its up to you to figure out whether anything has changed and needs updating
public void SaveSettings()
{
}
// MusicBee is closing the plugin (plugin is being disabled by user or MusicBee is shutting down)
public void Close(PluginCloseReason reason)
{
Eject();
}
// uninstall this plugin - clean up any persisted files
public void Uninstall()
{
Eject();
OpenMenu.Visible = false;
RemoveSyncTagsFrommAllLibraryFiles();
if (Directory.Exists(ReencodedFilesStorage))
Directory.Delete(ReencodedFilesStorage, true);
uninstalled = true;
}
// receive event notifications from MusicBee
// you need to set about.ReceiveNotificationFlags = PlayerEvents to receive all notifications, and not just the startup event
public void ReceiveNotification(string sourceFileUrl, NotificationType type)
{
// perform some action depending on the notification type
switch (type)
{
case NotificationType.PluginStartup:
// perform startup initialisation
break;
}
}
/// <summary>
/// Called by MusicBee in response to <c>MB_SendNotification(Plugin.CallbackType.StorageReady)</c>
/// </summary>
/// <param name="handle">Pointer to buffer in which to copy a <c>DeviceProperties</c> object</param>
/// <returns></returns>
public bool GetDeviceProperties(IntPtr handle)
{
Marshal.StructureToPtr(Device, handle, false);
Trace.WriteLine("Reporting device \"" + Device.DeviceName + "\" to MusicBee");
return true;
}
// flags has bit indicators whether 2 way rating and/or playcount is requested (only set if enabled in the device properties)
// for files():
// Key - the SynchronisationCategory the file should be sychronised to if appropriate for the device
// Value is 3 strings
// (0) - source file or playlist to be synchronised - use to query MusicBee for file tags, or files in a playlist
// (1) - the filename extension of the file to be synchronised - normally the same as the extension for (0) but if the file would need to be re-encoded to meet the user's synch preferences then the extension for the encoded file
// (2) - if SyncOrganisedFolders is enabled, filename as formatted by a naming template otherwise null
// for each file that is synchronised, call Sync_FileStart(filename(0))
// MusicBee will determine if the file needs to be re-encoded depending on the user synch settings and if so the returned filename will be the temporary encoded filename
// call Sync_FileEnd(filename(0), success, errorMessage) when that file has been synched or not
// return true if all files synchronised ok
public bool Synchronise(SynchronisationSettings flags, KeyValuePair<int, string[]>[] syncItems)
{
while (ReadyForSync == null) ; // Wait if still opening iTunes
try
{
if (SynchronizationInProgress)
{
lastEx = null;
return false;
}
SynchronizationInProgress = true;
var playlistKeys = new Dictionary<long, string>();
var trackKeys = new Dictionary<long, MusicBeeFile>();
foreach (var item in syncItems)
{
if (AbortSynchronization)
{
SynchronizationInProgress = false;
AbortSynchronization = false;
lastEx = null;
return true;
}
if (item.Key == (int)SynchronisationCategory.Playlist)
{
// Create or verify playlist. Populate after all files have been processed.
var name = Regex.Replace(item.Value[0], "^.*\\\\(.*)(\\..*)", "$1");
var playlist = iTunes.GetPlaylist(name) ?? iTunes.CreatePlaylist(name);
var key = iTunes.GetPersistentId(playlist);
Marshal.ReleaseComObject(playlist);
playlistKeys[key] = item.Value[0];
}
else
{
// item.Value[0] is the URL to a MusicBee file to be sync'ed
// item.Value[1] is the extension of the file
// indicate to MusicBee that you want to synch the file
// the returned filename is either the same as the supplied filename or
// if re-encoding/forced embedding artwork, a temporary filename is returned
var filename = Plugin.MbApiInterface.Sync_FileStart(item.Value[0]);
// if filename is returned as null, that means MusicBee wasnt able to encode the file and it should be skipped from synchronisation
if (filename == null) continue;
bool success = false;
string errorMessage = null;
try
{
var mbFile = new MusicBeeFile(item.Value[0]);
IITTrack itTrack = null;
string itTrackPath = null;
if (mbFile.WebFile)
{
itTrackPath = mbFile.Url;
}
else if (!File.Exists(filename))
{
throw new IOException(Text.L("Track source file not found: {0}", filename));
}
else if (mbFile.Url == filename)
{
itTrackPath = filename;
}
else
{
// Track was converted to a format that iTunes accepts...
// Create a unique name for the converted file and store it in the MB file record
var trackGUID = mbFile.ReencodingFileName;
if (string.IsNullOrEmpty(trackGUID))
{
trackGUID = Guid.NewGuid().ToString();
mbFile.ReencodingFileName = trackGUID;
mbFile.CommitChanges();
}
itTrackPath = Path.Combine(ReencodedFilesStorage, trackGUID + item.Value[1]);
File.Copy(filename, itTrackPath, true);
}
var itKey = mbFile.ITunesKey;
// Track was synced before
if (itKey != 0)
{
itTrack = iTunes.GetTrackByPersistentId(itKey);
if (itTrack == null)
{
Trace.WriteLine("A file in MusicBee appears to have been sync'ed to iTunes before but is not found in iTunes: " + mbFile.Url);
itKey = 0;
}
else if (!mbFile.WebFile)
{
//Local or local network file
((IITFileOrCDTrack)itTrack).UpdateInfoFromFile();
}
}
// Track was never synced before or was deleted from iTunes library
if (itTrack == null)
{
if (mbFile.WebFile)
{
itTrack = iTunes.LibraryPlaylist.AddURL(itTrackPath);
}
else
{
var operation = iTunes.LibraryPlaylist.AddFile(itTrackPath).Await();
var tracks = operation.Tracks;
itTrack = tracks[1];
Marshal.ReleaseComObject(tracks);
Marshal.ReleaseComObject(operation);
itKey = iTunes.GetPersistentId(itTrack);
mbFile.ITunesKey = itKey;
mbFile.CommitChanges();
}
}
// Sync ratings & play counts to iTunes
itTrack.SyncMusicBeeHistoryToITunes(mbFile);
mbFile.SyncFileTimestamp(itTrackPath);
Marshal.ReleaseComObject(itTrack);
trackKeys[itKey] = mbFile;
success = true;
errorMessage = null;
}
catch (Exception ex)
{
Trace.WriteLine(ex);
lastEx = ex;
if (errorMessage == null)
errorMessage = ex.Message;
}
finally
{
Plugin.MbApiInterface.Sync_FileEnd(item.Value[0], success, errorMessage);
}
}
}
// Remove non-sync'ed tracks
foreach (var track in iTunes.GetAllTracks())
{
var key = iTunes.GetPersistentId(track);
if (!trackKeys.ContainsKey(key))
{
Plugin.MbApiInterface.MB_SetBackgroundTaskMessage(Text.L("Removing track: \"{0}\"", track.Name));
track.Delete();
}
Marshal.ReleaseComObject(track);
}
// Remove non-sync'ed playlists and populate the remaining ones
foreach (var playlist in iTunes.GetPlaylists())
{
var key = iTunes.GetPersistentId(playlist);
if (playlistKeys.ContainsKey(key))
{
Plugin.MbApiInterface.MB_SetBackgroundTaskMessage(Text.L("Clearing playlist: \"{0}\"", playlist.Name));
playlist.DeleteAllTracks();
var m = 0;
var playlistFiles = MusicBeeFile.GetPlaylistFiles(playlistKeys[key]).ToArray();
foreach (var playlistFile in playlistFiles)
{
m++;
Plugin.MbApiInterface.MB_SetBackgroundTaskMessage(Text.L("Adding track {0} of {1} to playlist: \"{2}\"", m, playlistFiles.Length, playlist.Name));
iTunes.AddTrackToPlaylistByPersistentId(playlist, playlistFile.ITunesKey);
}
}
else
{
Plugin.MbApiInterface.MB_SetBackgroundTaskMessage(Text.L("Removing playlist: \"{0}\"", playlist.Name));
playlist.Delete();
}
Marshal.ReleaseComObject(playlist);
}
return lastEx == null;
}
catch (Exception ex)
{
Trace.WriteLine(ex);
MbApiInterface.MB_SendNotification(CallbackType.StorageFailed);
lastEx = ex;
return false;
}
finally
{
Plugin.MbApiInterface.MB_SetBackgroundTaskMessage("");
SynchronizationInProgress = false;
}
}
// called when user has requested the synchronisation aborts
public void SynchroniseAbort()
{
AbortSynchronization = true;
}
// called when user has requested the device be ejected
public bool Eject()
{
CloseITunes();
if (!uninstalled)
SaveSettings();
Trace.Flush();
return true;
}
public void Refresh()
{
// TODO: what to refresh
}
public Bitmap GetIcon()
{
return (Bitmap)MusicBeeITunesSyncPlugin.Properties.Resources.ResourceManager.GetObject("iTunes");
}
public bool IsReady()
{
return ReadyForSync == true;
}
private void StartITunes()
{
try
{
ReadyForSync = null;
Plugin.MbApiInterface.MB_SetBackgroundTaskMessage(Text.L("Starting iTunes..."));
iTunes = new iTunesApp();
#if !DEBUG
iTunes.BrowserWindow.Minimized = true;
#endif
iTunes.ForceToForegroundOnDialog = true;
Device.DeviceName = Text.L("iTunes");
Device.FirmwareVersion = iTunes.Version;
Device.Model = "";
Device.Manufacturer = "Apple Inc.";
Device.FreeSpace = 0;
Device.TotalSpace = 0;
// Tell MusicBee to add an item to the Devices panel for this.
// Music Bee calls GetDeviceProperties for details
Plugin.MbApiInterface.MB_SendNotification(Plugin.CallbackType.StorageReady);
// Sync play history and ratings from iTunes right now.
// Cannot wait for the Synchronize command from MB before collecting ratings and history
// because this data may affect the file list passed to Synchronize.
// if (flags.HasFlag(Plugin.SynchronisationSettings.SyncPlayCount2Way) || flags.HasFlag(Plugin.SynchronisationSettings.SyncRating2Way))
SyncITunesHistoryToMusicBee();
ReadyForSync = true;
}
catch (Exception ex)
{
Trace.WriteLine(ex);
lastEx = ex;
MessageBox.Show(ex.Message);
ReadyForSync = false;
CloseITunes();
}
finally
{
Plugin.MbApiInterface.MB_SetBackgroundTaskMessage("");
}
}
private void SyncITunesHistoryToMusicBee()
{
try
{
Plugin.MbApiInterface.MB_SetBackgroundTaskMessage(Text.L("Syncing play counts and ratings from iTunes..."));
foreach (var track in iTunes.GetAllTracks())
{
Plugin.MbApiInterface.MB_SetBackgroundTaskMessage(Text.L("Syncing play counts and ratings from iTunes: \"{0}\"", track.Name));
var file = new MusicBeeFile(track.Location);
if (file.Exists)
{
track.SyncITunesHistoryToMusicBee(file);
}
Marshal.ReleaseComObject(track);
}
}
finally
{
Plugin.MbApiInterface.MB_SetBackgroundTaskMessage("");
}
}
private void CloseITunes()
{
while (ReadyForSync == null) ; // Wait if still opening iTunes before trying to close
ReadyForSync = false;
if (Device.DeviceName != null)
{
Device.DeviceName = null;
// Tell MusicBee to call Eject()
Plugin.MbApiInterface.MB_SendNotification(Plugin.CallbackType.StorageEject);
}
if (iTunes != null)
{
try
{
iTunes.Quit();
}
catch (Exception x)
{
Trace.WriteLine(x);
}
Marshal.ReleaseComObject(iTunes);
iTunes = null;
}
OpenMenu.Enabled = true;
}
public bool FolderExists(string path)
{
return (string.IsNullOrEmpty(path) || path == @"\");
}
public string[] GetFolders(string path)
{
string[] folders;
folders = new string[1];
folders[0] = "";
return folders;
}
public KeyValuePair<string, string>[] GetPlaylists()
{
return iTunes.GetPlaylists().Select(playlist =>
{
try
{
return new KeyValuePair<string, string>(playlist.Name, playlist.Name);
}
finally
{
Marshal.ReleaseComObject(playlist);
}
}).ToArray();
}
private KeyValuePair<byte, string>[][] GetPlaylistTracks(IITPlaylist playlist)
{
var files = new List<KeyValuePair<byte, string>[]>();
SelectedPlaylistLocationsToPersistentIds.Clear();
foreach (IITTrack currTrack in playlist.Tracks)
{
if (currTrack.Kind == ITTrackKind.ITTrackKindFile)
{
var fileTrack = (IITFileOrCDTrack)currTrack;
if (fileTrack.Location != null)
{
SelectedPlaylistLocationsToPersistentIds.Add(fileTrack.Location, iTunes.GetPersistentId(fileTrack));
files.Add(fileTrack.ToMusicBeeFileProperties());
}
}
Marshal.ReleaseComObject(currTrack);
}
return files.ToArray();
}
public KeyValuePair<byte, string>[][] GetPlaylistFiles(string id)
{
var playlistFiles = new List<KeyValuePair<byte, string>[]>();
var libraryPlaylist = iTunes.GetPlaylist(id);
if (libraryPlaylist == null)
{
var file = new KeyValuePair<byte, string>[TagCount];
playlistFiles.Add(file);
return playlistFiles.ToArray();
}
SelectedPlaylistLocationsToPersistentIds.Clear();
foreach (IITTrack currTrack in libraryPlaylist.Tracks)
{
if (currTrack.Kind == ITTrackKind.ITTrackKindFile)
{
IITFileOrCDTrack fileTrack = (IITFileOrCDTrack)currTrack;
SelectedPlaylistLocationsToPersistentIds.Add(fileTrack.Location, iTunes.GetPersistentId(fileTrack));
playlistFiles.Add(fileTrack.ToMusicBeeFileProperties());
}
Marshal.ReleaseComObject(currTrack);
}
Marshal.ReleaseComObject(libraryPlaylist);
return playlistFiles.ToArray();
}
public KeyValuePair<byte, string>[][] GetFiles(string path)
{
lastEx = null;
KeyValuePair<byte, string>[][] files = null;
if (ReadyForSync != true)
{
files = new KeyValuePair<byte, string>[0][];
}
else
{
files = GetPlaylistTracks(iTunes.LibraryPlaylist);
}
return files;
}
public bool FileExists(string url)
{
long ids = 0;
if (SelectedPlaylistLocationsToPersistentIds.TryGetValue(url, out ids))
{
var foundTrack = iTunes.GetTrackByPersistentId(ids);
if (foundTrack != null)
{
Marshal.ReleaseComObject(foundTrack);
return true;
}
}
return false;
}
public KeyValuePair<byte, string>[] GetFile(string url)
{
long ids = 0;
if (SelectedPlaylistLocationsToPersistentIds.TryGetValue(url, out ids))
{
var foundTrack = iTunes.GetTrackByPersistentId(ids);
if (foundTrack != null)
{
try
{
if (foundTrack.Kind == ITTrackKind.ITTrackKindFile)
{
return ((IITFileOrCDTrack)foundTrack).ToMusicBeeFileProperties();
}
}
finally
{
Marshal.ReleaseComObject(foundTrack);
}
}
}
return new KeyValuePair<byte, string>[TagCount];
}
// return an array of lyric or artwork provider names this plugin supports
// the providers will be iterated through one by one and passed to the RetrieveLyrics/ RetrieveArtwork function in order set by the user in the MusicBee Tags(2) preferences screen until a match is found
public string[] GetProviders()
{
return null;
}
// return lyrics for the requested artist/title from the requested provider
// only required if PluginType = LyricsRetrieval
// return null if no lyrics are found
public string RetrieveLyrics(string sourceFileUrl, string artist, string trackTitle, string album, bool synchronisedPreferred, string provider)
{
return null;
}
// return Base64 string representation of the artwork binary data from the requested provider
// only required if PluginType = ArtworkRetrieval
// return null if no artwork is found
public string RetrieveArtwork(string sourceFileUrl, string albumArtist, string album, string provider)
{
//Return Convert.ToBase64String(artworkBinaryData)
return null;
}
public byte[] GetFileArtwork(string url)
{
lastEx = null;
try
{
long ids = 0;
if (SelectedPlaylistLocationsToPersistentIds.TryGetValue(url, out ids))
{
var foundTrack = iTunes.GetTrackByPersistentId(ids);
if (foundTrack != null && foundTrack.Kind == ITTrackKind.ITTrackKindFile)
{
IITFileOrCDTrack fileTrack = (IITFileOrCDTrack)foundTrack;
if (fileTrack.Location == url)
{
if (fileTrack.Artwork.Count == 0)
{
return null;
}
else
{
fileTrack.Artwork[1].SaveArtworkToFile(Plugin.MbApiInterface.Setting_GetPersistentStoragePath() + "iPod & iPhone Driver.jpg");
Bitmap artwork = new Bitmap(Plugin.MbApiInterface.Setting_GetPersistentStoragePath() + "iPod & iPhone Driver.jpg");
TypeConverter tc = TypeDescriptor.GetConverter(typeof(Bitmap));
byte[] artworkBytes = (byte[])tc.ConvertTo(artwork, typeof(byte[]));
artwork.Dispose();
artwork = null;
return artworkBytes;
}
}
}
}
}
catch (Exception ex)
{
Trace.WriteLine(ex);
lastEx = ex;
}
return null;
}
public Stream GetStream(string url)
{
return new FileStream(url, FileMode.Open);
}
public Exception GetError()
{
return lastEx;
}
}
}