private static void RemoveSyncTagsFrommAllLibraryFiles()
 {
     foreach (var file in MusicBeeFile.AllFiles())
     {
         file.ClearPluginTags();
     }
 }
        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("");
            }
        }
        // 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;
            }
        }