banshee r4477 - in trunk/banshee: . src/Core/Banshee.Services/Banshee.Collection src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Banshee.Services/Banshee.Playlist src/Core/Banshee.Services/Banshee.Playlists.Formats src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp src/Dap/Banshee.Dap/Banshee.Dap src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data src/Libraries/Hyena/Hyena.Collections



Author: gburt
Date: Sat Sep  6 21:58:35 2008
New Revision: 4477
URL: http://svn.gnome.org/viewvc/banshee?rev=4477&view=rev

Log:
2008-09-05  Gabriel Burt  <gabriel burt gmail com>

	This commit adds playlist support to USB Mass Storage players, and fixes a
	bug that causes very slow initial loading of their tracks.

	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastFeedModel.cs:
	Fix model so that it's filtered by the filters before it.

	* src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs:
	Add playlist support, respecting the HAL
	portable_audio_player.playlist_format and playlist_path keys.

	* src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodSource.cs:
	* src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs: Add helper
	AddYesNoDapProperty method and use it.

	* src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpSource.cs: Call OnTracksAdded
	manually after loading the tracks off the device.

	* src/Dap/Banshee.Dap/Banshee.Dap/DapSync.cs: Don't reload the models when
	the dap isn't yet loaded, or when we're syncing.

	* src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatDescription.cs:
	* src/Core/Banshee.Services/Banshee.Playlists.Formats/M3uPlaylistFormat.cs:
	* src/Core/Banshee.Services/Banshee.Playlists.Formats/AsxPlaylistFormat.cs:
	* src/Core/Banshee.Services/Banshee.Playlists.Formats/PlsPlaylistFormat.cs:
	Add a MimeType property to the description objects.

	* src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatBase.cs:
	In the BaseUri setter, make sure it ends with a directory separator char,
	and if not, fix it.

	* src/Core/Banshee.Services/Banshee.Playlist/PlaylistFileUtil.cs: Add a
	new Load method, factored out from the ImportPlaylist method.

	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportManager.cs:
	ImportFinished renamed to Finished because uses the QueuePipeline event
	now. Allow setting the BaseUri in the Load/Import methods.

	* src/Core/Banshee.Services/Banshee.Collection/ImportManager.cs: Fix
	painful bug caused by the pipelining of the importer.  The track
	processing element would sometimes (often) have zero items left when the
	scanning element was still working, but we were raising ImportFinished
	when that happened, instead of waiting for all elements in the pipeline to
	be finished (BGO #548254).

	* src/Libraries/Hyena/Hyena.Collections/QueuePipelineElement.cs: Add a
	Finished event.

	* src/Libraries/Hyena/Hyena.Collections/QueuePipeline.cs: Add a finished
	event, raised when all elements in the pipeline are finished.



Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportManager.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/ImportManager.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistFileUtil.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/AsxPlaylistFormat.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/M3uPlaylistFormat.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatBase.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatDescription.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlsPlaylistFormat.cs
   trunk/banshee/src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodSource.cs
   trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs
   trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpSource.cs
   trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs
   trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSync.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastFeedModel.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Collections/QueuePipeline.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Collections/QueuePipelineElement.cs

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportManager.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportManager.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportManager.cs	Sat Sep  6 21:58:35 2008
@@ -239,10 +239,10 @@
             counts.Clear ();
         }
 
-        protected override void OnImportFinished ()
+        protected override void OnFinished ()
         {
             NotifyAllSources ();
-            base.OnImportFinished ();
+            base.OnFinished ();
         }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/ImportManager.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/ImportManager.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/ImportManager.cs	Sat Sep  6 21:58:35 2008
@@ -81,13 +81,6 @@
                 return null;   
             }
             
-            protected override void OnFinished ()
-            {
-                base.OnFinished ();
-                manager.DestroyUserJob ();
-                manager.OnImportFinished ();
-            }
-            
             public void Reset ()
             {
                 processed_count = 0;
@@ -107,7 +100,6 @@
         private uint timer_id;
         
         public event ImportEventHandler ImportRequested;
-        public event EventHandler ImportFinished;
         
         public ImportManager ()
         {
@@ -251,12 +243,10 @@
             }
         }
         
-        protected virtual void OnImportFinished ()
+        protected override void OnFinished ()
         {
-            EventHandler handler = ImportFinished;
-            if (handler != null) {
-                handler (this, EventArgs.Empty);
-            }
+            DestroyUserJob ();
+            base.OnFinished ();
         }
         
 #endregion

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistFileUtil.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistFileUtil.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistFileUtil.cs	Sat Sep  6 21:58:35 2008
@@ -106,7 +106,24 @@
         }
         
         public static string [] ImportPlaylist (string playlistUri)
-        {            
+        {
+            return ImportPlaylist (playlistUri, null);
+        }
+
+        public static string [] ImportPlaylist (string playlistUri, Uri baseUri)
+        {
+            IPlaylistFormat playlist = Load (playlistUri, baseUri);
+            List<string> uris = new List<string> ();
+            if (playlist != null) {
+                foreach (Dictionary<string, object> element in playlist.Elements) {
+                    uris.Add (((Uri)element["uri"]).AbsoluteUri);
+                }
+            }
+            return uris.ToArray ();
+        }
+
+        public static IPlaylistFormat Load (string playlistUri, Uri baseUri)
+        {
             PlaylistFormatDescription [] formats = PlaylistFileUtil.ExportFormats;            
             
             // If the file has an extenstion, rearrange the format array so that the 
@@ -131,22 +148,17 @@
                 }
             }
             
-            List<string> uris = new List<string> ();
-                
             foreach (PlaylistFormatDescription format in formats) {
                 try {
                     IPlaylistFormat playlist = (IPlaylistFormat)Activator.CreateInstance (format.Type);
+                    playlist.BaseUri = baseUri;
                     playlist.Load (Banshee.IO.File.OpenRead (new SafeUri (playlistUri)), true);
-                    foreach (Dictionary<string, object> element in playlist.Elements) {
-                        uris.Add (((Uri)element["uri"]).AbsoluteUri);
-                    }
-                    break;
-                } catch (InvalidPlaylistException) {                    
-                    continue;
-                }      
+                    return playlist;
+                } catch (InvalidPlaylistException) {
+                }
             }
         
-            return uris.ToArray ();
+            return null;
         }
         
         public static void ImportPlaylistToLibrary (string path)
@@ -190,7 +202,7 @@
         {
             try {
                 importer = new LibraryImportManager ();
-                importer.ImportFinished += CreatePlaylist;
+                importer.Finished += CreatePlaylist;
                 importer.Enqueue (uris);
             } catch (PlaylistImportCanceledException e) {
                 Hyena.Log.Exception (e);

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/AsxPlaylistFormat.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/AsxPlaylistFormat.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/AsxPlaylistFormat.cs	Sat Sep  6 21:58:35 2008
@@ -43,7 +43,8 @@
     public class AsxPlaylistFormat : PlaylistFormatBase
     {
         public static readonly PlaylistFormatDescription FormatDescription = new PlaylistFormatDescription(
-            typeof(AsxPlaylistFormat), MagicHandler, Catalog.GetString("Windows Media ASX (*.asx)"), "asx");
+            typeof(AsxPlaylistFormat), MagicHandler, Catalog.GetString("Windows Media ASX (*.asx)"),
+            "asx", new string [] {"video/x-ms-asx", "video/asx", "video/x-ms-asf"});
         
         public static bool MagicHandler(StreamReader reader)
         {

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/M3uPlaylistFormat.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/M3uPlaylistFormat.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/M3uPlaylistFormat.cs	Sat Sep  6 21:58:35 2008
@@ -41,7 +41,8 @@
     public class M3uPlaylistFormat : PlaylistFormatBase
     {
         public static readonly PlaylistFormatDescription FormatDescription = new PlaylistFormatDescription(
-            typeof(M3uPlaylistFormat), MagicHandler, Catalog.GetString("MPEG Version 3.0 Extended (*.m3u)"), "m3u");
+            typeof(M3uPlaylistFormat), MagicHandler, Catalog.GetString("MPEG Version 3.0 Extended (*.m3u)"),
+            "m3u", new string [] {"audio/x-mpegurl", "audio/m3u", "audio/mpeg-url"});
         
         public static bool MagicHandler(StreamReader reader)
         {

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatBase.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatBase.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatBase.cs	Sat Sep  6 21:58:35 2008
@@ -110,7 +110,13 @@
         
         public virtual Uri BaseUri {
             get { return base_uri; }
-            set { base_uri = value; }
+            set {
+                string abs_uri = value.AbsoluteUri;
+                if (abs_uri[abs_uri.Length - 1] != System.IO.Path.DirectorySeparatorChar) {
+                    value = new Uri (abs_uri + System.IO.Path.DirectorySeparatorChar);
+                }
+                base_uri = value;
+            }
         }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatDescription.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatDescription.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlaylistFormatDescription.cs	Sat Sep  6 21:58:35 2008
@@ -37,14 +37,16 @@
         private Type type;
         private string name;
         private string extension;
+        private string [] mimetypes;
         private PlaylistFormatMagicHandler magic_handler;
         
-        public PlaylistFormatDescription(Type type, PlaylistFormatMagicHandler magic_handler, string name, string extension)
+        public PlaylistFormatDescription(Type type, PlaylistFormatMagicHandler magic_handler, string name, string extension, string [] mimetypes)
         {
             this.type = type;
             this.magic_handler = magic_handler;
             this.name = name;
             this.extension = extension;
+            this.mimetypes = mimetypes;
         }
         
         public Type Type {
@@ -62,5 +64,9 @@
         public string FileExtension {
             get { return extension; }
         }
+
+        public string [] MimeTypes {
+            get { return mimetypes; }
+        }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlsPlaylistFormat.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlsPlaylistFormat.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlists.Formats/PlsPlaylistFormat.cs	Sat Sep  6 21:58:35 2008
@@ -48,7 +48,8 @@
         }
         
         public static readonly PlaylistFormatDescription FormatDescription = new PlaylistFormatDescription(
-            typeof(PlsPlaylistFormat), MagicHandler, Catalog.GetString("Shoutcast Playlist version 2 (*.pls)"), "pls");
+            typeof(PlsPlaylistFormat), MagicHandler, Catalog.GetString("Shoutcast Playlist version 2 (*.pls)"),
+            "pls", new string [] {"audio/x-scpls"});
         
         public static bool MagicHandler(StreamReader reader)
         {

Modified: trunk/banshee/src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodSource.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodSource.cs	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodSource.cs	Sat Sep  6 21:58:35 2008
@@ -97,8 +97,8 @@
             string [] capabilities = new string [ipod_device.ModelInfo.Capabilities.Count];
             ipod_device.ModelInfo.Capabilities.CopyTo (capabilities, 0);
             AddDapProperty (Catalog.GetString ("Capabilities"), String.Join (", ", capabilities));
-            AddDapProperty (Catalog.GetString ("Supports cover art"), ipod_device.ModelInfo.AlbumArtSupported ? Catalog.GetString ("Yes") : Catalog.GetString ("No"));
-            AddDapProperty (Catalog.GetString ("Supports photos"), ipod_device.ModelInfo.PhotosSupported ? Catalog.GetString ("Yes") : Catalog.GetString ("No"));
+            AddYesNoDapProperty (Catalog.GetString ("Supports cover art"), ipod_device.ModelInfo.AlbumArtSupported);
+            AddYesNoDapProperty (Catalog.GetString ("Supports photos"), ipod_device.ModelInfo.PhotosSupported);
         }
 
         public override void Dispose ()
@@ -135,6 +135,7 @@
         {
             LoadIpod ();
             LoadFromDevice (false);
+            OnTracksAdded ();
         }
 
         private void LoadIpod ()

Modified: trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs	Sat Sep  6 21:58:35 2008
@@ -43,6 +43,9 @@
 using Banshee.Collection.Database;
 using Banshee.Hardware;
 
+using Banshee.Playlists.Formats;
+using Banshee.Playlist;
+
 namespace Banshee.Dap.MassStorage
 {
     public class MassStorageSource : DapSource
@@ -103,6 +106,8 @@
                 AddDapProperty (Catalog.GetString ("Required Folder Depth"), FolderDepth.ToString ());
             }
 
+            AddYesNoDapProperty (Catalog.GetString ("Supports Playlists"), PlaylistTypes.Count > 0);
+
             /*if (AcceptableMimeTypes.Length > 0) {
                 AddDapProperty (String.Format (
                     Catalog.GetPluralString ("Audio Format", "Audio Formats", PlaybackFormats.Length), PlaybackFormats.Length),
@@ -111,18 +116,54 @@
             }*/
         }
 
+        private DatabaseImportManager importer;
         // WARNING: This will be called from a thread!
         protected override void LoadFromDevice ()
         {
-            DatabaseImportManager importer = new DatabaseImportManager (this);
+            importer = new DatabaseImportManager (this);
             importer.KeepUserJobHidden = true;
             importer.Threaded = false; // We are already threaded
+            importer.Finished += OnImportFinished;
 
             foreach (string audio_folder in BaseDirectories) {
                 importer.Enqueue (audio_folder);
             }
         }
 
+        private void OnImportFinished (object o, EventArgs args)
+        {
+            importer.Finished -= OnImportFinished;
+
+            if (!CanSyncPlaylists) {
+                return;
+            }
+
+            Hyena.Data.Sqlite.HyenaSqliteCommand insert_cmd = new Hyena.Data.Sqlite.HyenaSqliteCommand (
+                "INSERT INTO CorePlaylistEntries (PlaylistID, TrackID) VALUES (?, ?)");
+            int [] psources = new int [] {DbId};
+            foreach (string playlist_path in PlaylistFiles) {
+                IPlaylistFormat loaded_playlist = PlaylistFileUtil.Load (playlist_path, new Uri (BaseDirectory));
+                if (loaded_playlist == null)
+                    continue;
+
+                PlaylistSource playlist = new PlaylistSource (System.IO.Path.GetFileNameWithoutExtension (playlist_path), DbId);
+                playlist.Save ();
+                //Hyena.Data.Sqlite.HyenaSqliteCommand.LogAll = true;
+                foreach (Dictionary<string, object> element in loaded_playlist.Elements) {
+                    string track_path = (element["uri"] as Uri).LocalPath;
+                    int track_id = DatabaseTrackInfo.GetTrackIdForUri (track_path, Paths.MakePathRelative (track_path, BaseDirectory), psources);
+                    if (track_id == 0) {
+                        Log.DebugFormat ("Failed to find track {0} in DAP library to load it into playlist {1}", track_path, playlist_path);
+                    } else {
+                        ServiceManager.DbConnection.Execute (insert_cmd, playlist.DbId, track_id);
+                    }
+                }
+                //Hyena.Data.Sqlite.HyenaSqliteCommand.LogAll = false;
+                playlist.UpdateCounts ();
+                AddChildSource (playlist);
+            }
+        }
+
         public override void CopyTrackTo (DatabaseTrackInfo track, SafeUri uri, BatchUserJob job)
         {
             if (track.PrimarySourceId == DbId) {
@@ -167,6 +208,113 @@
         protected string IsAudioPlayerPath {
             get { return System.IO.Path.Combine (volume.MountPoint, ".is_audio_player"); }
         }
+
+        #region Properties and Methods for Supporting Syncing of Playlists
+
+        private string playlists_path;
+        private string PlaylistsPath {
+            get {
+                if (playlists_path == null) {
+                    if (MediaCapabilities == null || MediaCapabilities.PlaylistPath == null) {
+                        playlists_path = WritePath;
+                    } else {
+                        playlists_path = System.IO.Path.Combine (WritePath, MediaCapabilities.PlaylistPath);
+                        playlists_path = playlists_path.Replace ("%File", String.Empty);
+                    }
+
+                    if (!Directory.Exists (playlists_path)) {
+                        Directory.Create (playlists_path);
+                    }
+                }
+                return playlists_path;
+            }
+        }
+
+        private string [] playlist_formats;
+        private string [] PlaylistFormats {
+            get {
+                if (playlist_formats == null && SupportsPlaylists && MediaCapabilities != null) {
+                    playlist_formats = MediaCapabilities.PlaylistFormats;
+                }
+                return playlist_formats;
+            }
+            set { playlist_formats = value; }
+        }
+
+        private List<PlaylistFormatDescription> playlist_types;
+        private IList<PlaylistFormatDescription> PlaylistTypes  {
+            get {
+                if (playlist_types == null) {
+                    playlist_types = new List<PlaylistFormatDescription> ();
+                    if (PlaylistFormats != null) {
+                        foreach (PlaylistFormatDescription desc in Banshee.Playlist.PlaylistFileUtil.ExportFormats) {
+                            foreach (string mimetype in desc.MimeTypes) {
+                                if (Array.IndexOf (PlaylistFormats, mimetype) != -1) {
+                                    playlist_types.Add (desc);
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+                
+                SupportsPlaylists = CanSyncPlaylists;
+                return playlist_types;
+            }
+        }
+
+        private IEnumerable<string> PlaylistFiles {
+            get {
+                foreach (string file_name in Directory.GetFiles (PlaylistsPath)) {
+                    foreach (PlaylistFormatDescription desc in playlist_types) {
+                        if (file_name.EndsWith (desc.FileExtension)) {
+                            yield return file_name;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        private bool CanSyncPlaylists {
+            get {
+                return PlaylistsPath != null && playlist_types.Count > 0;
+            }
+        }
+
+        public override void SyncPlaylists ()
+        {
+            if (!CanSyncPlaylists) {
+                return;
+            }
+
+            foreach (string file_name in PlaylistFiles) {
+                Banshee.IO.File.Delete (new SafeUri (file_name));
+            }
+
+            // Add playlists from Banshee to the device
+            PlaylistFormatBase playlist_format = null;
+            List<Source> children = new List<Source> (Children);
+            foreach (Source child in children) {
+                PlaylistSource from = child as PlaylistSource;
+                if (from != null) {
+                    from.Reload ();
+                    if (playlist_format == null) {
+                         playlist_format = Activator.CreateInstance (PlaylistTypes[0].Type) as PlaylistFormatBase;
+                    }
+
+                    SafeUri playlist_path = new SafeUri (System.IO.Path.Combine (
+                        PlaylistsPath, String.Format ("{0}.{1}", from.Name, PlaylistTypes[0].FileExtension)));
+
+                    System.IO.Stream stream = Banshee.IO.File.OpenWrite (playlist_path, true);
+                    playlist_format.BaseUri = new Uri (BaseDirectory);
+                    playlist_format.Save (stream, from);
+                    stream.Close ();
+                }
+            }
+        }
+
+        #endregion
         
         public override long BytesUsed {
             get { return BytesCapacity - volume.Available; }
@@ -351,10 +499,20 @@
                     case "folder_depth":
                         FolderDepth = Int32.Parse (val);
                         break;
-
-                    case "input_formats":
+    
                     case "playlist_format":
+                        PlaylistFormats = val.Split(',');
+                        for (int i = 0; i < PlaylistFormats.Length; i++) {
+                            PlaylistFormats[i] = PlaylistFormats[i].Trim ();
+                        }
+                        break;
+
                     case "playlist_path":
+                        playlists_path = System.IO.Path.Combine (WritePath, val);
+                        playlists_path = playlists_path.Replace ("%File", String.Empty);
+                        break;
+
+                    case "input_formats":
                     default:
                         Log.DebugFormat ("Unsupported .is_audio_player key: {0}", key);
                         break;

Modified: trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpSource.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpSource.cs	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpSource.cs	Sat Sep  6 21:58:35 2008
@@ -192,6 +192,7 @@
             } catch (Exception e) {
                 Log.Exception (e);
             }
+            OnTracksAdded ();
         }
 
         public override void Import ()

Modified: trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs	Sat Sep  6 21:58:35 2008
@@ -255,9 +255,9 @@
                 PurgeTracks ();
                 SetStatus (String.Format (Catalog.GetString ("Loading {0}"), Name), false);
                 LoadFromDevice ();
-                OnTracksAdded ();
                 HideStatus ();
 
+                sync.DapLoaded ();
                 sync.CalculateSync ();
                 if (sync.AutoSync) {
                     sync.Sync ();
@@ -315,6 +315,11 @@
             dap_properties.Add (new DapProperty (key, val));
         }
 
+        protected void AddYesNoDapProperty (string key, bool val)
+        {
+            AddDapProperty (key, val ? Catalog.GetString ("Yes") : Catalog.GetString ("No"));
+        }
+
         public IEnumerable<DapProperty> DapProperties {
             get { return dap_properties; }
         }

Modified: trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSync.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSync.cs	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSync.cs	Sat Sep  6 21:58:35 2008
@@ -135,6 +135,12 @@
             //OnEnabledChanged (null);
         }
 
+        private bool dap_loaded = false;
+        public void DapLoaded ()
+        {
+            dap_loaded = true;
+        }
+
         private void BuildSyncLists ()
         {
             int i = 0;
@@ -175,7 +181,7 @@
 
         private void OnDapChanged (Source sender, TrackEventArgs args)
         {
-            if (!AutoSync) {
+            if (!AutoSync && dap_loaded && !Syncing) {
                 foreach (DapLibrarySync lib_sync in library_syncs) {
                     lib_sync.CalculateSync ();
                 }
@@ -254,10 +260,19 @@
 
         private void RateLimitedSync ()
         {
+            syncing = true;
+            
             foreach (DapLibrarySync library_sync in library_syncs) {
                 library_sync.Sync ();
             }
             dap.SyncPlaylists ();
+
+            syncing = false;
+        }
+
+        private bool syncing = false;
+        public bool Syncing {
+            get { return syncing; }
         }
     }
 }

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastFeedModel.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastFeedModel.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Data/PodcastFeedModel.cs	Sat Sep  6 21:58:35 2008
@@ -48,10 +48,9 @@
         {
             ReloadFragmentFormat = @"
                 FROM PodcastSyndications WHERE FeedID IN
-                    (SELECT FeedID FROM PodcastItems
-                        WHERE ItemID IN
-                            (SELECT CoreTracks.ExternalID FROM CoreTracks, CoreCache{0}
-                                WHERE CoreCache.ModelID = {1} AND CoreCache.ItemId = {2}))
+                    (SELECT DISTINCT FeedID FROM PodcastItems, CoreTracks, PodcastEnclosures, CoreCache{0}
+                        WHERE PodcastItems.ItemID = CoreTracks.ExternalID AND PodcastEnclosures.ItemID = PodcastItems.ItemID AND 
+                        CoreCache.ModelID = {1} AND CoreCache.ItemId = {2} {3})
                     ORDER BY lower(Title)";
         }
         

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Collections/QueuePipeline.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Collections/QueuePipeline.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Collections/QueuePipeline.cs	Sat Sep  6 21:58:35 2008
@@ -32,6 +32,13 @@
 {
     public class QueuePipeline <T> where T : class
     {
+        #pragma warning disable 0067
+        // FIXME: This is to mute gmcs: https://bugzilla.novell.com/show_bug.cgi?id=360455
+        public event EventHandler Finished;
+        #pragma warning restore 0067
+
+        private object sync = new object ();
+        
         private QueuePipelineElement<T> first_element;
         internal QueuePipelineElement<T> FirstElement {
             get { return first_element; }
@@ -43,14 +50,15 @@
         
         public void AddElement (QueuePipelineElement<T> element)
         {
-            lock (this) {
+            element.Finished += OnElementFinished;
+            lock (sync) {
                 if (first_element == null) {
                     first_element = element;
                     return;
                 }
             
                 QueuePipelineElement<T> current = first_element;
-                
+
                 while (current != null) {
                     if (current.NextElement == null) {
                         current.NextElement = element;
@@ -77,5 +85,33 @@
                 first_element.Cancel ();
             }
         }
+
+        private void OnElementFinished (object o, EventArgs args)
+        {
+            bool any_processing = false;
+
+            lock (sync) {
+                QueuePipelineElement<T> element = FirstElement;
+                while (element != null) {
+                    any_processing |= element.Processing;
+                    if (any_processing) {
+                        break;
+                    }
+                    element = element.NextElement;
+                }
+            }
+
+            if (!any_processing) {
+                OnFinished ();
+            }
+        }
+
+        protected virtual void OnFinished ()
+        {
+            EventHandler handler = Finished;
+            if (handler != null) {
+                handler (this, EventArgs.Empty);
+            }
+        }
     }
 }

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Collections/QueuePipelineElement.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Collections/QueuePipelineElement.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Collections/QueuePipelineElement.cs	Sat Sep  6 21:58:35 2008
@@ -37,6 +37,11 @@
         private class ElementProcessCanceledException : ApplicationException
         {
         }
+
+        #pragma warning disable 0067
+        // FIXME: This is to mute gmcs: https://bugzilla.novell.com/show_bug.cgi?id=360455
+        public event EventHandler Finished;
+        #pragma warning restore 0067
     
         private Queue<T> queue = new Queue<T> ();
         private object monitor = new object ();
@@ -52,6 +57,11 @@
             lock (this) {
                 canceled = false;
             }
+            
+            EventHandler handler = Finished;
+            if (handler != null) {
+                handler (this, EventArgs.Empty);
+            }
         }
         
         protected virtual void OnCanceled ()



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]