/// <summary>
 /// Method for dispatching device connected events.
 /// </summary>
 /// <param name="drive">The drive where the device is connected.</param>
 /// <param name="device">Info on the connected device.</param>
 protected void OnDeviceConnected(DriveInfo drive, Device device)
 {
     if (DeviceConnected != null)
     {
         CDMEventArgs args = new CDMEventArgs(drive, device);
         DeviceConnected(this, args);
     }
 }
예제 #2
0
        /// <summary>
        /// Checks if an iTunes playlist exists.
        /// </summary>
        /// <param name="device">Device to check playlist for.</param>
        /// <returns>The playlist if it exists, null otherwise.</returns>
        private List<IITPlaylist> PlaylistExists(Device device)
        {

            string playlistDelimString = (device.Playlist == null || device.Playlist.Length == 0) ? device.Name : device.Playlist;

            List<string> aplList = new List<string>(playlistDelimString.Split('|'));
            List<IITPlaylist> aplIIT = new List<IITPlaylist>();

            bool retry = true;
            while (retry)
            {
                try
                {
                    for (int i = 0; i < aplList.Count; i++)
                    {
                        foreach (IITPlaylist playlist in itunes.LibrarySource.Playlists)
                        {
                            if (playlist.Name == aplList[i])
                            {
                                aplIIT.Add(playlist);
                                break;
                            }
                        }
                    }

                    return aplIIT;
                }
                catch (Exception comex)
                {
                    l.Warn(comex);

                    if (MessageBox.Show("Failed to get playlists from iTunes. This is most likely due to iTunes being busy or an open dialog. Do you want to try again?\n\n(" + comex.Message + ")", "Communication error", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
                    {
                        retry = true;
                    }
                    else
                    {
                        retry = false;
                    }

                    continue;
                }
            }

            return null;
        }
예제 #3
0
 /// <summary>
 /// Remove a Device.
 /// </summary>
 /// <param name="d">Device to remove.</param>
 /// <returns></returns>
 public bool RemoveDevice(Device d)
 {
     return devices.Remove(d);
 }
예제 #4
0
 /// <summary>
 /// Add a device.
 /// </summary>
 /// <param name="d">Device to add.</param>
 public void AddDevice(Device d)
 {
     devices.Add(d);
 }
예제 #5
0
        /// <summary>
        /// Event handler for the save button.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonSave_Click(object sender, EventArgs e)
        {
            string deviceName = textDeviceName.Text;
            string syncPattern = (string)comboSyncPatterns.SelectedItem;
            string mediaroot = textMediaRoot.Text;
            string recognizePattern = textRecognizePattern.Text;
            string associatedPlaylist = (string)comboAssociatePlaylist.SelectedItem;

            if (deviceName.Length == 0)
            {
                MessageBox.Show(this, "Please enter a name for the device.", "Missing information", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            if (syncPattern == null)
            {
                MessageBox.Show(this, "Please select a synchronize pattern for the device.", "Missing information", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            if (recognizePattern.Length == 0)
            {
                MessageBox.Show(this, "Please enter a recognize pattern for the device.", "Missing information", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            Device newDevice = new Device();
            newDevice.Name = deviceName;
            newDevice.MediaRoot = mediaroot;
            newDevice.RecognizePattern = recognizePattern;
            newDevice.Playlist = (associatedPlaylist == "Use device name..." ? "" : associatedPlaylist);
            foreach (SyncPattern sp in deviceConfiguration.SyncPatterns)
            {
                if (sp.Name != syncPattern)
                    continue;

                newDevice.SyncPattern = sp.Identifier;
            }

            //Add new device
            if (textDeviceName.Enabled)
            {
                //Check that the name does not already exist
                foreach (Device device in deviceConfiguration.Devices)
                {
                    if (device.Name != deviceName)
                        continue;

                    MessageBox.Show(this, "There is already a device configuration with the name '" + deviceName + "'. Please enter a unique name.", "Missing information", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }

                deviceConfiguration.AddDevice(newDevice);
                listDevices.Items.Add(newDevice.Name);
            }
            //Update existing device
            else
            {
                foreach (Device device in deviceConfiguration.Devices)
                {
                    if (device.Name != newDevice.Name)
                        continue;

                    device.MediaRoot = newDevice.MediaRoot;
                    device.RecognizePattern = newDevice.RecognizePattern;
                    device.SyncPattern = newDevice.SyncPattern;
                    device.Playlist = newDevice.Playlist;

                    break;
                }
            }

            deviceConfigurationChanged = true;
            SaveDeviceConfiguration();

            PrepareForNewDeviceConfiguration();
            DisableEditFields();

            MessageBox.Show(this, "New device configuration registered successfully.", "New device configuration", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
예제 #6
0
        /// <summary>
        /// <see cref="Notpod.ISynchronizer#SynchronizeDevice(IITUserPlaylist, string, Device)"/>
        /// </summary>
        public void SynchronizeDevice(IITUserPlaylist playlist, string drive, Device device)
        {
            //Check that configuration has been set.
            if (configuration == null)
                throw new SynchronizeException("Configuration has not been set.");

            DirectoryInfo di = new DirectoryInfo(drive + device.MediaRoot);

            // Check if the media root directory actually exists 
            // Thanks to Robert Grabowski for the contribution.
            try
            {
                if (!di.Exists)
                    di.Create();
            }
            catch (IOException ex)
            {
                string message = "Could not create directory '"
                    + di.Name + "' for device '" + device.Name
                    + "'. Unable to complete synchronization.";
                l.Error(message, ex);

                syncForm.AddLogText(message, Color.Red);
            }

            // Perform a write check to make sure Notpod has write 
            // access to the music folder of the device.
            String writeCheckPath = drive + device.MediaRoot + "\\wrtchk.ita";
            try
            {
                FileStream writeCheckStream = File.Create(writeCheckPath);
                writeCheckStream.Close();
                File.Delete(writeCheckPath);
            }
            catch (Exception e)
            {
                l.Error("Could not write " + writeCheckPath + ".", e);

                String message = "Error: I am unable to write to the music folder of "
                    + "your device. Please make sure I have the proper permissions"
                    + " and try again.";

                syncForm.AddLogText(message, Color.Red);
                return;
            }

            FileInfo[] files = FileHelper.GetFilesRecursive(di.ToString()).ToArray();

            //Find correct synchronize pattern for the device.
            SyncPattern devicePattern = null;
            foreach (SyncPattern sp in configuration.SyncPatterns)
            {
                if (sp.Identifier == device.SyncPattern)
                    devicePattern = sp;
            }

            //Throw an exception if the pattern could not be found.
            if (devicePattern == null)
            {
                OnSynchronizeError(device, "Illegal synchronize pattern '" + device.SyncPattern + "' for device '" + device.Name + "'. Unable to complete synchronization.");
                return;
            }

            syncForm.AddLogText("Synchronizing '" + device.Name + "'...");
            syncForm.SetDeviceName(device.Name, drive);

            syncForm.SetCurrentStatus("Initializing...");
            syncForm.SetMaxProgressValue(playlist.Tracks.Count);
            syncForm.SetProgressValue(0);


            // maintain a filename -> track object dictionary for the tracks to be copied onto the device           
            // Thanks to Robert Grabowski for the contribution.
            Dictionary<string, IITFileOrCDTrack> syncList = new Dictionary<string, IITFileOrCDTrack>();

            string deviceMediaRoot = drive + (device.MediaRoot.Length > 0 ? device.MediaRoot + "\\" : "");

            try
            {
                foreach (IITTrack track in playlist.Tracks)
                {
                    if (syncForm.GetOperationCancelled())
                    {
                        syncForm.SetCurrentStatus("Synchronization cancelled. 0 tracks added, 0 tracks removed.");
                        syncForm.AddLogText("Synchronization cancelled.", Color.OrangeRed);
                        OnSynchronizeCancelled();
                        return;
                    }

                    syncForm.SetProgressValue(syncForm.GetProgressValue() + 1);

                    //Continue if the track is not of kind "file" or the track is one of the initial tracks on the device.
                    if (track.Kind != ITTrackKind.ITTrackKindFile || device.InitialTracks.Contains(track))
                        continue;


                    string pathOnDevice = "";

                    IITTrack addTrack = track;

                    try
                    {
                        pathOnDevice = SyncPatternTranslator.Translate(devicePattern, (IITFileOrCDTrack)addTrack);                        
                    }
                    catch (Exception ex)
                    {
                        syncForm.AddLogText("An error occured while working with \"" + track.Artist + " - " + track.Name
                            + "\". This may be because the track has been deleted from disk. Look for an exclamation mark"
                            + "next to the track in your playlist.", Color.Orange);
                        continue;
                    }
                    string fullPath = deviceMediaRoot + pathOnDevice;
                    l.Debug(fullPath);

                    // Check if the list already contains a key - this happens in cases where there are duplicate 
                    // entries in the playlist for the same track. Although the track may have different locations on 
                    // the user's computer, Notpod will not handle this.
                    if (syncList.ContainsKey(fullPath))
                    {
                        syncForm.AddLogText("You have duplicate listings for " + track.Artist + " - " + track.Name
                            + " in your playlist. I will continue for now, but you should remove any duplicates "
                            + "when the synchronization is complete.", Color.Orange);
                        continue;
                    }

                    syncList.Add(fullPath, (IITFileOrCDTrack)addTrack);
                }
            }
            catch (Exception ex)
            {
                syncForm.SetCurrentStatus("");
                String message = "Error occured while initializing: " + ex.Message;
                syncForm.AddLogText(message, Color.Red);
                syncForm.DisableCancelButton();
                syncForm.SetProgressValue(0);
                OnSynchronizeError(device, message);

                l.Error(message, ex);
                return;
            }
            syncForm.AddLogText("Initialization completed.");

            syncForm.SetCurrentStatus("Checking tracks. Removing those that are no longer in the playlist...");
            int totalTracks = files.Length;
            syncForm.SetMaxProgressValue(totalTracks);
            syncForm.SetProgressValue(0);

            int tracksRemoved = 0;
            int tracksAdded = 0;
            long existingSize = 0;

            try
            {
                //Remove tracks from device which are no longer in the playlist.
                foreach (FileInfo file in files)
                {
                    l.Debug("Checking file: " + file.FullName);

                    // Check for cancelled operation.
                    if (syncForm.GetOperationCancelled())
                    {
                        syncForm.SetCurrentStatus("Synchronization cancelled. " + tracksAdded
                            + " track(s) added, " + tracksRemoved + " track(s) removed.");
                        syncForm.AddLogText("Synchronization cancelled.", Color.OrangeRed);
                        OnSynchronizeCancelled();
                        return;
                    }

                    //Increase progress bar
                    syncForm.SetProgressValue(syncForm.GetProgressValue() + 1);

                    //Continue with next track if it is not of a supported extension.
                    //if (file.Extension != ".mp3" && file.Extension != ".acc" && file.Extension != ".m4p" && file.Extension != ".m4a")
                    if (!extensions.Contains(file.Extension))
                        continue;
                    
                    if (syncList.ContainsKey(file.FullName))
                    {
                        FileInfo fi = new FileInfo(file.FullName);
                        existingSize += fi.Length;
                        continue;
                    }

                    //If the track was not found --- delete it!
                    string fileFullName = file.FullName;
                    file.Delete();
                    
                    l.Debug("Removing file no longer in playlist: " + fileFullName);
                    
                    CheckAndRemoveFolders(fileFullName, drive, device);

                    tracksRemoved++;

                }

                syncForm.AddLogText(tracksRemoved + " track(s) was removed from the device.",
                    Color.Orange);
            }
            catch (MissingTrackException ex)
            {
                syncForm.SetCurrentStatus("");
                String message = "You have a missing file in your library. Please clean up "
                    + "your playlist and remove the track '" + ex.Track.Artist + " - "
                    + ex.Track.Name + "' before re-synchronizing.";
                syncForm.AddLogText(message, Color.Red);
                syncForm.DisableCancelButton();
                syncForm.SetProgressValue(0);
                OnSynchronizeError(device, message);

                l.Error(message, ex);

                return;
            }
            catch (Exception ex)
            {
                syncForm.SetCurrentStatus("");
                String message = "Error occured while checking for deleted tracks: " + ex.Message;
                syncForm.AddLogText(message, Color.Red);
                syncForm.DisableCancelButton();
                syncForm.SetProgressValue(0);
                OnSynchronizeError(device, message);

                l.Error(message, ex);
                return;
            }

            files = null;

            // Check free space on the device
            double playlistSize = playlist.Size;
            DriveInfo driveInfo = new DriveInfo(drive.Substring(0, 1));
            long freeOnDisk = driveInfo.AvailableFreeSpace;

            if (freeOnDisk < playlistSize - existingSize)
            {
                string message = "There is not enough space on your device to synchronize the playlist.";
                OnSynchronizeError(device, message);
                syncForm.AddLogText(message, Color.Red);
                syncForm.SetCurrentStatus(message);
                syncForm.DisableCancelButton();
                syncForm.SetProgressValue(0);
                return;
            }

            try
            {
                syncForm.SetCurrentStatus("Copying new files...");
                syncForm.AddLogText("Preparing to copy new files.", Color.Black);
                syncForm.SetMaxProgressValue(syncList.Count);
                syncForm.SetProgressValue(0);

                //Check for new track in the playlist which should be copied to the device
                // NEW foreach: traverse synchronization list instead of playlist
                // Thanks to Robert Grabowski.                
                foreach (string filePath in syncList.Keys)
                {
                    IITTrack track = syncList[filePath];

                    // Check for cancelled operation.
                    if (syncForm.GetOperationCancelled())
                    {
                        syncForm.SetCurrentStatus("Synchronization cancelled. " + tracksAdded
                            + " track(s) added, " + tracksRemoved + " track(s) removed.");
                        syncForm.AddLogText("Synchronization cancelled.", Color.OrangeRed);
                        syncForm.DisableCancelButton();
                        syncForm.SetProgressValue(0);
                        OnSynchronizeCancelled();
                        return;
                    }


                    //Increase progress bar
                    syncForm.SetProgressValue(syncForm.GetProgressValue() + 1);

                    string trackPath = filePath.Substring(deviceMediaRoot.Length); // hack: cut out media root
                    l.Debug("Checking for copy: " + filePath);

                    if (File.Exists(filePath))
                        continue;

                    try
                    {
                        CheckAndCreateFolders(trackPath, drive, device);
                        syncForm.SetCurrentStatus("Copying " + filePath
                            + " (" + syncForm.GetProgressValue() + "/" + syncForm.GetMaxProgressValue() + ")");
                                                
                        File.Copy(((IITFileOrCDTrack)track).Location, filePath, true);
                        File.SetAttributes(filePath, FileAttributes.Normal);


                        syncForm.AddLogText(filePath + " copied successfully.", Color.Green);

                        l.Debug("Copied: " + filePath);
                    }
                    catch (Exception ex)
                    {
                        String message = "Failed to copy " + filePath + ".\n-> " + ex.Message;
                        syncForm.AddLogText(message, Color.Red);
                        OnSynchronizeError(device, message);

                        l.Error(message, ex);

                        return;
                    }

                    tracksAdded++;

                }
            }
            catch (MissingTrackException ex)
            {
                syncForm.SetCurrentStatus("");
                String message = "You have a missing file in your library. Please remove the track '" + ex.Track.Artist + " - " + ex.Track.Name + "' and try again. I am sorry for the inconvenience.";
                syncForm.AddLogText(message, Color.Red);
                syncForm.DisableCancelButton();
                syncForm.SetProgressValue(0);
                OnSynchronizeError(device, message);

                l.Error(message, ex);

                return;
            }
            catch (Exception ex)
            {
                string message = "An error occured while copying new tracks: " + ex.Message;
                syncForm.SetCurrentStatus("");
                syncForm.AddLogText(message,
                    Color.Red);
                syncForm.DisableCancelButton();
                syncForm.SetProgressValue(0);
                OnSynchronizeError(device, message);

                l.Error(message, ex);

                return;
            }

            syncForm.SetCurrentStatus("Synchronization completed. " + tracksAdded
                + " track(s) added, " + tracksRemoved + " track(s) removed.");
            syncForm.AddLogText("Completed. " + tracksAdded + " track(s) copied to your device.", Color.Green);
            syncForm.DisableCancelButton();
            OnSynchronizeComplete();

        }
예제 #7
0
        /// <summary>
        /// Event dispatcher for SynchronizeError events.
        /// </summary>
        /// <param name="device">The device that failed.</param>
        /// <param name="message">An error message.</param>
        protected void OnSynchronizeError(Device device, string message)
        {
            if (SynchronizeError != null)
            {
                SyncErrorArgs args = new SyncErrorArgs();
                args.Device = device;
                args.ErrorMessage = message;

                SynchronizeError(this, args);
            }
        }
예제 #8
0
        /// <summary>
        /// Check if the folder for the current artist/album is empty. If it is, then remove it.
        /// </summary>
        /// <param name="trackPath"></param>
        /// <param name="drive"></param>
        /// <param name="device"></param>
        private void CheckAndRemoveFolders(string trackPath, string drive, Device device)
        {
            if (device.MediaRoot.Length == 0)
                trackPath = trackPath.Replace(drive, "");
            else
                trackPath = trackPath.Replace(drive + device.MediaRoot + "\\", "");

            string[] folders = trackPath.Split('\\');
            string directoryPath = drive + device.MediaRoot;
            for (int f = folders.Length - 2; f >= 0; f--)
            {
                string parents = "";
                for (int pf = 0; pf < f; pf++)
                    parents += "\\" + folders[pf];

                string dirToDelete = directoryPath + parents + "\\" + folders[f];
                try
                {
                    DirectoryInfo di = new DirectoryInfo(dirToDelete);
                    if (di.GetFiles().Length == 0 && di.GetDirectories().Length == 0)
                        di.Delete();
                }
                catch (Exception ex)
                {
                    l.Error(ex);
                    throw new SynchronizeException("Unable to delete empty folder on device.", ex);
                }
            }
        }
예제 #9
0
        /// <summary>
        /// Check if the necessary folders for the given track exists. If not, create them.
        /// </summary>
        /// <param name="trackPath">The path of the track, relative to the device media root.</param>
        /// <param name="drive">The drive where the device is located.</param>
        /// <param name="device">Device information.</param>
        private void CheckAndCreateFolders(string trackPath, string drive, Device device)
        {
            string[] folders = trackPath.Split('\\');
            string directoryPath = drive + device.MediaRoot;
            for (int f = 0; f < folders.Length - 1; f++)
            {
                string folder = folders[f];
                directoryPath += "\\" + folder;
                if (Directory.Exists(directoryPath))
                    continue;

                l.Debug("Creating folder " + directoryPath);

                Directory.CreateDirectory(directoryPath);

            }

        }
예제 #10
0
        /// <summary>
        /// Checks if an iTunes playlist exists.
        /// </summary>
        /// <param name="device">Device to check playlist for.</param>
        /// <returns>The playlist if it exists, null otherwise.</returns>
        private IITPlaylist PlaylistExists(Device device)
        {

            string name = (device.Playlist == null || device.Playlist.Length == 0) ? device.Name : device.Playlist;

            bool retry = true;
            while (retry)
            {
                try
                {

                    foreach (IITPlaylist playlist in itunes.LibrarySource.Playlists)
                    {
                        if (playlist.Name == name)
                            return playlist;
                    }

                    return null;
                }
                catch (Exception comex)
                {
                    l.Warn(comex);

                    if (MessageBox.Show("Failed to get playlists from iTunes. This is most likely due to iTunes being busy or an open dialog. Do you want to try again?\n\n(" + comex.Message + ")", "Communication error", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
                    {
                        retry = true;
                    }
                    else
                    {
                        retry = false;
                    }

                    continue;
                }
            }

            return null;
        }
 /// <summary>
 /// Method for sending out device disconnected events.
 /// </summary>
 /// <param name="driveName">The name of the drive where the device was located.</param>
 /// <param name="device">Device object describing the device that was disconnected.</param>
 protected void OnDeviceDisconnected(string driveName, Device device)
 {
     if (DeviceDisconnected != null)
     {
         CDMEventArgs args = new CDMEventArgs(null, device);
         DeviceDisconnected(this, driveName, args);
     }
 }