[banshee] [emusic] Add new eMusic extension



commit 10514a97453c717e42936a94a3f0d7a17e7b1411
Author: Eitan Isaacson <eitan monotonous org>
Date:   Mon Nov 16 16:59:50 2009 -0800

    [emusic] Add new eMusic extension
    
    Download and import music purchased from eMusic by supporting importing
    their .emx file format (BGO #602891)
    
    Signed-off-by: Gabriel Burt <gabriel burt gmail com>

 build/build.environment.mk                         |    1 +
 configure.ac                                       |    1 +
 .../Banshee.Emusic/Banshee.Emusic.addin.xml        |   27 ++++
 .../Banshee.Emusic/Banshee.Emusic.csproj           |   77 ++++++++++
 .../DownloadManager/DownloadManagerInterface.cs    |  153 ++++++++++++++++++++
 .../DownloadManager/DownloadUserJob.cs             |  144 ++++++++++++++++++
 .../Banshee.Emusic/Banshee.Emusic/EmusicImport.cs  |   93 ++++++++++++
 .../Banshee.Emusic/Banshee.Emusic/EmusicService.cs |  137 ++++++++++++++++++
 src/Extensions/Banshee.Emusic/Makefile.am          |   15 ++
 src/Extensions/Makefile.am                         |    1 +
 10 files changed, 649 insertions(+), 0 deletions(-)
---
diff --git a/build/build.environment.mk b/build/build.environment.mk
index 1c28fc7..0d740c9 100644
--- a/build/build.environment.mk
+++ b/build/build.environment.mk
@@ -123,6 +123,7 @@ REF_EXTENSION_BOOSCRIPT = $(LINK_BANSHEE_THICKCLIENT_DEPS) $(LINK_BOO)
 REF_EXTENSION_BPM = $(LINK_BANSHEE_THICKCLIENT_DEPS)
 REF_EXTENSION_COVERART = $(LINK_BANSHEE_THICKCLIENT_DEPS)
 REF_EXTENSION_DAAP = $(LINK_BANSHEE_THICKCLIENT_DEPS) $(LINK_ICSHARP_ZIP_LIB) $(LINK_MONO_ZEROCONF)
+REF_EXTENSION_EMUSIC = $(LINK_BANSHEE_THICKCLIENT_DEPS) $(LINK_MIGO_DEPS)
 REF_EXTENSION_FILESYSTEMQUEUE = $(LINK_BANSHEE_THICKCLIENT_DEPS)
 REF_EXTENSION_INTERNETRADIO = $(LINK_BANSHEE_THICKCLIENT_DEPS)
 REF_EXTENSION_INTERNETARCHIVE = $(LINK_BANSHEE_THICKCLIENT_DEPS)
diff --git a/configure.ac b/configure.ac
index ec908ef..9a4cf55 100644
--- a/configure.ac
+++ b/configure.ac
@@ -282,6 +282,7 @@ src/Extensions/Banshee.BooScript/Makefile
 src/Extensions/Banshee.Bpm/Makefile
 src/Extensions/Banshee.CoverArt/Makefile
 src/Extensions/Banshee.Daap/Makefile
+src/Extensions/Banshee.Emusic/Makefile
 src/Extensions/Banshee.FileSystemQueue/Makefile
 src/Extensions/Banshee.InternetArchive/Makefile
 src/Extensions/Banshee.InternetRadio/Makefile
diff --git a/src/Extensions/Banshee.Emusic/Banshee.Emusic.addin.xml b/src/Extensions/Banshee.Emusic/Banshee.Emusic.addin.xml
new file mode 100644
index 0000000..39b9d3c
--- /dev/null
+++ b/src/Extensions/Banshee.Emusic/Banshee.Emusic.addin.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Addin
+    id="Banshee.Emusic"
+    version="0.1"
+    compatVersion="0.1"
+    copyright="© 2009 Eitan Isaacson"
+    name="eMusic Import"
+    category=""
+    description="Download and import music purchased from eMusic"
+    author="Eitan Isaacson"
+    url="http://banshee-project.org/";
+    defaultEnabled="true">
+
+  <Dependencies>
+    <Addin id="Banshee.Services" version="1.0"/>
+  </Dependencies>
+
+  <Extension path="/Banshee/Library/ImportSource">
+    <ImportSource class="Banshee.Emusic.EmusicImport"/>
+  </Extension>
+
+  <Extension path="/Banshee/ServiceManager/Service">
+    <Service class="Banshee.Emusic.EmusicService"/>
+  </Extension>
+
+</Addin>
+
diff --git a/src/Extensions/Banshee.Emusic/Banshee.Emusic.csproj b/src/Extensions/Banshee.Emusic/Banshee.Emusic.csproj
new file mode 100644
index 0000000..608e411
--- /dev/null
+++ b/src/Extensions/Banshee.Emusic/Banshee.Emusic.csproj
@@ -0,0 +1,77 @@
+<?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>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{10A5B2EE-C9F0-4B7B-B79B-87B7DA9C1DC1}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AssemblyName>Banshee.Emusic</AssemblyName>
+    <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\bin</OutputPath>
+    <DefineConstants>DEBUG</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CustomCommands>
+      <CustomCommands>
+        <Command type="Build" command="make" />
+      </CustomCommands>
+    </CustomCommands>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>none</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="gtk-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="System" />
+    <Reference Include="Mono.Posix" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Data" />
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Banshee.Emusic.addin.xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Banshee.Emusic\" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Banshee.Emusic\EmusicImport.cs" />
+    <Compile Include="Banshee.Emusic\DownloadManager\DownloadManagerInterface.cs" />
+    <Compile Include="Banshee.Emusic\DownloadManager\DownloadUserJob.cs" />
+    <Compile Include="Banshee.Emusic\EmusicService.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <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="..\Banshee.Wikipedia\Banshee.Wikipedia.csproj">
+      <Project>{BF5D1722-269B-452E-B577-AEBA0CB894BA}</Project>
+      <Name>Banshee.Wikipedia</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\Libraries\Hyena.Gui\Hyena.Gui.csproj">
+      <Project>{C856EFD8-E812-4E61-8B76-E3583D94C233}</Project>
+      <Name>Hyena.Gui</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\Libraries\Migo\Migo.csproj">
+      <Project>{9C7B8E9C-A4E6-4459-A2C4-3D2D199EA919}</Project>
+      <Name>Migo</Name>
+    </ProjectReference>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/src/Extensions/Banshee.Emusic/Banshee.Emusic/DownloadManager/DownloadManagerInterface.cs b/src/Extensions/Banshee.Emusic/Banshee.Emusic/DownloadManager/DownloadManagerInterface.cs
new file mode 100644
index 0000000..573db98
--- /dev/null
+++ b/src/Extensions/Banshee.Emusic/Banshee.Emusic/DownloadManager/DownloadManagerInterface.cs
@@ -0,0 +1,153 @@
+/***************************************************************************
+ *  DownloadManagerInterface.cs
+ *
+ *  Copyright (C) 2008 Michael C. Urbanski
+ *  Written by Mike Urbanski <michael c urbanski gmail com>
+ ****************************************************************************/
+
+/*  THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
+ *
+ *  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 System.ComponentModel;
+
+using Gtk;
+
+using Migo.TaskCore;
+using Migo.DownloadCore;
+
+using System.Threading;
+
+namespace Banshee.Emusic
+{
+    public class DownloadManagerInterface : IDisposable
+    {
+        private DownloadManager manager;
+        private DownloadUserJob downloadJob;
+        //private DownloadManagerSource downloadSource;
+
+        private readonly object sync = new object ();
+
+        public DownloadManagerInterface (DownloadManager manager)
+        {
+            if (manager == null) {
+                throw new ArgumentNullException ("manager");
+            }
+
+            this.manager = manager;
+        }
+
+        public void Dispose ()
+        {
+            lock (sync) {
+                if (manager != null) {
+                    manager.Group.Started -= OnManagerStartedHandler;
+                    manager.Group.Stopped -= OnManagerStoppedHandler;
+                    manager.Group.ProgressChanged -= OnManagerProgressChangedHandler;
+                    manager.Group.StatusChanged -= OnManagerStatusChangedHandler;
+
+                    manager = null;
+                }
+            }
+
+            Gtk.Application.Invoke (delegate {
+                lock (sync) {
+                    if (downloadJob != null) {
+                        downloadJob.CancelRequested -= OnCancelRequested;
+                        downloadJob.Finish ();
+                        downloadJob = null;
+                        //SourceManager.RemoveSource (downloadSource);
+                        //downloadSource = null;
+                    }
+                }
+            });
+        }
+
+        public void Initialize ()
+        {
+            //downloadSource = new DownloadManagerSource (manager);
+            manager.Group.Started += OnManagerStartedHandler;
+            manager.Group.Stopped += OnManagerStoppedHandler;
+            manager.Group.ProgressChanged += OnManagerProgressChangedHandler;
+            manager.Group.StatusChanged += OnManagerStatusChangedHandler;
+        }
+
+        private void OnManagerStartedHandler (object sender, EventArgs e)
+        {
+            Gtk.Application.Invoke (delegate {
+                lock (sync) {
+                    if (downloadJob == null) {
+                        //SourceManager.AddSource (downloadSource);
+
+                        downloadJob = new DownloadUserJob ();
+                        downloadJob.CancelRequested += OnCancelRequested;
+                        downloadJob.Register ();
+                    }
+                }
+            });
+        }
+
+        private void OnManagerStoppedHandler (object sender, EventArgs e)
+        {
+            Gtk.Application.Invoke (delegate {
+                lock (sync) {
+                    if (downloadJob != null) {
+                        downloadJob.CancelRequested -= OnCancelRequested;
+                        downloadJob.Finish ();
+                        downloadJob = null;
+                        //SourceManager.RemoveSource (downloadSource);
+                    }
+                }
+            });
+        }
+
+        private void OnManagerProgressChangedHandler (object sender,
+                                                      ProgressChangedEventArgs e)
+        {
+            Application.Invoke (delegate {
+                lock (sync) {
+                    if (downloadJob != null) {
+                        downloadJob.UpdateProgress (e.ProgressPercentage);
+                    }
+                }
+            });
+        }
+
+        private void OnManagerStatusChangedHandler (object sender,
+                                                    GroupStatusChangedEventArgs e)
+        {
+            DownloadGroupStatusChangedEventArgs args = e as DownloadGroupStatusChangedEventArgs;
+
+            Application.Invoke (delegate {
+                lock (sync) {
+                    if (downloadJob != null) {
+                        downloadJob.UpdateStatus (args.RunningTasks, args.RemainingTasks, args.CompletedTasks, args.BytesPerSecond);
+                    }
+                }
+            });
+        }
+
+        private void OnCancelRequested (object sender, EventArgs e)
+        {
+            manager.Group.CancelAsync ();
+        }
+    }
+}
diff --git a/src/Extensions/Banshee.Emusic/Banshee.Emusic/DownloadManager/DownloadUserJob.cs b/src/Extensions/Banshee.Emusic/Banshee.Emusic/DownloadManager/DownloadUserJob.cs
new file mode 100644
index 0000000..91c6ea5
--- /dev/null
+++ b/src/Extensions/Banshee.Emusic/Banshee.Emusic/DownloadManager/DownloadUserJob.cs
@@ -0,0 +1,144 @@
+/***************************************************************************
+ *  DownloadUserJob.cs
+ *
+ *  Copyright (C) 2007 Michael C. Urbanski
+ *  Written by Mike Urbanski <michael c urbanski gmail com>
+ ****************************************************************************/
+
+/*  THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
+ *
+ *  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 Gtk;
+using Mono.Unix;
+
+using Banshee.ServiceStack;
+
+namespace Banshee.Emusic
+{
+    public class DownloadUserJob : UserJob
+    {
+        private bool disposed = false;
+        private bool canceled = false;
+        private bool cancelRequested = false;
+
+        private readonly object sync = new object ();
+
+        public DownloadUserJob () : base (Catalog.GetString ("Downloads"), String.Empty, String.Empty)
+        {
+            CancelRequested += OnCancelRequested;
+
+            Title = Catalog.GetString ("Downloading eMusic Track(s)");
+            Status = Catalog.GetString ("Initializing...");
+            CancelMessage = Catalog.GetString ("Cancel all eMusic downloads?");
+
+            this.IconNames = new string[1] {
+                Stock.Network
+            };
+
+            CanCancel = true;
+        }
+
+        public void Dispose ()
+        {
+            lock (sync) {
+                if (disposed) {
+                    throw new ObjectDisposedException (GetType ().FullName);
+                } else if (cancelRequested) {
+                    throw new InvalidOperationException ("Cannot dispose object while canceling.");
+                } else {
+                    disposed = true;
+                }
+
+                CancelRequested -= OnCancelRequested;
+            }
+        }
+
+        private bool SetCanceled ()
+        {
+            bool ret = false;
+
+            lock (sync) {
+                if (!cancelRequested && !canceled && !disposed) {
+                    CanCancel = false;
+                    ret = cancelRequested = true;
+                }
+            }
+
+            return ret;
+        }
+
+        public void UpdateProgress (int progress)
+        {
+            if (progress < 0 || progress > 100) {
+                throw new ArgumentException ("progress:  Must be between 0 and 100.");
+            }
+
+            lock (sync) {
+                if (canceled || cancelRequested || disposed) {
+                    return;
+                }
+
+                Progress = (double) progress / 100;
+            }
+        }
+
+        public void UpdateStatus (int downloading, int remaining, int completed, long bytesPerSecond)
+        {
+            if (downloading < 0) {
+                throw new ArgumentException ("downloading:  Must be positive.");
+            } else if (bytesPerSecond < 0) {
+                bytesPerSecond = 0;
+            }
+
+            lock (sync) {
+                if (canceled || cancelRequested || disposed) {
+                    return;
+                }
+
+                int total = remaining + completed;
+                string fmt = Catalog.GetPluralString (
+                        "Transferring {0} file at {1} KB/s",
+                        "Transferring {0} of {2} files at {1} KB/s", total
+                );
+
+                Status = String.Format (fmt, downloading, (bytesPerSecond / 1024), total);
+            }
+        }
+
+        private void OnCancelRequested (object sender, EventArgs e)
+        {
+            if (SetCanceled ()) {
+                lock (sync)  {
+                    Progress = 0.0;
+                    Title = Catalog.GetString ("Canceling Downloads");
+                    Status = Catalog.GetString (
+                        "Waiting for downloads to terminate..."
+                    );
+
+                    cancelRequested = false;
+                    canceled = true;
+                }
+            }
+        }
+    }
+}
diff --git a/src/Extensions/Banshee.Emusic/Banshee.Emusic/EmusicImport.cs b/src/Extensions/Banshee.Emusic/Banshee.Emusic/EmusicImport.cs
new file mode 100644
index 0000000..d1067e8
--- /dev/null
+++ b/src/Extensions/Banshee.Emusic/Banshee.Emusic/EmusicImport.cs
@@ -0,0 +1,93 @@
+//
+// EmusicImport.cs
+//
+// Author:
+//   Eitan Isaacson <eitan monotonous org>
+//
+// Copyright (C) 2009 Eitan Isaacson
+//
+// 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 System.Data;
+using System.IO;
+using System.Xml;
+using System.Collections.Generic;
+
+using Mono.Unix;
+
+using Hyena.Data.Sqlite;
+
+using Banshee.Base;
+using Banshee.Collection.Database;
+using Banshee.Library;
+using Banshee.ServiceStack;
+using Banshee.Playlist;
+using Banshee.Emusic;
+
+using Migo.DownloadCore;
+using Migo.TaskCore;
+
+namespace Banshee.Emusic
+{
+    public sealed class EmusicImport : IImportSource
+    {
+
+        public EmusicImport ()
+        {
+        }
+
+        public void Import ()
+        {
+            
+            var chooser = Banshee.Gui.Dialogs.FileChooserDialog.CreateForImport (Catalog.GetString ("Import eMusic Downloads to Library"), true);
+            Gtk.FileFilter ff = new Gtk.FileFilter();
+            ff.Name = Catalog.GetString ("eMusic Files");
+            ff.AddPattern("*.emx");
+            chooser.AddFilter (ff);
+
+            if (chooser.Run () == (int)Gtk.ResponseType.Ok)
+                ServiceManager.Get<EmusicService> ().ImportEmx (chooser.Uris);
+            
+            chooser.Destroy ();
+        }
+
+        public bool CanImport {
+            get { return true;}
+        }
+
+        public string Name {
+            get { return Catalog.GetString ("eMusic Tracks"); }
+        }
+
+        public string ImportLabel {
+            get { return Catalog.GetString ("C_hoose Files"); }
+        }
+
+        public string [] IconNames {
+            get { return new string [] { "gtk-open" }; }
+        }
+
+        public int SortOrder {
+            get { return 50; }
+        }
+    }
+}
diff --git a/src/Extensions/Banshee.Emusic/Banshee.Emusic/EmusicService.cs b/src/Extensions/Banshee.Emusic/Banshee.Emusic/EmusicService.cs
new file mode 100644
index 0000000..3453237
--- /dev/null
+++ b/src/Extensions/Banshee.Emusic/Banshee.Emusic/EmusicService.cs
@@ -0,0 +1,137 @@
+using System;
+using System.IO;
+using System.Xml;
+using System.Collections.Generic;
+using Mono.Unix;
+
+using Hyena;
+
+using Banshee.Collection.Database;
+using Banshee.ServiceStack;
+using Banshee.Library;
+using Banshee.Base;
+using Banshee.Gui;
+
+using Migo.DownloadCore;
+using Migo.TaskCore;
+
+namespace Banshee.Emusic
+{
+    public class EmusicService : IExtensionService, IDisposable
+    {
+        private DownloadManager download_manager;
+        private DownloadManagerInterface download_manager_iface;
+        private LibraryImportManager import_manager;
+        private Dictionary<string,HttpFileDownloadTask> tasks;
+        private readonly string tmp_download_path = Paths.Combine (Paths.ExtensionCacheRoot, "emusic", "partial-downloads");
+
+        public EmusicService ()
+        {
+            Log.DebugFormat ("{0} constructed.", this.ToString());
+        }
+
+        public void Initialize ()
+        {
+            Log.DebugFormat ("{0} initialized.", this.ToString());
+            tasks = new Dictionary<string, HttpFileDownloadTask> ();
+
+            import_manager = ServiceManager.Get<LibraryImportManager> ();
+            import_manager.ImportResult += HandleImportResult;
+
+            if (download_manager == null)
+                download_manager = new DownloadManager (2, tmp_download_path);
+
+            if (download_manager_iface == null) {
+                download_manager_iface = new DownloadManagerInterface (download_manager);
+                download_manager_iface.Initialize ();
+            }
+
+            ServiceManager.Get<DBusCommandService> ().ArgumentPushed += OnCommandLineArgument;
+        }
+
+        public void Dispose ()
+        {
+            Log.DebugFormat ("{0} disposed.", this.ToString());
+            download_manager.Dispose ();
+            download_manager_iface.Dispose ();
+            download_manager = null;
+            download_manager_iface = null;
+        }
+
+        string IService.ServiceName {
+            get { return "EmusicService"; }
+        }
+
+        private void OnCommandLineArgument (string argument, object value, bool isFile)
+        {
+            if (isFile && File.Exists (argument) && Path.GetExtension (argument) == ".emx")
+                ImportEmx (argument);
+        }
+
+        public void ImportEmx (string uri)
+        {
+            ImportEmx (new string [] {uri});
+        }
+
+        public void ImportEmx (string[] uris)
+        {
+            foreach (string uri in uris)
+            {
+                using (var xml_reader = new XmlTextReader (uri))
+                {
+                    while (xml_reader.Read())
+                    {
+                        if (xml_reader.NodeType == XmlNodeType.Element &&
+                            xml_reader.Name == "TRACKURL")
+                        {
+                            xml_reader.Read();
+                            Hyena.Log.DebugFormat ("Downloading: {0}", xml_reader.Value);
+                            HttpFileDownloadTask task = download_manager.CreateDownloadTask (xml_reader.Value);
+                            if (File.Exists (task.LocalPath))
+                                File.Delete (task.LocalPath); // FIXME: We go into a download loop if we don't.
+                            task.Completed += OnDownloadCompleted;
+                            download_manager.QueueDownload (task);
+                            tasks.Add (task.LocalPath, task);
+                        }
+                    }
+                }
+            }
+        }
+
+        private void OnDownloadCompleted (object sender, TaskCompletedEventArgs args)
+        {
+            HttpFileDownloadTask task = sender as HttpFileDownloadTask;
+
+            if (task.Status != TaskStatus.Succeeded)
+            {
+                task.Completed -= OnDownloadCompleted;
+
+                if (File.Exists (task.LocalPath))
+                    File.Delete (task.LocalPath);
+
+                if (Directory.Exists (Path.GetDirectoryName (task.LocalPath)))
+                    Directory.Delete (Path.GetDirectoryName (task.LocalPath));
+
+                tasks.Remove (task.LocalPath);
+
+                Hyena.Log.ErrorFormat ("Could not download eMusic track: {0}",
+                                       task.Error.ToString());
+            } else {
+                import_manager.Enqueue (task.LocalPath);
+            }
+        }
+
+        void HandleImportResult(object o, DatabaseImportResultArgs args)
+        {
+            if (tasks.ContainsKey (args.Path))
+            {
+                HttpFileDownloadTask task = tasks[args.Path];
+                task.Completed -= OnDownloadCompleted;
+                File.Delete (args.Path);
+                Directory.Delete (Path.GetDirectoryName (args.Path));
+                tasks.Remove (args.Path);
+            }
+        }
+
+    }
+}
diff --git a/src/Extensions/Banshee.Emusic/Makefile.am b/src/Extensions/Banshee.Emusic/Makefile.am
new file mode 100644
index 0000000..3cf1d12
--- /dev/null
+++ b/src/Extensions/Banshee.Emusic/Makefile.am
@@ -0,0 +1,15 @@
+ASSEMBLY = Banshee.Emusic
+TARGET = library
+LINK = $(REF_EXTENSION_EMUSIC)
+INSTALL_DIR = $(EXTENSIONS_INSTALL_DIR)
+
+SOURCES =  \
+	Banshee.Emusic/EmusicImport.cs \
+	Banshee.Emusic/EmusicService.cs \
+	Banshee.Emusic/DownloadManager/DownloadUserJob.cs \
+	Banshee.Emusic/DownloadManager/DownloadManagerInterface.cs
+
+RESOURCES = Banshee.Emusic.addin.xml
+
+include $(top_srcdir)/build/build.mk
+
diff --git a/src/Extensions/Makefile.am b/src/Extensions/Makefile.am
index 58f66a7..0ddfda3 100644
--- a/src/Extensions/Makefile.am
+++ b/src/Extensions/Makefile.am
@@ -6,6 +6,7 @@ SUBDIRS = \
 	Banshee.Bpm \
 	Banshee.CoverArt \
 	Banshee.Daap \
+	Banshee.Emusic \
 	Banshee.FileSystemQueue \
 	Banshee.InternetArchive \
 	Banshee.InternetRadio \



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