public RequestedSong GetRandomSong() { lock (lockObject) { if (_songs.Count == 0) { return(null); } int randomizerIgnoreHours; if (!int.TryParse(SongPlayerFactory.GetConfigFile().GetValue("player.randomizerignorehours"), out randomizerIgnoreHours)) { randomizerIgnoreHours = 8; } // If song is > 10 minutes, ignore // If song is played last xxx hours, ignore List <Song> songsToChooseFrom = _songs.Values.Where(x => (x.Duration != null && x.Duration < 600) && (x.LastPlayDateTime == null || x.LastPlayDateTime < DateTime.Now.AddHours(-1 * randomizerIgnoreHours))).ToList(); if (songsToChooseFrom.Count == 0) { songsToChooseFrom = _songs.Values.ToList(); } Song randomSong = songsToChooseFrom[random.Next(songsToChooseFrom.Count)]; return(new RequestedSong() { Song = randomSong, RequesterName = "randomizer" }); } }
private void UpdateTagsThread() { Song song; bool fixErrors = DateTime.Now > _lastFixErrors + TimeSpan.FromMinutes(2); List <ManualResetEvent> doneEvents = new List <ManualResetEvent>(); Config.ConfigFile config = SongPlayerFactory.GetConfigFile(); string[] extensionsArray = config.GetValue("library.extensions").Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.StartsWith(".", StringComparison.OrdinalIgnoreCase) ? x : "." + x) .ToArray(); HashSet <string> extensions = new HashSet <string>(extensionsArray, StringComparer.OrdinalIgnoreCase); if (extensions.Count == 0) { extensions.Add(".mp3"); } do { //Lock collection as short as possible lock (lockObject) { if (fixErrors) { song = _songs.Values.FirstOrDefault(s => s.TagRead == false); } else { song = _songs.Values.FirstOrDefault(s => s.TagRead == false && s.ErrorReadingTag == false); } } if (song != null) { if (extensions.Contains(song.Extension)) { if (song.ErrorReadingTag) { _lastFixErrors = DateTime.Now; } // update song UpdateSingleTag(song); _updatedTag = true; } } // loop until no song found } while (song != null); // finished this run _updateRunning = false; }
/// <summary> /// Enqueue song /// </summary> public void Enqueue(Song song, string requesterName) { int maximalsonginqueue; if (!int.TryParse(SongPlayerFactory.GetConfigFile().GetValue("player.maximalsonginqueue"), out maximalsonginqueue)) { maximalsonginqueue = int.MaxValue; } if (_queue.Count >= maximalsonginqueue) { return; } SongLibrary.UpdateSingleTag(song); _queue.Add(new RequestedSong { Song = song, RequesterName = requesterName, RequestedDate = DateTime.Now }); }
public bool ScanLibrary() { int minutesBetweenScans; if (!int.TryParse(SongPlayerFactory.GetConfigFile().GetValue("library.minutesbetweenscans"), out minutesBetweenScans)) { minutesBetweenScans = 2; } bool tagChanges = UpdateTags(); if (tagChanges) { int noTagCount; int songCount; lock (lockObject) { noTagCount = _songs.Values.Count(s => s.TagRead); songCount = _songs.Count(); } OnStatusChanged(string.Format("Library updated: {0} songs. Tags read: {1}/{0}. Next scan: {2}.", songCount, noTagCount, (_lastFullUpdate + TimeSpan.FromMinutes(minutesBetweenScans)).ToShortTimeString())); } else { int songCount; lock (lockObject) { songCount = _songs.Count(); } OnStatusChanged("Library update completed (" + songCount + " songs). Next scan: " + (_lastFullUpdate + TimeSpan.FromMinutes(minutesBetweenScans)).ToShortTimeString()); } // check need to save // -> unsaved changes // -> tag(s) are changed // -> song is marked dirty (last time played is changed) bool dirtySongs; lock (lockObject) { dirtySongs = _songs.Values.Any(x => x.IsDirty); } _unsavedChanges = _unsavedChanges || tagChanges || dirtySongs; //Save, but no more than once every 2 minutes if (_unsavedChanges && _lastSerialize + TimeSpan.FromMinutes(2) < DateTime.Now) { Serialize(); } //No need to scan... if (_lastFullUpdate + TimeSpan.FromMinutes(minutesBetweenScans) > DateTime.Now) { return(tagChanges); } bool fileChanges = ScanSongs(); if (fileChanges || tagChanges) { int songCount; int noTagCount; lock (lockObject) { songCount = _songs.Count(); noTagCount = _songs.Values.Count(s => s.TagRead); } OnStatusChanged(string.Format("Library updated: {0} songs. Tags read: {1}/{0}. Next scan: {2}.", songCount, noTagCount, (_lastFullUpdate + TimeSpan.FromMinutes(minutesBetweenScans)).ToShortTimeString())); } _lastFullUpdate = DateTime.Now; if (!fileChanges || !tagChanges) { int songCount; lock (lockObject) { songCount = _songs.Count(); } OnStatusChanged("Library update completed (" + songCount + " songs). Next scan: " + (_lastFullUpdate + TimeSpan.FromMinutes(minutesBetweenScans)).ToShortTimeString()); } _unsavedChanges = _unsavedChanges || fileChanges || tagChanges; return(fileChanges || tagChanges); }
private void ScanSongsThread() { Config.ConfigFile config = SongPlayerFactory.GetConfigFile(); string[] directories = config.GetValue("library.path").Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); string[] extensionsArray = config.GetValue("library.extensions").Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.StartsWith(".", StringComparison.OrdinalIgnoreCase) ? x : "." + x) .ToArray(); HashSet <string> extensions = new HashSet <string>(extensionsArray, StringComparer.OrdinalIgnoreCase); if (extensions.Count == 0) { extensions.Add(".mp3"); } HashSet <string> files = new HashSet <string>(StringComparer.OrdinalIgnoreCase); //assuming we could have several dirs here, lets speed up the process Parallel.ForEach(directories, directory => { if (Directory.Exists(directory)) { HashSet <string> filesFound = GetFilesRecursive(directory, extensions); // lock files object lock (lockObject) { files.UnionWith(filesFound); } } }); //Find removed songs lock (lockObject) { string[] keysToRemove = _songs.Keys.Where(x => !files.Contains(x, StringComparer.OrdinalIgnoreCase)).ToArray(); foreach (string key in keysToRemove) { if (_songs.Remove(key)) { _scanFoundChange = true; } } } //Find added songs. Here we can have thousands of files Parallel.ForEach(files, fileName => { bool checkNext = false; lock (lockObject) { if (_songs.ContainsKey(fileName)) { checkNext = true; } } if (!checkNext) { FileInfo fileInfo = new FileInfo(fileName); Song song = new Song(); song.FileName = fileName; song.Extension = fileInfo.Extension; song.Name = Regex.Replace(fileInfo.Name, @"\" + fileInfo.Extension + "$", string.Empty, RegexOptions.IgnoreCase); song.DateCreated = fileInfo.CreationTime.ToString("yyyy-MM-dd HH:mm"); song.GenerateSearchAndDoubleMetaphone(); lock (lockObject) { _songs.Add(fileName, song); } _scanFoundChange = true; } }); _scanRunning = false; }
private void Deserialize() { try { lock (lockObject) { if (File.Exists("library.bin")) { Config.ConfigFile config = SongPlayerFactory.GetConfigFile(); string[] extensionsArray = config.GetValue("library.extensions").Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.StartsWith(".", StringComparison.OrdinalIgnoreCase) ? x : "." + x) .ToArray(); HashSet <string> extensions = new HashSet <string>(extensionsArray, StringComparer.OrdinalIgnoreCase); if (extensions.Count == 0) { extensions.Add(".mp3"); } using (Stream stream = File.Open("library.bin", FileMode.Open)) { if (stream.Length > 0) { BinaryFormatter bin = new BinaryFormatter(); object fromLibrary = bin.Deserialize(stream); if (fromLibrary is List <Song> ) { List <Song> songs = (List <Song>)fromLibrary; foreach (Song song in songs) { // only add supported songs if (extensions.Contains(song.Extension)) { song.GenerateSearchAndDoubleMetaphone(); _songs.Add(song.FileName, song); } } } else if (fromLibrary is Dictionary <string, Song> ) { Dictionary <string, Song> songs = (Dictionary <string, Song>)fromLibrary; foreach (Song song in songs.Values) { // only add supported songs if (extensions.Contains(song.Extension)) { song.GenerateSearchAndDoubleMetaphone(); _songs.Add(song.FileName, song); } } } else if (fromLibrary is Dictionary <string, Song> .ValueCollection) { Dictionary <string, Song> .ValueCollection valueCollection = (Dictionary <string, Song> .ValueCollection)fromLibrary; List <Song> songs = valueCollection.ToList(); foreach (Song song in songs) { // only add supported songs if (extensions.Contains(song.Extension)) { song.GenerateSearchAndDoubleMetaphone(); _songs.Add(song.FileName, song); } } } else { throw new Exception(string.Format("Songs saved in unknown type '{0}'!", fromLibrary.GetType().Name)); } // can't be dirty when just deserialized... List <Song> dirtySongs = _songs.Values.Where(x => x.IsDirty).ToList(); foreach (Song song in dirtySongs) { song.IsDirty = false; } } } } } OnStatusChanged("Loaded library containing " + _songs.Count() + " songs"); } catch (Exception) { OnStatusChanged("Error loading library..."); } _unsavedChanges = false; }
/// <summary> /// Update method /// </summary> public void Update() { while (_running) { try { bool isPlaying; lock (lockObject) { isPlaying = _mediaDevice.IsPlaying; } if (!isPlaying) { Next("randomizer"); } } catch { } string status; if (SongPlayerFactory.GetSongPlayer().PlayerStatus.RequestedSong != null) { status = string.Format("Currently playing at volume {2}: {0} sec -> {1}", SongPlayerFactory.GetSongPlayer().PlayerStatus.Position, SongPlayerFactory.GetSongPlayer().PlayerStatus.RequestedSong.Song.GetArtistAndTitle(), SongPlayerFactory.GetSongPlayer().Volume); } else { status = "No song playing..."; } OnPlayerStatusChanged(status); int minimalsonginqueue; if (!int.TryParse(SongPlayerFactory.GetConfigFile().GetValue("player.minimalsonginqueue"), out minimalsonginqueue)) { minimalsonginqueue = 0; } //Enqueue random song when the queue is empty and the current song is almost finished if (_currentSong != null && _queue.Count < minimalsonginqueue + ((int)(DateTime.Now - _currentSongStart).TotalSeconds + 20 > _currentSong.Song.Duration ? 1 : 0)) { RequestedSong requestedSong = _songLibrary.GetRandomSong(); if (requestedSong != null) { Enqueue(requestedSong.Song, requestedSong.RequesterName); } } // when not scanning for songs, clear the queue of unavailable songs if (!_songLibrary.ScanRunning) { ClearQueue(); } if (!_songLibrary.ScanLibrary()) { Thread.Sleep(50); } else { Thread.Sleep(10); } } }