[banshee] Imported the Amazon MP3 downloader extension



commit 4a46f20a96e93c4a706b54abf801a788375d764a
Author: Aaron Bockover <abockover novell com>
Date:   Wed Jul 7 19:33:02 2010 -0400

    Imported the Amazon MP3 downloader extension
    
    This extension supports the downloading and importing of purchases (.amz
    files) from Amazon.com's MP3 store. Additionally it features a simple
    command line tool that will download a purchase outside of Banshee (e.g.
    into the current directory).
    
    A mime type file for .amz files is provided for web/file browser
    integration.

 .../Banshee.AmazonMp3/Banshee.AmazonMp3.addin.xml  |   22 ++++
 .../Banshee.AmazonMp3/Banshee.AmazonMp3.csproj     |  107 +++++++++++++++++
 .../AmazonMp3DownloaderService.cs                  |   76 ++++++++++++
 .../Banshee.AmazonMp3/AmzMp3Downloader.cs          |   78 ++++++++++++
 .../Banshee.AmazonMp3/AmzXspfPlaylist.cs           |  117 ++++++++++++++++++
 .../Banshee.AmazonMp3/ConsoleTool.cs               |  125 ++++++++++++++++++++
 .../Banshee.AmazonMp3/ImportSource.cs              |   79 ++++++++++++
 .../Banshee.AmazonMp3/UserJobDownloadManager.cs    |  114 ++++++++++++++++++
 src/Extensions/Banshee.AmazonMp3/Makefile.am       |   32 +++++
 src/Extensions/Banshee.AmazonMp3/amazonmp3.xml     |    8 ++
 src/Extensions/Banshee.AmazonMp3/bamz.in           |    3 +
 11 files changed, 761 insertions(+), 0 deletions(-)
---
diff --git a/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3.addin.xml b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3.addin.xml
new file mode 100644
index 0000000..b0ec29d
--- /dev/null
+++ b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3.addin.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Addin
+    id="Banshee.AmazonMp3"
+    version="1.0"
+    compatVersion="1.0"
+    copyright="Copyright 2010 Novell, Inc."
+    name="Amazon MP3 Import"
+    category="Online Sources"
+    description="Download and import music purchased from Amazon.com"
+    author="Aaron Bockover"
+    url="http://banshee.fm/";
+    defaultEnabled="true">
+  <Dependencies>
+    <Addin id="Banshee.Services" version="1.0"/>
+  </Dependencies>
+  <Extension path="/Banshee/Library/ImportSource">
+    <ImportSource class="Banshee.AmazonMp3.ImportSource"/>
+  </Extension>
+  <Extension path="/Banshee/ServiceManager/Service">
+    <Service class="Banshee.AmazonMp3.AmazonMp3DownloaderService"/>
+  </Extension>
+</Addin>
\ No newline at end of file
diff --git a/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3.csproj b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3.csproj
new file mode 100644
index 0000000..28b697d
--- /dev/null
+++ b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3.csproj
@@ -0,0 +1,107 @@
+<?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>{930ADBFD-07F1-4044-A1C5-8B28BD23DB5C}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AssemblyName>Banshee.AmazonMp3</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <ReleaseVersion>1.3</ReleaseVersion>
+    <RootNamespace>Banshee.AmazonMp3</RootNamespace>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <DefineConstants>DEBUG</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <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>
+    <Reference Include="gtk-sharp">
+      <SpecificVersion>False</SpecificVersion>
+    </Reference>
+    <Reference Include="gdk-sharp">
+      <SpecificVersion>False</SpecificVersion>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="Mono.Posix">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..bin\Mono.Posix.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Data" />
+    <Reference Include="glib-sharp">
+      <SpecificVersion>False</SpecificVersion>
+    </Reference>
+    <Reference Include="atk-sharp">
+      <SpecificVersion>False</SpecificVersion>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Banshee.AmazonMp3.addin.xml">
+      <LogicalName>Banshee.AmazonMp3.addin.xml</LogicalName>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Banshee.AmazonMp3\" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Banshee.AmazonMp3\AmazonMp3DownloaderService.cs" />
+    <Compile Include="Banshee.AmazonMp3\AmzMp3Downloader.cs" />
+    <Compile Include="Banshee.AmazonMp3\AmzXspfPlaylist.cs" />
+    <Compile Include="Banshee.AmazonMp3\ConsoleTool.cs" />
+    <Compile Include="Banshee.AmazonMp3\ImportSource.cs" />
+    <Compile Include="Banshee.AmazonMp3\UserJobDownloadManager.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="..\..\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="..\..\Libraries\Hyena\Hyena.csproj">
+      <Project>{95374549-9553-4C1E-9D89-667755F90E12}</Project>
+      <Name>Hyena</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <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/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/AmazonMp3DownloaderService.cs b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/AmazonMp3DownloaderService.cs
new file mode 100644
index 0000000..81f5c21
--- /dev/null
+++ b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/AmazonMp3DownloaderService.cs
@@ -0,0 +1,76 @@
+//
+// AmzMp3DownloaderService.cs
+//  
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 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 System.IO;
+
+using Hyena;
+
+using Banshee.ServiceStack;
+
+namespace Banshee.AmazonMp3
+{
+    public class AmazonMp3DownloaderService : IExtensionService, IDisposable
+    {
+        public void Initialize ()
+        {
+            ServiceManager.Get<DBusCommandService> ().ArgumentPushed += OnCommandLineArgument;
+            GLib.Timeout.Add (2500, delegate {
+                foreach (var path in ApplicationContext.CommandLine.Files) {
+                    OnCommandLineArgument (path, null, true);
+                }
+                return false;
+            });
+        }
+
+        public void Dispose ()
+        {
+            ServiceManager.Get<DBusCommandService> ().ArgumentPushed -= OnCommandLineArgument;
+        }
+
+        private void OnCommandLineArgument (string argument, object value, bool isFile)
+        {
+            if (isFile && File.Exists (argument) && Path.GetExtension (argument) == ".amz") {
+                DownloadAmz (argument);
+            }
+        }
+
+        public void DownloadAmz (string path)
+        {
+            try {
+                new UserJobDownloadManager (path);
+                Log.Information ("Downloading Amazon MP3 purchase", path);
+            } catch (Exception e) {
+                Log.Exception ("Invalid .amz file: " + path, e);
+                Log.Error ("Invalid Amazon MP3 downloader file", path, true);
+            }
+        }
+
+        string IService.ServiceName {
+            get { return "AmazonMp3DownloaderService"; }
+        }
+    }
+}
diff --git a/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/AmzMp3Downloader.cs b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/AmzMp3Downloader.cs
new file mode 100644
index 0000000..bb82e4c
--- /dev/null
+++ b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/AmzMp3Downloader.cs
@@ -0,0 +1,78 @@
+// 
+// AmzMp3Downloader.cs
+//  
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 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 System.IO;
+
+using Hyena;
+using Hyena.Downloader;
+using Xspf = Media.Playlists.Xspf;
+
+namespace Banshee.AmazonMp3
+{
+    public class AmzMp3Downloader : HttpFileDownloader
+    {
+        public Xspf.Track Track { get; private set; }
+        public string OutputPath { get; set; }
+
+        public AmzMp3Downloader (Xspf.Track track)
+        {
+            UserAgent = "Amazon MP3 Downloader (Linux 1.0.9 en_US)";
+            TempPathRoot = Path.Combine (Path.GetTempPath (), "banshee-amz-downloader");
+            FileExtension = "mp3";
+            Uri = track.Locations[0];
+            Track = track;
+            Name = String.Format ("{0} ({1})", Track.Title, Track.Creator);
+        }
+
+        protected override void OnFileFinished ()
+        {
+            if (!State.Success) {
+                return;
+            }
+
+            base.OnFileFinished ();
+
+            if (OutputPath == null) {
+                return;
+            }
+
+            using (var file = TagLib.File.Create (LocalPath, "taglib/mp3", TagLib.ReadStyle.Average)) {
+                var artist = StringUtil.EscapeFilename (file.Tag.JoinedPerformers);
+                var album = StringUtil.EscapeFilename (file.Tag.Album);
+                var title = StringUtil.EscapeFilename (file.Tag.Title);
+
+                var track_dir = Path.Combine (OutputPath, Path.Combine (artist, album));
+                var track_path = Path.Combine (track_dir, String.Format ("{0:00}. {1}.mp3",
+                    file.Tag.Track, title));
+
+                Directory.CreateDirectory (track_dir);
+                File.Copy (LocalPath, track_path, true);
+                File.Delete (LocalPath);
+            }
+        }
+    }
+}
diff --git a/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/AmzXspfPlaylist.cs b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/AmzXspfPlaylist.cs
new file mode 100644
index 0000000..3475713
--- /dev/null
+++ b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/AmzXspfPlaylist.cs
@@ -0,0 +1,117 @@
+// 
+// AmzXspfPlaylist.cs
+//  
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 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 NOvoidT 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.IO;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Security.Cryptography;
+
+using Xspf = Media.Playlists.Xspf;
+
+namespace Banshee.AmazonMp3
+{
+    public class AmzXspfPlaylist : Xspf.Playlist
+    {
+        /*
+            Decrypt/Encrypt an AMZ file. To encrypt, remove the -d option
+            and invert the -in/-out values.
+
+            openssl enc -a -d -des-cbc \
+                -K 29AB9D18B2449E31 \
+                -iv 5E72D79A11B34FEE \
+                -in input.amz \
+                -out output.xml
+        */
+
+        private static byte [] amz_key = new byte []
+            { 0x29, 0xAB, 0x9D, 0x18, 0xB2, 0x44, 0x9E, 0x31 };
+
+        private static byte [] amz_iv = new byte []
+            { 0x5E, 0x72, 0xD7, 0x9A, 0x11, 0xB3, 0x4F, 0xEE };
+
+        private List<Xspf.Track> downloadable_tracks = new List<Xspf.Track> ();
+
+        public AmzXspfPlaylist (string path)
+        {
+            using (var stream = File.OpenRead (path)) {
+                Decrypt (stream);
+            }
+        }
+
+        public AmzXspfPlaylist (Stream stream)
+        {
+            Decrypt (stream);
+        }
+
+        private void Decrypt (Stream stream)
+        {
+            var crypto_service = new DESCryptoServiceProvider () {
+                Key = amz_key,
+                IV = amz_iv,
+                Mode = CipherMode.CBC
+            };
+
+            using (var encrypted_stream = new MemoryStream (Base64Decode (stream))) {
+                using (var decrypted_stream = new CryptoStream (encrypted_stream,
+                    crypto_service.CreateDecryptor (), CryptoStreamMode.Read)) {
+                    using (var reader = new StreamReader (decrypted_stream)) {
+                        Load (decrypted_stream);
+                        AmzLoad ();
+                    }
+                }
+            }
+        }
+
+        private byte [] Base64Decode (Stream input)
+        {
+            using (var reader = new StreamReader (input)) {
+                return Convert.FromBase64String (reader.ReadToEnd ());
+            }
+        }
+
+        private void AmzLoad ()
+        {
+            var downloadable_track_meta = new Xspf.MetaEntry (
+                new Uri ("http://www.amazon.com/dmusic/productTypeName";),
+                "DOWNLOADABLE_MUSIC_TRACK");
+
+            foreach (var track in Tracks) {
+                if (track.Meta.Contains (downloadable_track_meta)) {
+                    downloadable_tracks.Add (track);
+                }
+            }
+        }
+
+        public ReadOnlyCollection<Xspf.Track> DownloadableTracks {
+            get { return new ReadOnlyCollection<Xspf.Track> (downloadable_tracks); }
+        }
+
+        public int DownloadableTrackCount {
+            get { return downloadable_tracks.Count; }
+        }
+    }
+}
diff --git a/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/ConsoleTool.cs b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/ConsoleTool.cs
new file mode 100644
index 0000000..b34739e
--- /dev/null
+++ b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/ConsoleTool.cs
@@ -0,0 +1,125 @@
+// 
+// ConsoleTool.cs
+//  
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 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 System.IO;
+using System.Linq;
+using System.Collections.Generic;
+
+using Hyena.Downloader;
+
+namespace Banshee.AmazonMp3
+{
+    public static class ConsoleTool
+    {
+        private static void Usage ()
+        {
+            Console.Error.WriteLine ("Usage: amzclient [-o output_dir] amz_files...");
+            Console.Error.WriteLine ();
+            Console.Error.WriteLine ("Written by Aaron Bockover <aaron abock org>");
+            Console.Error.WriteLine ("Copyright 2010 Novell, Inc.");
+            Environment.Exit (1);
+        }
+
+        public static void Main (string [] args)
+        {
+            var output_path = Environment.CurrentDirectory;
+
+            if (args.Length < 1) {
+                Usage ();
+                return;
+            }
+
+            var amz_files = new Queue<AmzXspfPlaylist> ();
+
+            for (int i = 0; i < args.Length; i++) {
+                if (args[i] == "-o") {
+                    if (i < args.Length - 1) {
+                        output_path = args[++i];
+                    } else {
+                        Usage ();
+                        return;
+                    }
+                } else if (args[i] == "--help" || args[i] == "-h") {
+                    Usage ();
+                    return;
+                } else {
+                    try {
+                        amz_files.Enqueue (new AmzXspfPlaylist (args[i]));
+                    } catch {
+                        Console.Error.WriteLine ("Invalid .amz file: {0}", args[i]);
+                    }
+                }
+            }
+
+            while (amz_files.Count > 0) {
+                int i = 1;
+                var playlist = amz_files.Dequeue ();
+
+                var download_manager = new DownloadManager { MaxConcurrentDownloaders = 1 };
+
+                download_manager.Finished += d => {
+                    if (!d.State.Success) {
+                        Console.WriteLine ("[{0}/{1}] {2}: {3}", i, playlist.DownloadableTrackCount,
+                            d.Name, d.State.FailureException.Message);
+                    } else {
+                        Console.WriteLine ();
+                    }
+                    i++;
+                };
+
+                download_manager.Progress += d => {
+                    int progress_bar_size = Console.WindowWidth - 65;
+                    Console.Write ("\r{0} {1} |{2}| {3} {4}",
+                        Field (String.Format ("[{0}/{1}]", i, playlist.DownloadableTrackCount), 7),
+                        Field (d.Name, 35),
+                        Field (String.Empty.PadRight ((int)Math.Ceiling (progress_bar_size
+                            * d.State.PercentComplete), '='), progress_bar_size),
+                        Field (((int)Math.Round (d.State.PercentComplete * 100)).ToString () + "%", 4),
+                        Field (String.Format ("{0:0.00} KB/s", d.State.TransferRate / 1024), 12));
+                };
+
+                Console.WriteLine ("Downloading Album");
+
+                foreach (var track in playlist.DownloadableTracks) {
+                    download_manager.QueueDownloader (new AmzMp3Downloader (track) {
+                        OutputPath = output_path
+                    });
+                }
+
+                download_manager.WaitUntilFinished ();
+            }
+        }
+
+        private static string Field (string s, int l)
+        {
+            if (s.Length > l) {
+                s = s.Substring (0, l - 3).TrimEnd () + "...";
+            }
+            return s.PadRight (l);
+        }
+    }
+}
diff --git a/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/ImportSource.cs b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/ImportSource.cs
new file mode 100644
index 0000000..335410b
--- /dev/null
+++ b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/ImportSource.cs
@@ -0,0 +1,79 @@
+// 
+// ImportSource.cs
+//  
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 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.ServiceStack;
+using Banshee.Library;
+using Banshee.I18n;
+
+namespace Banshee.AmazonMp3
+{
+    public sealed class ImportSource : IImportSource
+    {
+        public void Import ()
+        {
+            var chooser = Banshee.Gui.Dialogs.FileChooserDialog.CreateForImport (
+                Catalog.GetString ("Download Amazon MP3 Purchase"), true);
+            var filter = new Gtk.FileFilter () {
+                Name = Catalog.GetString ("Amazon MP3 Files")
+            };
+            filter.AddPattern ("*.amz");
+            chooser.AddFilter (filter);
+
+            try {
+                if (chooser.Run () == (int)Gtk.ResponseType.Ok) {
+                    foreach (var path in chooser.Filenames) {
+                        ServiceManager.Get<AmazonMp3DownloaderService> ().DownloadAmz (path);
+                    }
+                }
+            } finally {
+                chooser.Destroy ();
+            }
+        }
+
+        public bool CanImport {
+            get { return true; }
+        }
+
+        public string Name {
+            get { return Catalog.GetString ("Amazon MP3 Purchase"); }
+        }
+
+        public string ImportLabel {
+            get { return Catalog.GetString ("C_hoose Files"); }
+        }
+
+        public string [] IconNames {
+            get { return new string [] { "amazon-mp3-source" }; }
+        }
+
+        public int SortOrder {
+            get { return 40; }
+        }
+    }
+}
+
diff --git a/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/UserJobDownloadManager.cs b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/UserJobDownloadManager.cs
new file mode 100644
index 0000000..e41939d
--- /dev/null
+++ b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3/UserJobDownloadManager.cs
@@ -0,0 +1,114 @@
+//
+// UserJobDownloadManager.cs
+//  
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 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 Hyena;
+using Hyena.Downloader;
+
+using Banshee.Library;
+using Banshee.Collection.Database;
+using Banshee.ServiceStack;
+using Banshee.I18n;
+
+namespace Banshee.AmazonMp3
+{
+    public class UserJobDownloadManager : DownloadManager
+    {
+        private UserJob user_job;
+        private int total_count;
+        private int finished_count;
+        private LibraryImportManager import_manager;
+
+        public UserJobDownloadManager (string path)
+        {
+            var playlist = new AmzXspfPlaylist (path);
+            total_count = playlist.DownloadableTrackCount;
+            foreach (var track in playlist.DownloadableTracks) {
+                QueueDownloader (new AmzMp3Downloader (track));
+            }
+
+            user_job = new UserJob (Catalog.GetString ("Amazon MP3 Purchases"),
+                Catalog.GetString ("Contacting..."), "amazon-mp3-source");
+            user_job.Register ();
+
+            import_manager = new LibraryImportManager (true) {
+                KeepUserJobHidden = true
+            };
+        }
+
+        protected override void OnDownloaderStarted (HttpDownloader downloader)
+        {
+            var track = ((AmzMp3Downloader)downloader).Track;
+            Log.InformationFormat ("Starting to download \"{0}\" by {1}", track.Title, track.Creator);
+        }
+
+        protected override void OnDownloaderProgress (HttpDownloader downloader)
+        {
+            lock (SyncRoot) {
+                double weight = 1.0 / total_count;
+                double progress = finished_count * weight;
+                double speed = 0;
+                int count = 0;
+                foreach (var active_downloader in ActiveDownloaders) {
+                    progress += weight * active_downloader.State.PercentComplete;
+                    speed = active_downloader.State.TransferRate;
+                    count++;
+                }
+                user_job.Progress = progress;
+                user_job.Status = String.Format (
+                    Catalog.GetPluralString (
+                        "{0} download at {1}/s ({2} pending)",
+                        "{0} downloads at {1}/s ({2} pending)",
+                        count),
+                    count, new Hyena.Query.FileSizeQueryValue (
+                        (long)Math.Round (speed)).ToUserQuery (),
+                    PendingDownloadCount
+                );
+            }
+        }
+
+        protected override void OnDownloaderFinished (HttpDownloader downloader)
+        {
+            base.OnDownloaderFinished (downloader);
+
+            if (downloader.State.Success) {
+                import_manager.Enqueue (((HttpFileDownloader)downloader).LocalPath);
+            }
+
+            var track = ((AmzMp3Downloader)downloader).Track;
+            Log.InformationFormat ("Finished downloading \"{0}\" by {1}", track.Title, track.Creator);
+
+            lock (SyncRoot) {
+                finished_count++;
+
+                if (TotalDownloadCount <= 0) {
+                    user_job.Finish ();
+                }
+            }
+        }
+    }
+}
diff --git a/src/Extensions/Banshee.AmazonMp3/Makefile.am b/src/Extensions/Banshee.AmazonMp3/Makefile.am
new file mode 100644
index 0000000..6671f64
--- /dev/null
+++ b/src/Extensions/Banshee.AmazonMp3/Makefile.am
@@ -0,0 +1,32 @@
+ASSEMBLY = Banshee.AmazonMp3
+TARGET = exe
+LINK = $(REF_EXTENSION_AMAZONMP3)
+INSTALL_DIR = $(EXTENSIONS_INSTALL_DIR)
+
+SOURCES =  \
+	Banshee.AmazonMp3/AmazonMp3DownloaderService.cs \
+	Banshee.AmazonMp3/AmzMp3Downloader.cs \
+	Banshee.AmazonMp3/AmzXspfPlaylist.cs \
+	Banshee.AmazonMp3/ConsoleTool.cs \
+	Banshee.AmazonMp3/ImportSource.cs \
+	Banshee.AmazonMp3/UserJobDownloadManager.cs 
+
+RESOURCES = Banshee.AmazonMp3.addin.xml
+
+bamzdir = $(bindir)
+bamz_SCRIPTS = bamz
+
+mimedir = $(datadir)/mime/packages
+mime_DATA = amazonmp3.xml
+
+bamz: bamz.in
+	@echo '  GEN   $@'; sed 's,@bansheedir@,$(pkglibdir),g' < $< > $@
+
+define EXTRA_INSTALL_DATA_HOOK
+	update-mime-database $(DESTDIR)$(datadir)/mime
+endef
+
+include $(top_srcdir)/build/build.mk
+
+CLEANFILES += bamz
+EXTRA_DIST += bamz.in amazonmp3.xml
diff --git a/src/Extensions/Banshee.AmazonMp3/amazonmp3.xml b/src/Extensions/Banshee.AmazonMp3/amazonmp3.xml
new file mode 100644
index 0000000..5e94d87
--- /dev/null
+++ b/src/Extensions/Banshee.AmazonMp3/amazonmp3.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+  <mime-type type="audio/x-amzxml">
+    <generic-icon name="package-x-generic"/>
+    <comment>Amazon MP3 Purchase Playlist</comment>
+    <glob pattern="*.amz"/>
+  </mime-type>
+</mime-info>
diff --git a/src/Extensions/Banshee.AmazonMp3/bamz.in b/src/Extensions/Banshee.AmazonMp3/bamz.in
new file mode 100644
index 0000000..d96f243
--- /dev/null
+++ b/src/Extensions/Banshee.AmazonMp3/bamz.in
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+MONO_PATH= bansheedir@ exec -a bamz mono @bansheedir@/Extensions/Banshee.AmazonMp3.exe $@



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