banshee r3883 - in trunk/banshee: . src/Core/Banshee.ThickClient/Banshee.Sources.Gui src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod
- From: abock svn gnome org
- To: svn-commits-list gnome org
- Subject: banshee r3883 - in trunk/banshee: . src/Core/Banshee.ThickClient/Banshee.Sources.Gui src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod
- Date: Tue, 6 May 2008 03:40:40 +0100 (BST)
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]