banshee r3883 - in trunk/banshee: . src/Core/Banshee.ThickClient/Banshee.Sources.Gui src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod



Author: abock
Date: Tue May  6 02:40:40 2008
New Revision: 3883
URL: http://svn.gnome.org/viewvc/banshee?rev=3883&view=rev

Log:
2008-05-05  Aaron Bockover  <abock gnome org>

    * src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodSource.cs:
    Implement the new iPod syncing model - it's mostly done, but still some
    glitches that need to be addressed

    * src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodTrackInfo.cs: Implemented
    full two way copy of database tracks to iPod tracks and back again -
    track media attributes are preserved in both directions, so this allows
    for video syncing - yes, I said video syncing. You can now use Banshee
    to manage videos on your iPod. Epic. Stop using iPods though, they suck.
    Buy an MTP device, save a seal, vote Obama.

    * src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView_DragAndDrop.cs:
    Removed the thread stuff which needs to be moved to DapSource (not done,
    so don't tell Gabe)



Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView_DragAndDrop.cs
   trunk/banshee/src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodSource.cs
   trunk/banshee/src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodTrackInfo.cs

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView_DragAndDrop.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView_DragAndDrop.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView_DragAndDrop.cs	Tue May  6 02:40:40 2008
@@ -197,15 +197,11 @@
                 
                 if (Gtk.Drag.GetSourceWidget (context) == this) {
                     DragDropList<Source> sources = selectionData;
-                    if(sources.Count > 0) {
-                        Banshee.Base.ThreadAssist.SpawnFromMain (delegate {
-                            drop_source.MergeSourceInput (sources[0], SourceMergeType.Source);
-                        });
+                    if (sources.Count > 0) {
+                        drop_source.MergeSourceInput (sources[0], SourceMergeType.Source);
                     }
-                } else {   
-                    Banshee.Base.ThreadAssist.SpawnFromMain (delegate {
-                        drop_source.MergeSourceInput (ServiceManager.SourceManager.ActiveSource, SourceMergeType.ModelSelection);
-                    });
+                } else {
+                    drop_source.MergeSourceInput (ServiceManager.SourceManager.ActiveSource, SourceMergeType.ModelSelection);
                 }
                 
                 Gtk.Drag.Finish (context, true, false, time);

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	Tue May  6 02:40:40 2008
@@ -28,12 +28,15 @@
 
 using System;
 using System.IO;
+using System.Threading;
 using System.Collections.Generic;
+using Mono.Unix;
 
 using IPod;
 
 using Hyena;
 using Banshee.Base;
+using Banshee.ServiceStack;
 using Banshee.Dap;
 using Banshee.Hardware;
 using Banshee.Collection.Database;
@@ -73,6 +76,7 @@
                 
         public override void Dispose ()
         {
+            CancelSyncThread ();
             base.Dispose ();
         }
 
@@ -90,6 +94,10 @@
             Dispose ();
         }
         
+        protected override IDeviceMediaCapabilities MediaCapabilities {
+            get { return ipod_device.Parent.MediaCapabilities ?? base.MediaCapabilities; }
+        }
+        
 #endregion
 
 #region Database Loading
@@ -263,7 +271,7 @@
                     name = ipod_device.Name;
                 }
                     
-                if (!String.IsNullOrEmpty (name)) {
+                /*if (!String.IsNullOrEmpty (name)) {
                     return name;
                 } else if (ipod_device.PropertyExists ("volume.label")) {
                     name = ipod_device.GetPropertyString ("volume.label");
@@ -271,7 +279,9 @@
                     name = ipod_device.GetPropertyString ("info.product");
                 } else {
                     name = ((IDevice)ipod_device).Name ?? "iPod";
-                }
+                }*/
+                
+                name = "WTF";
                 
                 try {
                     return name;
@@ -300,7 +310,14 @@
 #region Syncing
 
         private Queue<IpodTrackInfo> tracks_to_add = new Queue<IpodTrackInfo> ();
-        // private Queue<IpodTrackInfo> track_to_remove = new Queue<IpodTrackInfo> ();
+        private Queue<IpodTrackInfo> tracks_to_remove = new Queue<IpodTrackInfo> ();
+        
+        private uint sync_timeout_id = 0;
+        private object sync_timeout_mutex = new object ();
+        private object sync_mutex = new object ();
+        private Thread sync_thread;
+        private AutoResetEvent sync_thread_wait;
+        private bool sync_thread_dispose = false;
         
         public override bool IsReadOnly {
             get { return ipod_device.IsReadOnly; }
@@ -313,6 +330,14 @@
 
         protected override void DeleteTrack (DatabaseTrackInfo track)
         {
+            lock (sync_mutex) {
+                IpodTrackInfo ipod_track = track as IpodTrackInfo;
+                if (ipod_track != null) {
+                    tracks_to_remove.Enqueue (ipod_track);
+                    
+                    QueueSync ();
+                }
+            }
         }
         
         protected override void OnTracksDeleted ()
@@ -322,7 +347,7 @@
 
         protected override void AddTrackToDevice (DatabaseTrackInfo track, SafeUri fromUri)
         {
-            lock (this) {
+            lock (sync_mutex) {
                 if (track.PrimarySourceId == DbId) {
                     return;
                 }
@@ -333,14 +358,133 @@
                 ipod_track.Save (false);
             
                 tracks_to_add.Enqueue (ipod_track);
+                
+                QueueSync ();
             }
         }
 
-        /*private int OnUploadProgress (ulong sent, ulong total, IntPtr data)
+        private void QueueSync ()
         {
-            AddTrackJob.DetailedProgress = (double) sent / (double) total;
-            return 0;
-        }*/
+            lock (sync_timeout_mutex) {
+                if (sync_timeout_id > 0) {
+                    Application.IdleTimeoutRemove (sync_timeout_id);
+                }
+                
+                sync_timeout_id = Application.RunTimeout (5000, PerformSync);
+            }
+        }
+        
+        private void CancelSyncThread ()
+        {
+            lock (sync_mutex) {
+                if (sync_thread != null && sync_thread_wait != null) {
+                    sync_thread_dispose = true;
+                    sync_thread_wait.Set ();
+                }
+            }
+        }
+        
+        private bool PerformSync ()
+        {
+            lock (sync_mutex) {
+                if (sync_thread == null) {
+                    sync_thread_wait = new AutoResetEvent (true);
+                
+                    sync_thread = new Thread (new ThreadStart (PerformSyncThread));
+                    sync_thread.IsBackground = false;
+                    sync_thread.Priority = ThreadPriority.Lowest;
+                    sync_thread.Start ();
+                }
+                
+                sync_thread_wait.Set ();
+                
+                lock (sync_timeout_mutex) {
+                    sync_timeout_id = 0;
+                }
+                
+                return false;
+            }
+        }
+        
+        private void PerformSyncThread ()
+        {
+            while (true) {
+                sync_thread_wait.WaitOne ();
+                if (sync_thread_dispose) {
+                    break;
+                }
+                
+                PerformSyncThreadCycle ();
+            }
+            
+            lock (sync_mutex) {
+                sync_thread_dispose = false;
+                sync_thread_wait.Close ();
+                sync_thread_wait = null;
+                sync_thread = null;
+            }
+        }
+        
+        private void PerformSyncThreadCycle ()
+        {
+            while (tracks_to_add.Count > 0) {
+                IpodTrackInfo track = null;
+                lock (sync_mutex) {
+                    track = tracks_to_add.Dequeue ();
+                }
+                
+                try {
+                    track.CommitToIpod (ipod_device);
+                } catch (Exception e) {
+                    Log.Exception ("Cannot save track to iPod", e);
+                }
+            }
+            
+            while (tracks_to_remove.Count > 0) {
+                IpodTrackInfo track = null;
+                lock (sync_mutex) {
+                    track = tracks_to_remove.Dequeue ();
+                }
+                
+                try {
+                    if (track.IpodTrack != null) {
+                        ipod_device.TrackDatabase.RemoveTrack (track.IpodTrack);
+                    }
+                } catch (Exception e) {
+                    Log.Exception ("Cannot remove track from iPod", e);
+                }
+            } 
+            
+            try {
+                ipod_device.TrackDatabase.SaveProgressChanged += OnIpodDatabaseSaveProgressChanged;
+                ipod_device.Save ();
+            } catch (Exception e) {
+                Log.Exception ("Failed to save iPod database", e);
+            } finally {
+                ipod_device.TrackDatabase.SaveProgressChanged -= OnIpodDatabaseSaveProgressChanged;
+            }
+        }
+        
+        private void OnIpodDatabaseSaveProgressChanged (object o, IPod.TrackSaveProgressArgs args)
+        {
+            double progress = args.CurrentTrack == null ? 0.0 : args.TotalProgress;
+            string message = args.CurrentTrack == null 
+                    ? Catalog.GetString("Waiting for Media")
+                    : String.Format ("{0} - {1}", args.CurrentTrack.Artist, args.CurrentTrack.Title);
+             
+             Console.WriteLine ("Progress: {0}", progress);
+             AddTrackJob.Title = Catalog.GetString ("Syncing iPod");
+             AddTrackJob.Status = message;
+             AddTrackJob.Progress = progress;
+        }
+        
+        public bool SyncNeeded {
+            get {
+                lock (sync_mutex) {
+                    return tracks_to_add.Count > 0 || tracks_to_remove.Count > 0;
+                }
+            }
+        }
 
 #endregion
         

Modified: trunk/banshee/src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodTrackInfo.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodTrackInfo.cs	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodTrackInfo.cs	Tue May  6 02:40:40 2008
@@ -29,9 +29,12 @@
 using System;
 
 using Banshee.Base;
+using Banshee.Streaming;
 using Banshee.Collection;
 using Banshee.Collection.Database;
 
+using Hyena;
+
 namespace Banshee.Dap.Ipod
 {   
     public class IpodTrackInfo : DatabaseTrackInfo
@@ -72,6 +75,7 @@
                 TrackCount = track.TrackCount;
                 TrackNumber = track.TrackNumber;
                 Year = track.Year;
+                MediaAttributes = track.MediaAttributes;
             }
             
             CanSaveToDatabase = true;
@@ -86,9 +90,15 @@
             }
 
             ipod_id = (int)track.Id;
+            
             Duration = track.Duration;
             PlayCount = track.PlayCount;
-
+            LastPlayed = track.LastPlayed;
+            DateAdded = track.DateAdded;
+            TrackCount = track.TotalTracks;
+            TrackNumber = track.TrackNumber;
+            Year = track.Year;
+            
             AlbumTitle = String.IsNullOrEmpty (track.Album) ? null : track.Album;
             ArtistName = String.IsNullOrEmpty (track.Artist) ? null : track.Artist;
             TrackTitle = String.IsNullOrEmpty (track.Title) ? null : track.Title;
@@ -104,15 +114,137 @@
                 default:                     Rating = 0; break;
             }
             
-            LastPlayed = track.LastPlayed;
-            DateAdded = track.DateAdded;
-            TrackCount = track.TotalTracks;
-            TrackNumber = track.TrackNumber;
-            Year = track.Year;
-
             if (track.IsProtected) {
-                CanPlay = false;
-                // FIXME: indicate the song is DRMed
+                PlaybackError = StreamPlaybackError.Drm;
+            }
+            
+            MediaAttributes = TrackMediaAttributes.AudioStream;
+            
+            switch (track.Type) {
+                case IPod.MediaType.Audio:
+                    MediaAttributes |= TrackMediaAttributes.Music;
+                    break;
+                case IPod.MediaType.AudioVideo:
+                case IPod.MediaType.Video:
+                    MediaAttributes |= TrackMediaAttributes.VideoStream;
+                    break;
+                case IPod.MediaType.MusicVideo:
+                    MediaAttributes |= TrackMediaAttributes.Music | TrackMediaAttributes.VideoStream;
+                    break;
+                case IPod.MediaType.Movie:
+                    MediaAttributes |= TrackMediaAttributes.VideoStream | TrackMediaAttributes.Movie;
+                    break;
+                case IPod.MediaType.TVShow:
+                    MediaAttributes |= TrackMediaAttributes.VideoStream | TrackMediaAttributes.TvShow;
+                    break;
+                case IPod.MediaType.VideoPodcast:
+                    MediaAttributes |= TrackMediaAttributes.VideoStream | TrackMediaAttributes.Podcast;
+                    break;
+                case IPod.MediaType.Podcast:
+                    MediaAttributes |= TrackMediaAttributes.Podcast;
+                    // FIXME: persist URL on the track (track.PodcastUrl)
+                    break;
+                case IPod.MediaType.Audiobook:
+                    MediaAttributes |= TrackMediaAttributes.AudioBook;
+                    break;
+            }
+        }
+        
+        public void CommitToIpod (IPod.Device device)
+        {
+            IPod.Track track = device.TrackDatabase.CreateTrack ();
+
+            try {
+                track.Uri = new Uri (Uri.AbsoluteUri);
+            } catch (Exception e) {
+                Log.Exception ("Failed to create System.Uri for iPod track", e);
+                device.TrackDatabase.RemoveTrack (track);
+            }
+            
+            track.Duration = Duration;
+            track.PlayCount = PlayCount;
+            track.LastPlayed = LastPlayed;
+            track.DateAdded = DateAdded;
+            track.TotalTracks = TrackCount;
+            track.TrackNumber = TrackNumber;
+            track.Year = Year;
+            
+            if (!String.IsNullOrEmpty (AlbumTitle)) {
+                track.Album = AlbumTitle;
+            }
+            
+            if (!String.IsNullOrEmpty (ArtistName)) {
+                track.Artist = ArtistName;
+            }
+            
+            if (!String.IsNullOrEmpty (TrackTitle)) {
+                track.Title = TrackTitle;
+            }
+            
+            if (!String.IsNullOrEmpty (Genre)) {
+                track.Genre = Genre;
+            }
+            
+            switch (Rating) {
+                case 1: track.Rating = IPod.TrackRating.Zero; break;
+                case 2: track.Rating = IPod.TrackRating.Two; break;
+                case 3: track.Rating = IPod.TrackRating.Three; break;
+                case 4: track.Rating = IPod.TrackRating.Four; break;
+                case 5: track.Rating = IPod.TrackRating.Five; break;
+                default: track.Rating = IPod.TrackRating.Zero; break;
+            }
+            
+            if ((MediaAttributes & TrackMediaAttributes.VideoStream) != 0) {
+                if ((MediaAttributes & TrackMediaAttributes.Music) != 0) {
+                    track.Type = IPod.MediaType.MusicVideo;
+                } else if ((MediaAttributes & TrackMediaAttributes.Podcast) != 0) {
+                    track.Type = IPod.MediaType.VideoPodcast;
+                } else if ((MediaAttributes & TrackMediaAttributes.Movie) != 0) {
+                    track.Type = IPod.MediaType.Movie;
+                } else if ((MediaAttributes & TrackMediaAttributes.TvShow) != 0) {
+                    track.Type = IPod.MediaType.TVShow;
+                } else {
+                    track.Type = IPod.MediaType.Video;
+                }
+            } else {
+                if ((MediaAttributes & TrackMediaAttributes.Podcast) != 0) {
+                    track.Type = IPod.MediaType.Podcast;
+                } else if ((MediaAttributes & TrackMediaAttributes.AudioBook) != 0) {
+                    track.Type = IPod.MediaType.Audiobook;
+                } else if ((MediaAttributes & TrackMediaAttributes.Music) != 0) {
+                    track.Type = IPod.MediaType.Audio;
+                } else {
+                    track.Type = IPod.MediaType.Audio;
+                }
+            }
+            
+            if (CoverArtSpec.CoverExists (ArtistAlbumId)) {
+                SetIpodCoverArt (device, track, CoverArtSpec.GetPath (ArtistAlbumId));
+            }
+        }
+        
+        // FIXME: No reason for this to use GdkPixbuf - the file is on disk already in 
+        // the artwork cache as a JPEG, so just shove the bytes from disk into the track
+        
+        private void SetIpodCoverArt (IPod.Device device, IPod.Track track, string path)
+        {
+            try {
+                Gdk.Pixbuf pixbuf = new Gdk.Pixbuf (path);
+                if (pixbuf != null) {
+                    SetIpodCoverArt (device, track, IPod.ArtworkUsage.Cover, pixbuf);
+                    pixbuf.Dispose ();
+                }
+            } catch (Exception e) {
+                Log.Exception (String.Format ("Failed to set cover art on iPod from {0}", path), e);
+            }
+        }
+
+        private void SetIpodCoverArt (IPod.Device device, IPod.Track track, IPod.ArtworkUsage usage, Gdk.Pixbuf pixbuf)
+        {
+            foreach (IPod.ArtworkFormat format in device.LookupArtworkFormats (usage)) {
+                if (!track.HasCoverArt (format)) {
+                    track.SetCoverArt (format, IPod.ArtworkHelpers.ToBytes (format, pixbuf));
+                }
             }
         }
     }



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