private void GetAllFiles(MountedDevice device, string subPath, AudioFile[] allAudioFiles, List <string> newFiles, List <string> existingFiles)
        {
            // Probe all subdirectories
            string path = device.MountPath + subPath;

            string[] directories = null;
            try
            {
                directories = Directory.GetDirectories(path);
                foreach (string directory in directories)
                {
                    try
                    {
                        GetAllFiles(device, subPath + (subPath.EndsWith("/") ? null : "/") + Path.GetFileName(directory), allAudioFiles, newFiles, existingFiles);
                    }
                    catch
                    {
                    }
                }


                string[] mp3files = Directory.GetFiles(path, "*.mp3");
                if (mp3files.Length < 1)
                {
                    return;
                }
                foreach (string file in mp3files)
                {
                    string relativePath = Path.Combine(subPath, Path.GetFileName(file));
                    if (allAudioFiles.Any(audioFile => audioFile.RelativePath == relativePath))
                    {
                        existingFiles.Add(relativePath);
                    }
                    else
                    {
                        newFiles.Add(relativePath);
                    }
                }
            }
            catch
            {
            }
        }
Example #2
0
 /// <summary>
 /// Creates a new instance fo this class.
 /// </summary>
 /// <param name='device'>
 /// The device that these event arguments represent.
 /// </param>
 public MountedDeviceEventArgs(MountedDevice device)
 {
     Device = device;
 }
        private void ProcessFileList(MountedDevice device, List <string> mp3Files, AudioFile[] allAudioFiles)
        {
            // Create a new notification object if required
            AudioLibraryUpdateNotification notification = new AudioLibraryUpdateNotification();

            // Now probe each file within this directory
            try
            {
                foreach (string relativePath in mp3Files)
                {
                    string file = Path.Combine(device.MountPath + relativePath);
                    if (!File.Exists(file))
                    {
                        Logger.Error("File no longer exists when probing mounted file " + file + " for audio information, aborting loop");
                        break;
                    }
                    try
                    {
                        AudioFile audioFile = new AudioFile();
                        using (TagLib.File tagFile = TagLib.File.Create(file))
                        {
                            if (!string.IsNullOrEmpty(tagFile.Tag.Album))
                            {
                                audioFile.Album = tagFile.Tag.Album;
                            }
                            if (!string.IsNullOrEmpty(tagFile.Tag.JoinedAlbumArtists))
                            {
                                audioFile.Artist = tagFile.Tag.JoinedAlbumArtists;
                            }
                            if (tagFile.Properties.Duration != TimeSpan.Zero)
                            {
                                audioFile.Duration = tagFile.Properties.Duration;
                            }
                            if (!string.IsNullOrEmpty(tagFile.Tag.Title))
                            {
                                audioFile.Title = tagFile.Tag.Title;
                            }
                            if (tagFile.Tag.Track != 0)
                            {
                                audioFile.TrackNumber = (int)tagFile.Tag.Track;
                            }
                        }
                        if (string.IsNullOrEmpty(audioFile.Artist))
                        {
                            string[] parts       = relativePath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                            int      depth       = parts.Length - 1;
                            string   partToParse = parts[depth < 2 ? 0 : depth - 2];
                            if (partToParse.Contains("-"))
                            {
                                partToParse = partToParse.Split(new char[] { '-' })[0].Trim();
                            }
                            audioFile.Artist = partToParse;
                            if (audioFile.Artist == string.Empty)
                            {
                                audioFile.Artist = null;
                            }
                        }
                        if (string.IsNullOrEmpty(audioFile.Album))
                        {
                            string[] parts       = relativePath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                            int      depth       = parts.Length - 1;
                            string   partToParse = parts[depth < 1 ? 0 : depth - 1];
                            if (partToParse.Contains("-"))
                            {
                                partToParse = partToParse.Split(new char[] { '-' })[0].Trim();
                            }
                            audioFile.Album = partToParse;
                            if (audioFile.Album == string.Empty)
                            {
                                audioFile.Album = null;
                            }
                        }
                        if (string.IsNullOrEmpty(audioFile.Title))
                        {
                            audioFile.Title = Path.GetFileNameWithoutExtension(file).Trim();
                            if (audioFile.Title.Contains("-"))
                            {
                                audioFile.Title = audioFile.Title.Split(new char[] { '-' }, 2)[1].Trim();
                            }
                            while (!string.IsNullOrEmpty(audioFile.Title) && char.IsDigit(audioFile.Title[0]))
                            {
                                if (audioFile.Title.Length == 1)
                                {
                                    audioFile.Title = null;
                                    break;
                                }
                                audioFile.Title = audioFile.Title.Substring(1, audioFile.Title.Length - 1).Trim();
                            }
                            if (audioFile.Title == string.Empty)
                            {
                                audioFile.Title = null;
                            }
                        }
                        audioFile.DeviceUuid   = device.Uuid;
                        audioFile.LastSeen     = DateTime.UtcNow;
                        audioFile.RelativePath = relativePath;
                        Logger.Debug(audioFile.ToString());

                        // See if we have an existing file for this one
                        AudioFile existing        = allAudioFiles.Where(existingFile => existingFile.RelativePath == audioFile.RelativePath).FirstOrDefault();
                        bool      existingIsEqual = false;
                        if (existing != null)
                        {
                            existingIsEqual = audioFile.Equals(existing);
                            if (!existingIsEqual)
                            {
                                if ((existing.Album != audioFile.Album) || (existing.Artist != audioFile.Artist))
                                {
                                    existing.ArtworkSearchDate = null;
                                }
                                existing.Album       = audioFile.Album;
                                existing.Artist      = audioFile.Artist;
                                existing.Duration    = audioFile.Duration;
                                existing.LastSeen    = audioFile.LastSeen;
                                existing.Title       = audioFile.Title;
                                existing.TrackNumber = audioFile.TrackNumber;
                                audioFile            = existing;
                            }
                        }

                        // The "AC/DC Fix"
                        if ((audioFile.Artist == "AC;DC") || (audioFile.Artist == "AC; DC") || (audioFile.Artist == "AC_DC"))
                        {
                            audioFile.Artist = "AC/DC";
                        }

                        // Add to update notification if new or if it is updated
                        if (audioFile.AudioFileId == 0)
                        {
                            notification.NewFiles.Add(audioFile);
                        }
                        else if (!existingIsEqual)
                        {
                            notification.UpdatedFiles.Add(audioFile);
                        }

                        // Deal database updates and changes and firing of notifications if we have reached enough
                        // files in this object and create a new object
                        if (notification.ReadyToSend)
                        {
                            ProcessFileChanges(notification);
                            notification = new AudioLibraryUpdateNotification();
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.Error("Failed to probe file " + file, ex);
                    }
                }
            }
            catch
            {
            }

            // Deal database updates and changes and firing of notifications if we have reached enough
            // files in this object and create a new object
            ProcessFileChanges(notification);
        }
        /// <summary>
        /// This thread is used to probe all files on a particular device.
        /// </summary>
        /// <param name='args'>
        /// The arguments to pass to the thread.
        /// </param>
        private void AudioDiscoveryThread(object args)
        {
            try
            {
                // Cast object from thread arguments
                MountedDevice device = (MountedDevice)args;

                // Get a list from database of all existing tracks
                AudioFile[] allAudioFiles = AudioFileFactory.ApplicationInstance.ReadAll().Where(file => file.DeviceUuid == device.Uuid).ToArray();

                // Recursively gain two lists - new and existing files.  We always process new files
                // first, then online, then we check for changed to online and fire updated
                // and finally deleted to give quickest response to the client
                List <string> newFiles      = new List <string>();
                List <string> existingFiles = new List <string>();
                GetAllFiles(device, "/", allAudioFiles, newFiles, existingFiles);

                // Now process the file sets
                DateTime startTime = DateTime.UtcNow;
                Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
                ProcessFileList(device, newFiles, allAudioFiles);
                AudioLibraryUpdateNotification notification = new AudioLibraryUpdateNotification();
                if (existingFiles.Count > 0)
                {
                    foreach (string relativePath in existingFiles)
                    {
                        AudioFile file = allAudioFiles.FirstOrDefault(f => f.RelativePath == relativePath);
                        if (file == null)
                        {
                            continue;
                        }
                        notification.OnlineFiles.Add(file);
                    }
                    ProcessFileChanges(notification);
                    notification = new AudioLibraryUpdateNotification();
                }
                Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
                ProcessFileList(device, existingFiles, allAudioFiles);
                Thread.CurrentThread.Priority = ThreadPriority.Normal;
                foreach (AudioFile file in allAudioFiles)
                {
                    if (file.LastSeen < startTime)
                    {
                        notification.DeletedFiles.Add(file.AudioFileId);
                    }
                }
                if (notification.DeletedFiles.Count > 0)
                {
                    Controller.NotificationNetworkServer.SendNotification(notification);
                }
                AudioFileFactory.ApplicationInstance.RemoveForUuid(device.Uuid, startTime);
            }
            catch (ThreadAbortException)
            {
            }
            catch (Exception ex)
            {
                Logger.Error("Fatal error during audio file discovery", ex);
            }
            finally
            {
                lock (_discoveryThreads)
                {
                    MountedDevice key = null;
                    foreach (KeyValuePair <MountedDevice, Thread> kvp in _discoveryThreads)
                    {
                        if (kvp.Value == Thread.CurrentThread)
                        {
                            key = kvp.Key;
                            break;
                        }
                    }
                    if ((key != null) && (_discoveryThreads.ContainsKey(key)))
                    {
                        _discoveryThreads.Remove(key);
                    }
                }
            }
        }