[banshee/gio-hardware] Create a new extension which will handle all Apple based DAPs using libgpod.



commit 1738bd109c3d1cb87de1a3edf6df1dc3dccc0023
Author: Alan McGovern <alan mcgovern gmail com>
Date:   Wed Jul 21 00:07:21 2010 +0100

    Create a new extension which will handle all Apple based DAPs using libgpod.

 build/build.environment.mk                         |    5 +
 configure.ac                                       |    3 +
 po/POTFILES.in                                     |    1 +
 .../Banshee.Dap.AppleDevice.addin.xml              |   27 +
 .../Banshee.Dap.AppleDevice.csproj                 |  106 ++++
 .../Banshee.Dap.AppleDevice/AppleDeviceProvider.cs |   53 ++
 .../Banshee.Dap.AppleDevice/AppleDeviceSource.cs   |  629 ++++++++++++++++++++
 .../AppleDeviceTrackInfo.cs                        |  290 +++++++++
 src/Dap/Banshee.Dap.AppleDevice/Makefile.am        |   31 +
 src/Dap/Makefile.am                                |    1 +
 10 files changed, 1146 insertions(+), 0 deletions(-)
---
diff --git a/build/build.environment.mk b/build/build.environment.mk
index 7c4eeb2..7862a74 100644
--- a/build/build.environment.mk
+++ b/build/build.environment.mk
@@ -70,6 +70,10 @@ REF_MTP = $(LINK_SYSTEM) $(LINK_MONO_POSIX)
 LINK_MTP = -r:$(DIR_BIN)/Mtp.dll
 LINK_MTP_DEPS = $(REF_MTP) $(LINK_MTP)
 
+# AppleDevice
+REF_APPLEDEVICE = $(LINK_SYSTEM)
+LINK_APPLEDEVICE_DEPS = $(REF_APPLEDEVICE) $(LIBGPODSHARP_LIBS)
+
 # Karma
 REF_KARMA = $(LINK_SYSTEM) $(LINK_MONO_POSIX)
 LINK_KARMA = $(KARMASHARP_LIBS)
@@ -116,6 +120,7 @@ REF_BANSHEE_COLLECTIONINDEXER = $(LINK_SYSTEM) $(LINK_DBUS_NO_GLIB) $(LINK_MONO_
 REF_DAP = $(LINK_BANSHEE_SERVICES_DEPS) $(LINK_BANSHEE_THICKCLIENT_DEPS)
 LINK_DAP = -r:$(DIR_BIN)/Banshee.Dap.dll
 LINK_DAP_DEPS = $(REF_DAP) $(LINK_DAP)
+REF_DAP_APPLEDEVICE = $(LINK_DAP_DEPS) $(LINK_APPLEDEVICE_DEPS)
 REF_DAP_MASS_STORAGE = $(LINK_DAP_DEPS)
 REF_DAP_MTP = $(LINK_DAP_DEPS) $(LINK_MTP_DEPS)
 REF_DAP_IPOD = $(LINK_DAP_DEPS) $(LINK_IPOD)
diff --git a/configure.ac b/configure.ac
index b038b60..54148f9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -161,6 +161,7 @@ fi
 
 dnl DAP support (each module is optional)
 BANSHEE_CHECK_DAP_MTP
+BANSHEE_CHECK_DAP_APPLEDEVICE
 BANSHEE_CHECK_DAP_IPOD
 BANSHEE_CHECK_DAP_KARMA
 
@@ -326,6 +327,7 @@ src/Libraries/MusicBrainz/Makefile
 
 src/Dap/Makefile
 src/Dap/Banshee.Dap/Makefile
+src/Dap/Banshee.Dap.AppleDevice/Makefile
 src/Dap/Banshee.Dap.Ipod/Makefile
 src/Dap/Banshee.Dap.MassStorage/Makefile
 src/Dap/Banshee.Dap.Mtp/Makefile
@@ -393,6 +395,7 @@ ${PACKAGE}-${VERSION}
   Digital Audio Player (DAP) Support:
     Mass Storage:      yes
     MTP:               ${enable_libmtp}
+    Apple Device:      ${enable_appledevice}
     iPod:              ${enable_ipodsharp}
     Karma:             ${enable_karmasharp}
 
diff --git a/po/POTFILES.in b/po/POTFILES.in
index f61bfd4..04d9575 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -149,6 +149,7 @@ src/Core/Banshee.Widgets/Banshee.Widgets/DiscUsageDisplay.cs
 src/Core/Banshee.Widgets/Banshee.Widgets/SeekSlider.cs
 src/Core/Banshee.Widgets/Banshee.Widgets/StreamPositionLabel.cs
 src/Core/Banshee.Widgets/Banshee.Widgets/VolumeButton.cs
+src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice/AppleDeviceSource.cs
 src/Dap/Banshee.Dap/Banshee.Dap.addin.xml
 src/Dap/Banshee.Dap/Banshee.Dap/DapLibrarySync.cs
 src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs
diff --git a/src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice.addin.xml b/src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice.addin.xml
new file mode 100644
index 0000000..5c9a5b0
--- /dev/null
+++ b/src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice.addin.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Addin
+    id="Banshee.Dap.AppleDevice"
+    version="0.1"
+    compatVersion="0.1"
+    copyright="© 2010 Novell Inc. Licensed under the MIT X11 license."
+    name="Apple device Support"
+    category="Device Support"
+    description="Support for most iPod/iPhone/iPad devices."
+    author="Alan McGovern"
+    url="http://banshee.fm/";
+    defaultEnabled="true">
+
+  <Dependencies>
+    <Addin id="Banshee.Services" version="1.0"/>
+    <Addin id="Banshee.Dap" version="1.0"/>
+  </Dependencies>
+
+  <Extension path="/Banshee/Platform/HardwareDeviceProvider">
+    <HardwareDeviceProvider class="Banshee.Dap.AppleDevice.AppleDeviceProvider"/>
+  </Extension>
+  
+  <Extension path="/Banshee/Dap/DeviceClass">
+    <DeviceClass class="Banshee.Dap.AppleDevice.AppleDeviceSource" priority="10"/>
+  </Extension>
+
+</Addin>
diff --git a/src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice.csproj b/src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice.csproj
new file mode 100644
index 0000000..40c55af
--- /dev/null
+++ b/src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice.csproj
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"; ToolsVersion="3.5">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.50727</ProductVersion>
+    <ProjectGuid>{DEADBEEF-CAFE-BABE-FACE-000C0FFEE000}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AssemblyName>Banshee.Dap.AppleDevice</AssemblyName>
+    <SchemaVersion>2.0</SchemaVersion>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <Optimize>true</Optimize>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ReleaseVersion>1.3</ReleaseVersion>
+    <RootNamespace>Banshee.Dap.AppleDevice</RootNamespace>
+    <AssemblyOriginatorKeyFile>.</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <WarningLevel>4</WarningLevel>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\bin</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Windows|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <WarningLevel>4</WarningLevel>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\bin</OutputPath>
+  </PropertyGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\Core\Banshee.Core\Banshee.Core.csproj">
+      <Project>{2ADB831A-A050-47D0-B6B9-9C19D60233BB}</Project>
+      <Name>Banshee.Core</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\Core\Banshee.Services\Banshee.Services.csproj">
+      <Project>{B28354F0-BA87-44E8-989F-B864A3C7C09F}</Project>
+      <Name>Banshee.Services</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\Libraries\Hyena\Hyena.csproj">
+      <Project>{95374549-9553-4C1E-9D89-667755F90E12}</Project>
+      <Name>Hyena</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Banshee.Dap\Banshee.Dap.csproj">
+      <Project>{BC2E94DF-7A82-461E-BE7C-60E41ADC3562}</Project>
+      <Name>Banshee.Dap</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\Libraries\Hyena.Gui\Hyena.Gui.csproj">
+      <Project>{C856EFD8-E812-4E61-8B76-E3583D94C233}</Project>
+      <Name>Hyena.Gui</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\Core\Banshee.ThickClient\Banshee.ThickClient.csproj">
+      <Project>{AC839523-7BDF-4AB6-8115-E17921B96EC6}</Project>
+      <Name>Banshee.ThickClient</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\Core\Banshee.Widgets\Banshee.Widgets.csproj">
+      <Project>{A3701765-E571-413D-808C-9788A22791AF}</Project>
+      <Name>Banshee.Widgets</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="Mono.Posix">
+      <SpecificVersion>False</SpecificVersion>
+    </Reference>
+    <Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+    <Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+    <Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+    <Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+    <Reference Include="taglib-sharp, Version=2.0.3.6, Culture=neutral, PublicKeyToken=db62eba44689b5b0">
+      <HintPath>..\..\..\bin\taglib-sharp.dll</HintPath>
+    </Reference>
+    <Reference Include="libgpod-sharp, Version=1.0.3824.40135, Culture=neutral">
+      <Package>libgpod-sharp</Package>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Banshee.Dap.AppleDevice.addin.xml">
+      <LogicalName>Banshee.Dap.AppleDevice.addin.xml</LogicalName>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Banshee.Dap.AppleDevice\AppleDeviceSource.cs" />
+    <Compile Include="Banshee.Dap.AppleDevice\AppleDeviceProvider.cs" />
+    <Compile Include="Banshee.Dap.AppleDevice\AppleDeviceTrackInfo.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ProjectExtensions>
+    <MonoDevelop>
+      <Properties>
+        <MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="true" RelativeMakefileName="./Makefile.am">
+          <BuildFilesVar Sync="true" Name="SOURCES" />
+          <DeployFilesVar />
+          <ResourcesVar Sync="true" Name="RESOURCES" />
+          <OthersVar />
+          <GacRefVar />
+          <AsmRefVar />
+          <ProjectRefVar />
+        </MonoDevelop.Autotools.MakefileInfo>
+      </Properties>
+    </MonoDevelop>
+  </ProjectExtensions>
+</Project>
diff --git a/src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice/AppleDeviceProvider.cs b/src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice/AppleDeviceProvider.cs
new file mode 100644
index 0000000..7165868
--- /dev/null
+++ b/src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice/AppleDeviceProvider.cs
@@ -0,0 +1,53 @@
+//
+// AppleDeviceProvider.cs
+//
+// Author:
+//   Alan McGovern <amcgovern novell com>
+//
+// Copyright (C) 2010 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using Banshee.Hardware;
+
+namespace Banshee.Dap.AppleDevice
+{
+    public class AppleDeviceProvider : ICustomDeviceProvider
+    {
+        public T GetCustomDevice<T> (T device) where T : class, IDevice
+        {
+            // Do i even need this?
+//            IVolume volume = device as IVolume;
+//
+//            if (volume != null && volume.FileSystem == "afc") {
+//                return new AppleDeviceDevice (volume);
+//            }
+
+            return device;
+        }
+
+        public void Dispose ()
+        {
+
+        }
+    }
+}
diff --git a/src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice/AppleDeviceSource.cs b/src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice/AppleDeviceSource.cs
new file mode 100644
index 0000000..5f718bb
--- /dev/null
+++ b/src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice/AppleDeviceSource.cs
@@ -0,0 +1,629 @@
+//
+// AppleDeviceSource.cs
+//
+// Author:
+//   Alan McGovern <amcgovern novell com>
+//
+// Copyright (C) 2010 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using Banshee.Base;
+using Banshee.Collection.Database;
+using Banshee.ServiceStack;
+using Banshee.Library;
+using System.Collections.Generic;
+using System.Threading;
+using Banshee.Hardware;
+using Banshee.Sources;
+using Banshee.I18n;
+using Hyena;
+
+namespace Banshee.Dap.AppleDevice
+{
+    public class AppleDeviceSource : DapSource
+    {
+        GPod.Device Device {
+            get; set;
+        }
+
+        IVolume Volume {
+            get; set;
+        }
+
+        GPod.ITDB MediaDatabase {
+            get; set;
+        }
+
+        string MountPoint {
+            get { return Device.Mountpoint; }
+        }
+
+        private Dictionary<int, AppleDeviceTrackInfo> tracks_map = new Dictionary<int, AppleDeviceTrackInfo> (); // FIXME: EPIC FAIL
+
+        //private UnsupportedDatabaseView unsupported_view;
+
+#region Device Setup/Dispose
+
+        public override void DeviceInitialize (IDevice device)
+        {
+            Volume = device as IVolume;
+            if (Volume == null || Volume.FileSystem != "afc")
+                throw new InvalidDeviceException ();
+
+            base.DeviceInitialize (device);
+
+            Device = new GPod.Device (Volume.MountPoint);
+
+            // FIXME: Set name properly using libgpod.
+            // FIXME: How do we detect if playlists are supported?
+            Name = Volume.Name;
+            SupportsPlaylists = true;
+            SupportsPodcasts = Device.SupportsPodcast;
+            SupportsVideo = Device.SupportsVideo;
+
+            Initialize ();
+
+            // FIXME: Properly parse the device, color and generation and don't use the fallback strings
+            AddDapProperty (Catalog.GetString ("Device"), Device.IpodInfo.ModelString);
+            AddDapProperty (Catalog.GetString ("Color"), "black");
+            AddDapProperty (Catalog.GetString ("Generation"), Device.IpodInfo.GenerationString);
+            AddDapProperty (Catalog.GetString ("Capacity"), string.Format ("{0:0.00}GB", BytesCapacity));
+            AddDapProperty (Catalog.GetString ("Avaiable"), string.Format ("{0:0.00}GB", BytesAvailable));
+            AddDapProperty (Catalog.GetString ("Serial number"), Volume.Serial);
+            //AddDapProperty (Catalog.GetString ("Produced on"), ipod_device.ProductionInfo.DisplayDate);
+            //AddDapProperty (Catalog.GetString ("Firmware"), ipod_device.FirmwareVersion);
+
+            //string [] capabilities = new string [ipod_device.ModelInfo.Capabilities.Count];
+            //ipod_device.ModelInfo.Capabilities.CopyTo (capabilities, 0);
+            //AddDapProperty (Catalog.GetString ("Capabilities"), String.Join (", ", capabilities));
+            AddYesNoDapProperty (Catalog.GetString ("Supports cover art"), Device.SupportsArtwork);
+            AddYesNoDapProperty (Catalog.GetString ("Supports photos"), Device.SupportsPhoto);
+        }
+
+        public override void Dispose ()
+        {
+            //ThreadAssist.ProxyToMain (DestroyUnsupportedView);
+            CancelSyncThread ();
+            base.Dispose ();
+        }
+
+        // WARNING: This will be called from a thread!
+        protected override void Eject ()
+        {
+            base.Eject ();
+            CancelSyncThread ();
+            if (Volume.CanUnmount)
+                Volume.Unmount ();
+            if (Volume.CanEject)
+                Volume.Eject ();
+
+            Dispose ();
+        }
+
+        protected override bool CanHandleDeviceCommand (DeviceCommand command)
+        {
+            // Whats this for?
+            return false;
+//            try {
+//                SafeUri uri = new SafeUri (command.DeviceId);
+//                return IpodDevice.MountPoint.StartsWith (uri.LocalPath);
+//            } catch {
+//                return false;
+//            }
+        }
+
+#endregion
+
+#region Database Loading
+
+        // WARNING: This will be called from a thread!
+        protected override void LoadFromDevice ()
+        {
+            LoadFromDevice (false);
+            OnTracksAdded ();
+        }
+
+        private int CountMusicFiles ()
+        {
+            return 0;
+//            try {
+//                int file_count = 0;
+//
+//                DirectoryInfo m_dir = new DirectoryInfo (Path.Combine (ipod_device.ControlPath, "Music"));
+//                foreach (DirectoryInfo f_dir in m_dir.GetDirectories ()) {
+//                    file_count += f_dir.GetFiles().Length;
+//                }
+//
+//                return file_count;
+//            } catch {
+//                return 0;
+//            }
+        }
+
+        private void LoadFromDevice (bool refresh)
+        {
+            tracks_map.Clear ();
+            if (refresh || MediaDatabase  == null) {
+                if (MediaDatabase != null)
+                    MediaDatabase.Dispose ();
+
+                MediaDatabase = new GPod.ITDB (MountPoint);
+            }
+
+            foreach (var ipod_track in MediaDatabase.Tracks) {
+                try {
+                    var track = new AppleDeviceTrackInfo (ipod_track);
+                    track.PrimarySource = this;
+                    track.Save (false);
+                    tracks_map.Add (track.TrackId, track);
+                } catch (Exception e) {
+                    Log.Exception (e);
+                    Console.WriteLine (e);
+                }
+            }
+
+//                Hyena.Data.Sqlite.HyenaSqliteCommand insert_cmd = new Hyena.Data.Sqlite.HyenaSqliteCommand (
+//                    @"INSERT INTO CorePlaylistEntries (PlaylistID, TrackID)
+//                        SELECT ?, TrackID FROM CoreTracks WHERE PrimarySourceID = ? AND ExternalID = ?");
+//                foreach (IPod.Playlist playlist in ipod_device.TrackDatabase.Playlists) {
+//                    if (playlist.IsOnTheGo) { // || playlist.IsPodcast) {
+//                        continue;
+//                    }
+//                    PlaylistSource pl_src = new PlaylistSource (playlist.Name, this);
+//                    pl_src.Save ();
+//                    // We use the IPod.Track.Id here b/c we just shoved it into ExternalID above when we loaded
+//                    // the tracks, however when we sync, the Track.Id values may/will change.
+//                    foreach (IPod.Track track in playlist.Tracks) {
+//                        ServiceManager.DbConnection.Execute (insert_cmd, pl_src.DbId, this.DbId, track.Id);
+//                    }
+//                    pl_src.UpdateCounts ();
+//                    AddChildSource (pl_src);
+//                }
+            /*else {
+                BuildDatabaseUnsupportedWidget ();
+            }*/
+
+            /*if(previous_database_supported != database_supported) {
+                OnPropertiesChanged();
+            }*/
+        }
+
+        private void OnRebuildDatabaseRefresh (object o, EventArgs args)
+        {
+            ServiceManager.SourceManager.SetActiveSource (MusicGroupSource);
+            base.LoadDeviceContents ();
+        }
+
+//        private void DestroyUnsupportedView ()
+//        {
+//            if (unsupported_view != null) {
+//                unsupported_view.Refresh -= OnRebuildDatabaseRefresh;
+//                unsupported_view.Destroy ();
+//                unsupported_view = null;
+//            }
+//        }
+
+#endregion
+
+#region Source Cosmetics
+
+        internal string [] _GetIconNames ()
+        {
+            return GetIconNames ();
+        }
+
+        protected override string [] GetIconNames ()
+        {
+            string [] names = new string[4];
+            string prefix = "multimedia-player-";
+            string shell_color = "green";
+
+            names[0] = "";
+            names[2] = "ipod-standard-color";
+            names[3] = "multimedia-player";
+
+            switch ("grayscale") {
+                case "grayscale":
+                    names[1] = "ipod-standard-monochrome";
+                    break;
+                case "color":
+                    names[1] = "ipod-standard-color";
+                    break;
+                case "mini":
+                    names[1] = String.Format ("ipod-mini-{0}", shell_color);
+                    names[2] = "ipod-mini-silver";
+                    break;
+                case "shuffle":
+                    names[1] = String.Format ("ipod-shuffle-{0}", shell_color);
+                    names[2] = "ipod-shuffle";
+                    break;
+                case "nano":
+                case "nano3":
+                    names[1] = String.Format ("ipod-nano-{0}", shell_color);
+                    names[2] = "ipod-nano-white";
+                    break;
+                case "video":
+                    names[1] = String.Format ("ipod-video-{0}", shell_color);
+                    names[2] = "ipod-video-white";
+                    break;
+                case "classic":
+                case "touch":
+                case "phone":
+                default:
+                    break;
+            }
+
+            names[1] = names[1] ?? names[2];
+            names[1] = prefix + names[1];
+            names[2] = prefix + names[2];
+
+            return names;
+        }
+
+        public override void Rename (string name)
+        {
+            return;
+//            if (!CanRename) {
+//                return;
+//            }
+//
+//            try {
+//                if (name_path != null) {
+//                    Directory.CreateDirectory (Path.GetDirectoryName (name_path));
+//
+//                    using (StreamWriter writer = new StreamWriter (File.Open (name_path, FileMode.Create),
+//                        System.Text.Encoding.Unicode)) {
+//                        writer.Write (name);
+//                    }
+//                }
+//            } catch (Exception e) {
+//                Log.Exception (e);
+//            }
+//
+//            ipod_device.Name = name;
+//            base.Rename (name);
+        }
+
+        public override bool CanRename {
+            get { return !(IsAdding || IsDeleting || IsReadOnly); }
+        }
+
+        public override long BytesUsed {
+            get { return (long) Volume.Capacity - Volume.Available; }
+        }
+
+        public override long BytesCapacity {
+            get { return (long) Volume.Capacity; }
+        }
+
+#endregion
+
+#region Syncing
+
+        protected override void OnTracksAdded ()
+        {
+            if (!IsAdding && tracks_to_add.Count > 0 && !Sync.Syncing) {
+                QueueSync ();
+            }
+            base.OnTracksAdded ();
+        }
+
+        protected override void OnTracksDeleted ()
+        {
+            if (!IsDeleting && tracks_to_remove.Count > 0 && !Sync.Syncing) {
+                QueueSync ();
+            }
+            base.OnTracksDeleted ();
+        }
+
+        private Queue<AppleDeviceTrackInfo> tracks_to_add = new Queue<AppleDeviceTrackInfo> ();
+        private Queue<AppleDeviceTrackInfo> tracks_to_remove = new Queue<AppleDeviceTrackInfo> ();
+
+        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 AcceptsInputFromSource (Source source)
+        {
+            Console.WriteLine ("AcceptsInputFromSource: {0}", base.AcceptsInputFromSource(source));
+            return base.AcceptsInputFromSource (source);
+        }
+        public override bool CanAddTracks {
+            get {
+                Console.WriteLine ("Can add: {0}", base.CanAddTracks);
+                return base.CanAddTracks;
+            }
+        }
+        public override bool IsReadOnly {
+            get { return false; }//!database_supported; }
+        }
+
+        public override void Import ()
+        {
+            Banshee.ServiceStack.ServiceManager.Get<LibraryImportManager> ().Enqueue (GPod.ITDB.GetMusicPath (MountPoint));
+        }
+
+        public override void CopyTrackTo (DatabaseTrackInfo track, SafeUri uri, BatchUserJob job)
+        {
+            Banshee.IO.File.Copy (track.Uri, uri, false);
+        }
+
+        protected override bool DeleteTrack (DatabaseTrackInfo track)
+        {
+            lock (sync_mutex) {
+                if (!tracks_map.ContainsKey (track.TrackId)) {
+                    return true;
+                }
+
+                var ipod_track = tracks_map[track.TrackId];
+                if (ipod_track != null) {
+                    tracks_to_remove.Enqueue (ipod_track);
+                }
+
+                return true;
+            }
+        }
+
+        protected override void AddTrackToDevice (DatabaseTrackInfo track, SafeUri fromUri)
+        {
+            lock (sync_mutex) {
+                if (track.PrimarySourceId == DbId) {
+                    return;
+                }
+
+                if (track.Duration.Equals (TimeSpan.Zero)) {
+                    throw new Exception (Catalog.GetString ("Track duration is zero"));
+                }
+
+                AppleDeviceTrackInfo ipod_track = new AppleDeviceTrackInfo (track);
+                ipod_track.Uri = fromUri;
+                ipod_track.PrimarySource = this;
+                ipod_track.Save (false);
+
+                tracks_to_add.Enqueue (ipod_track);
+            }
+        }
+
+        public override void SyncPlaylists ()
+        {
+            if (!IsReadOnly && Monitor.TryEnter (sync_mutex)) {
+                PerformSync ();
+                Monitor.Exit (sync_mutex);
+            }
+        }
+
+        private void QueueSync ()
+        {
+            lock (sync_timeout_mutex) {
+                if (sync_timeout_id > 0) {
+                    Application.IdleTimeoutRemove (sync_timeout_id);
+                }
+
+                sync_timeout_id = Application.RunTimeout (150, PerformSync);
+            }
+        }
+
+        private void CancelSyncThread ()
+        {
+            Thread thread = sync_thread;
+            lock (sync_mutex) {
+                if (sync_thread != null && sync_thread_wait != null) {
+                    sync_thread_dispose = true;
+                    sync_thread_wait.Set ();
+                }
+            }
+
+            if (thread != null) {
+                thread.Join ();
+            }
+        }
+
+        private bool PerformSync ()
+        {
+            lock (sync_mutex) {
+                if (sync_thread == null) {
+                    sync_thread_wait = new AutoResetEvent (false);
+
+                    sync_thread = new Thread (new ThreadStart (PerformSyncThread));
+                    sync_thread.Name = "iPod Sync Thread";
+                    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 ()
+        {
+            try {
+                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;
+                }
+            } catch (Exception e) {
+                Log.Exception (e);
+            }
+        }
+
+        private void PerformSyncThreadCycle ()
+        {
+            OnIpodDatabaseSaveStarted (this, EventArgs.Empty);
+            while (tracks_to_add.Count > 0) {
+                AppleDeviceTrackInfo track = null;
+                lock (sync_mutex) {
+                    track = tracks_to_add.Dequeue ();
+                }
+
+                try {
+                    OnIpodDatabaseSaveProgressChanged (this, EventArgs.Empty);
+                    track.CommitToIpod (MediaDatabase);
+                    tracks_map[track.TrackId] = track;
+                } catch (Exception e) {
+                    Log.Exception ("Cannot save track to iPod", e);
+                }
+            }
+
+            // TODO sync updated metadata to changed tracks
+
+            while (tracks_to_remove.Count > 0) {
+                AppleDeviceTrackInfo track = null;
+                lock (sync_mutex) {
+                    track = tracks_to_remove.Dequeue ();
+                }
+
+                if (tracks_map.ContainsKey (track.TrackId)) {
+                    tracks_map.Remove (track.TrackId);
+                }
+
+                try {
+                    if (track.IpodTrack != null) {
+                        OnIpodDatabaseSaveProgressChanged (this, EventArgs.Empty);
+                        Console.WriteLine ("Removing them from the list");
+                        foreach (var playlist in MediaDatabase.Playlists)
+                            playlist.Tracks.Remove (track.IpodTrack);
+                        MediaDatabase.MasterPlaylist.Tracks.Remove (track.IpodTrack);
+                        MediaDatabase.Tracks.Remove (track.IpodTrack);
+                        Banshee.IO.File.Delete (new SafeUri (GPod.ITDB.GetLocalPath (MountPoint, track.IpodTrack)));
+                        Console.WriteLine ("Removed them from the list");
+                    } else {
+                        Console.WriteLine ("The ipod track was null. Darn!");
+                    }
+                } catch (Exception e) {
+                    Log.Exception ("Cannot remove track from iPod", e);
+                }
+            }
+
+//            // Remove playlists on the device
+//            List<IPod.Playlist> device_playlists = new List<IPod.Playlist> (ipod_device.TrackDatabase.Playlists);
+//            foreach (IPod.Playlist playlist in device_playlists) {
+//                if (!playlist.IsOnTheGo) {
+//                    ipod_device.TrackDatabase.RemovePlaylist (playlist);
+//                }
+//            }
+//            device_playlists.Clear ();
+//
+//            if (SupportsPlaylists) {
+//                // Add playlists from Banshee to the device
+//                foreach (Source child in Children) {
+//                    PlaylistSource from = child as PlaylistSource;
+//                    if (from != null && from.Count > 0) {
+//                        IPod.Playlist playlist = ipod_device.TrackDatabase.CreatePlaylist (from.Name);
+//                        foreach (int track_id in ServiceManager.DbConnection.QueryEnumerable<int> (String.Format (
+//                            "SELECT CoreTracks.TrackID FROM {0} WHERE {1}",
+//                            from.DatabaseTrackModel.ConditionFromFragment, from.DatabaseTrackModel.Condition)))
+//                        {
+//                            if (tracks_map.ContainsKey (track_id)) {
+//                                playlist.AddTrack (tracks_map[track_id].IpodTrack);
+//                            }
+//                        }
+//                    }
+//                }
+//            }
+
+            try {
+//                ipod_device.TrackDatabase.SaveStarted += OnIpodDatabaseSaveStarted;
+//                ipod_device.TrackDatabase.SaveEnded += OnIpodDatabaseSaveEnded;
+//                ipod_device.TrackDatabase.SaveProgressChanged += OnIpodDatabaseSaveProgressChanged;
+                MediaDatabase.Write ();
+                Console.WriteLine ("Wrote database");
+            } catch (Exception e) {
+                Log.Exception ("Failed to save iPod database", e);
+            } finally {
+                OnIpodDatabaseSaveEnded (this, EventArgs.Empty);
+//                ipod_device.TrackDatabase.SaveStarted -= OnIpodDatabaseSaveStarted;
+//                ipod_device.TrackDatabase.SaveEnded -= OnIpodDatabaseSaveEnded;
+//                ipod_device.TrackDatabase.SaveProgressChanged -= OnIpodDatabaseSaveProgressChanged;
+            }
+        }
+
+        private UserJob sync_user_job;
+
+        private void OnIpodDatabaseSaveStarted (object o, EventArgs args)
+        {
+            DisposeSyncUserJob ();
+
+            sync_user_job = new UserJob (Catalog.GetString ("Syncing iPod"),
+                Catalog.GetString ("Preparing to synchronize..."), GetIconNames ());
+            sync_user_job.Register ();
+        }
+
+        private void OnIpodDatabaseSaveEnded (object o, EventArgs args)
+        {
+            DisposeSyncUserJob ();
+        }
+
+        private void DisposeSyncUserJob ()
+        {
+            if (sync_user_job != null) {
+                sync_user_job.Finish ();
+                sync_user_job = null;
+            }
+        }
+
+        private void OnIpodDatabaseSaveProgressChanged (object o, EventArgs args)
+        {
+            string message = string.Format ("Copying track {0} of {1}", 1, tracks_to_add.Count + tracks_to_remove.Count);
+            double progress = 1.0 / (tracks_to_add.Count + tracks_to_remove.Count);
+             if (progress >= 0.99) {
+                 sync_user_job.Status = Catalog.GetString ("Flushing to disk...");
+                 sync_user_job.Progress = 0;
+             } else {
+                 sync_user_job.Status = message;
+                 sync_user_job.Progress = progress;
+             }
+        }
+
+        public bool SyncNeeded {
+            get {
+                lock (sync_mutex) {
+                    return tracks_to_add.Count > 0 || tracks_to_remove.Count > 0;
+                }
+            }
+        }
+
+#endregion
+
+    }
+}
diff --git a/src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice/AppleDeviceTrackInfo.cs b/src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice/AppleDeviceTrackInfo.cs
new file mode 100644
index 0000000..62a8a01
--- /dev/null
+++ b/src/Dap/Banshee.Dap.AppleDevice/Banshee.Dap.AppleDevice/AppleDeviceTrackInfo.cs
@@ -0,0 +1,290 @@
+// 
+// AppleDeviceTrackInfo.cs
+// 
+// Author:
+//   Alan McGovern <amcgovern novell com>
+// 
+// Copyright (c) 2010 Moonlight Team
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+
+using Banshee.Base;
+using Banshee.Streaming;
+using Banshee.Collection;
+using Banshee.Collection.Database;
+
+using Hyena;
+
+namespace Banshee.Dap.AppleDevice
+{
+    public class AppleDeviceTrackInfo : DatabaseTrackInfo
+    {
+        internal GPod.Track IpodTrack {
+            get; set;
+        }
+
+        // Used for podcasts only
+        //private string description;
+
+        public AppleDeviceTrackInfo (GPod.Track track)
+        {
+            IpodTrack = track;
+            LoadFromIpodTrack ();
+            CanSaveToDatabase = true;
+        }
+
+        public AppleDeviceTrackInfo (TrackInfo track)
+        {
+            if (track is AppleDeviceTrackInfo) {
+                IpodTrack = ((AppleDeviceTrackInfo)track).IpodTrack;
+                LoadFromIpodTrack ();
+            } else {
+                AlbumArtist = track.AlbumArtist;
+                AlbumTitle = track.AlbumTitle;
+                ArtistName = track.ArtistName;
+                BitRate = track.BitRate;
+                SampleRate = track.SampleRate;
+                Bpm = track.Bpm;
+                Comment = track.Comment;
+                Composer = track.Composer;
+                Conductor = track.Conductor;
+                Copyright = track.Copyright;
+                DateAdded = track.DateAdded;
+                DiscCount = track.DiscCount;
+                DiscNumber = track.DiscNumber;
+                Duration = track.Duration;
+                FileSize = track.FileSize;
+                Genre = track.Genre;
+                Grouping = track.Grouping;
+                IsCompilation = track.IsCompilation ;
+                LastPlayed = track.LastPlayed;
+                LastSkipped = track.LastSkipped;
+                PlayCount = track.PlayCount;
+                Rating = track.Rating;
+                ReleaseDate = track.ReleaseDate;
+                SkipCount = track.SkipCount;
+                TrackCount = track.TrackCount;
+                TrackNumber = track.TrackNumber;
+                TrackTitle = track.TrackTitle;
+                Year = track.Year;
+                MediaAttributes = track.MediaAttributes;
+
+                var podcast_info = track.ExternalObject as IPodcastInfo;
+                if (podcast_info != null) {
+                    //description = podcast_info.Description;
+                    ReleaseDate = podcast_info.ReleaseDate;
+                }
+            }
+
+            CanSaveToDatabase = true;
+        }
+
+        private void LoadFromIpodTrack ()
+        {
+            var track = IpodTrack;
+            try {
+                Uri = new SafeUri (System.IO.Path.Combine (track.ITDB.Mountpoint, track.IpodPath.Replace (":", System.IO.Path.DirectorySeparatorChar.ToString ()).Substring (1)));
+            } catch (Exception ex) {
+                Console.WriteLine (ex);
+                Uri = null;
+            }
+
+            ExternalId = (long) track.DBID;
+
+            AlbumArtist = track.AlbumArtist;
+            AlbumTitle = String.IsNullOrEmpty (track.Album) ? null : track.Album;
+            ArtistName = String.IsNullOrEmpty (track.Artist) ? null : track.Artist;
+            BitRate = track.Bitrate;
+            SampleRate = track.Samplerate;
+            Bpm = (int)track.BPM;
+            Comment = track.Comment;
+            Composer = track.Composer;
+            DateAdded = track.TimeAdded;
+            DiscCount = track.CDs;
+            DiscNumber = track.CDNumber;
+            Duration = TimeSpan.FromMilliseconds (track.TrackLength);
+            FileSize = track.Size;
+            Genre = String.IsNullOrEmpty (track.Genre) ? null : track.Genre;
+            Grouping = track.Grouping;
+            IsCompilation = track.Compilation;
+            LastPlayed = track.TimePlayed;
+            PlayCount = (int) track.PlayCount;
+            TrackCount = track.Tracks;
+            TrackNumber = track.TrackNumber;
+            TrackTitle = String.IsNullOrEmpty (track.Title) ? null : track.Title;
+            Year = track.Year;
+            //description = track.Description;
+            ReleaseDate = track.TimeReleased;
+
+            rating = track.Rating > 5 ? 0 : (int) track.Rating;
+
+            if (track.DRMUserID > 0) {
+                PlaybackError = StreamPlaybackError.Drm;
+            }
+
+            MediaAttributes = TrackMediaAttributes.AudioStream | TrackMediaAttributes.Music;
+
+//            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 (GPod.ITDB database)
+        {
+            bool addTrack = IpodTrack == null;
+            Console.WriteLine ("Committing a track to {0}", database);
+            if (IpodTrack == null) {
+                IpodTrack = new GPod.Track ();
+            }
+
+            var track = IpodTrack;
+            track.AlbumArtist = AlbumArtist;
+            track.Bitrate = BitRate;
+            track.Samplerate= (ushort)SampleRate;
+            track.BPM = (short)Bpm;
+            track.Comment = Comment;
+            track.Composer = Composer;
+            track.TimeAdded = DateAdded;
+            track.CDs = DiscCount;
+            track.CDNumber = DiscNumber;
+            track.TrackLength = (int) Duration.TotalMilliseconds;
+            track.Size = (int)FileSize;
+            track.Grouping = Grouping;
+            track.Compilation = IsCompilation;
+            track.TimePlayed = LastPlayed;
+            track.PlayCount = (uint) PlayCount;
+            track.Tracks = TrackCount;
+            track.TrackNumber = TrackNumber;
+            track.Year = Year;
+            track.TimeReleased = ReleaseDate;
+
+            track.Album = AlbumTitle;
+            track.Artist = ArtistName;
+            track.Title = TrackTitle;
+            track.Genre = Genre;
+
+            switch (Rating) {
+            case 1:
+            case 2:
+            case 3:
+            case 4:
+            case 5:
+                track.Rating = (uint) rating;
+                break;
+            default: track.Rating = 0;
+                break;
+            }
+
+//            if (HasAttribute (TrackMediaAttributes.Podcast)) {
+//                track.DateReleased = ReleaseDate;
+//                track.Description = description;
+//                track.RememberPosition = true;
+//                track.NotPlayedMark = track.PlayCount == 0;
+//            }
+//
+//            if (HasAttribute (TrackMediaAttributes.VideoStream)) {
+//                if (HasAttribute (TrackMediaAttributes.Podcast)) {
+//                    track.Type = IPod.MediaType.VideoPodcast;
+//                } else if (HasAttribute (TrackMediaAttributes.Music)) {
+//                    track.Type = IPod.MediaType.MusicVideo;
+//                } else if (HasAttribute (TrackMediaAttributes.Movie)) {
+//                    track.Type = IPod.MediaType.Movie;
+//                } else if (HasAttribute (TrackMediaAttributes.TvShow)) {
+//                    track.Type = IPod.MediaType.TVShow;
+//                } else {
+//                    track.Type = IPod.MediaType.Video;
+//                }
+//            } else {
+//                if (HasAttribute (TrackMediaAttributes.Podcast)) {
+//                    track.Type = IPod.MediaType.Podcast;
+//                } else if (HasAttribute (TrackMediaAttributes.AudioBook)) {
+//                    track.Type = IPod.MediaType.Audiobook;
+//                } else if (HasAttribute (TrackMediaAttributes.Music)) {
+//                    track.Type = IPod.MediaType.Audio;
+//                } else {
+//                    track.Type = IPod.MediaType.Audio;
+//                }
+//            }
+            track.MediaType = GPod.MediaType.Audio;
+            if (addTrack) {
+                track.Filetype = "MP3-file";
+                database.Tracks.Add (IpodTrack);
+                database.MasterPlaylist.Tracks.Add (IpodTrack);
+                database.CopyTrackToIPod (track, Uri.LocalPath);
+                ExternalId = (long) IpodTrack.DBID;
+                Console.WriteLine ("The ipod path is now: {0}", IpodTrack.IpodPath);
+            }
+//            if (CoverArtSpec.CoverExists (ArtworkId)) {
+//                SetIpodCoverArt (device, track, CoverArtSpec.GetPath (ArtworkId));
+//            }
+        }
+
+        // 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
+        public static void SetIpodCoverArt (GPod.Device device, GPod.Track track, string path)
+        {
+//            try {
+//                Gdk.Pixbuf pixbuf = null;
+//                foreach (IPod.ArtworkFormat format in device.LookupArtworkFormats (IPod.ArtworkUsage.Cover)) {
+//                    if (!track.HasCoverArt (format)) {
+//                        // Lazily load the pixbuf
+//                        if (pixbuf == null) {
+//                            pixbuf = new Gdk.Pixbuf (path);
+//                        }
+//
+//                        track.SetCoverArt (format, IPod.ArtworkHelpers.ToBytes (format, pixbuf));
+//                    }
+//                }
+//
+//                if (pixbuf != null) {
+//                    pixbuf.Dispose ();
+//                }
+//            } catch (Exception e) {
+//                Log.Exception (String.Format ("Failed to set cover art on iPod from {0}", path), e);
+//            }
+        }
+    }
+}
diff --git a/src/Dap/Banshee.Dap.AppleDevice/Makefile.am b/src/Dap/Banshee.Dap.AppleDevice/Makefile.am
new file mode 100644
index 0000000..93d2ca4
--- /dev/null
+++ b/src/Dap/Banshee.Dap.AppleDevice/Makefile.am
@@ -0,0 +1,31 @@
+ASSEMBLY = Banshee.Dap.AppleDevice
+TARGET = library
+LINK = $(REF_DAP_APPLEDEVICE)
+INSTALL_DIR = $(EXTENSIONS_INSTALL_DIR)
+
+SOURCES =  \
+	Banshee.Dap.AppleDevice/AppleDeviceProvider.cs \
+	Banshee.Dap.AppleDevice/AppleDeviceSource.cs \
+	Banshee.Dap.AppleDevice/AppleDeviceTrackInfo.cs
+
+RESOURCES = Banshee.Dap.AppleDevice.addin.xml
+
+EXTRA_BUNDLE = $(LIBGPODSHARP_ASSEMBLIES)
+
+if ENABLE_APPLEDEVICE
+include $(top_srcdir)/build/build.mk
+
+install-data-hook:
+	for ASM in $(LIBGPODSHARP_ASSEMBLIES); do \
+		$(INSTALL) -m 0755 $$ASM $(DESTDIR)$(moduledir); \
+	done;
+
+uninstall-hook:
+	for ASM in $(LIBGPODSHARP_ASSEMBLIES); do \
+		rm -f $(DESTDIR)$(moduledir)/`basename $$ASM`; \
+	done;
+
+else
+EXTRA_DIST = $(SOURCES) $(RESOURCES)
+endif
+
diff --git a/src/Dap/Makefile.am b/src/Dap/Makefile.am
index c71a973..0da024c 100644
--- a/src/Dap/Makefile.am
+++ b/src/Dap/Makefile.am
@@ -1,5 +1,6 @@
 SUBDIRS = \
 	Banshee.Dap \
+	Banshee.Dap.AppleDevice \
 	Banshee.Dap.Ipod \
 	Banshee.Dap.MassStorage \
 	Banshee.Dap.Mtp \



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