[banshee] Imported the Amazon MP3 downloader extension
- From: Aaron Bockover <abock src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [banshee] Imported the Amazon MP3 downloader extension
- Date: Thu, 8 Jul 2010 01:25:39 +0000 (UTC)
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]