
Property changes on: search/icons
___________________________________________________________________
Added: svn:ignore
   + Makefile
Makefile.in



Property changes on: firefox-extension
___________________________________________________________________
Modified: svn:ignore
   - Makefile
Makefile.in
beagle.xpi
chrome

   + Makefile
Makefile.in
beagle.xpi
chrome
install.rdf


Index: beagled/BansheeQueryable/BansheeQueryable.cs
===================================================================
--- /dev/null
+++ beagled/BansheeQueryable/BansheeQueryable.cs
@@ -0,0 +1,98 @@
+//
+// BansheeQueryable.cs
+//
+// Author:
+//   Aaron Bockover <abockover@novell.com>
+//
+// Copyright (C) 2008 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.Threading;
+using System.Diagnostics;
+using System.Collections.Generic;
+
+using Stopwatch = Beagle.Util.Stopwatch;
+
+using Beagle.Daemon;
+using Beagle.Util;
+
+[assembly: Beagle.Daemon.IQueryableTypes (typeof (Beagle.Daemon.BansheeQueryable.BansheeQueryable))]
+
+namespace Beagle.Daemon.BansheeQueryable
+{
+    [QueryableFlavor (Name = "Banshee", Domain=QueryDomain.Local, RequireInotify = false, DependsOn = "Files")]
+    public class BansheeQueryable : ExternalMetadataQueryable
+    {
+        private FileSystemQueryable.FileSystemQueryable fs_queryable;
+        private BansheeIndexer indexer;
+        private BansheeIndexableGenerator indexable_generator;
+        
+        internal BansheeIndexer Indexer {
+            get { return indexer; }
+        }
+
+        public override void Start () 
+        {
+            base.Start ();
+            NDesk.DBus.BusG.Init ();
+            fs_queryable = (FileSystemQueryable.FileSystemQueryable)QueryDriver.GetQueryable ("Files").IQueryable;
+            ExceptionHandlingThread.Start (new ThreadStart (StartWorker));
+        }
+
+        private void StartWorker ()
+        {
+            indexer = new BansheeIndexer (this);
+            indexer.Start ();
+        
+            Log.Info ("BansheeQueryable: Banshee metadata backend started");
+        }
+        
+        internal void OnIndexablesReady ()
+        {
+            LaunchIndexable ();
+        }
+        
+        private void LaunchIndexable ()
+        {
+            // Cancel running task before adding a new one
+            CancelIndexable ();
+
+            // Add the new indexable generator
+            indexable_generator = new BansheeIndexableGenerator (this);
+
+            Scheduler.Task task = fs_queryable.NewAddTask (indexable_generator);
+            task.Tag = BansheeIndexableGenerator.Tag;
+            fs_queryable.ThisScheduler.Add (task);
+            
+            Log.Info ("BansheeQueryable: Scheduled new BansheeIndexableGenerator ({0})", indexable_generator);
+        }
+
+        private void CancelIndexable ()
+        {
+            if (indexable_generator != null && fs_queryable.ThisScheduler.ContainsByTag (BansheeIndexableGenerator.Tag)) {
+                Log.Info ("BansheeQueryable: Cancelling existing BansheeIndexableGenerator ({0})", indexable_generator);
+                fs_queryable.ThisScheduler.GetByTag (BansheeIndexableGenerator.Tag).Cancel ();
+            }
+        }
+    }
+}
Index: beagled/BansheeQueryable/BansheeIndexer.cs
===================================================================
--- /dev/null
+++ beagled/BansheeQueryable/BansheeIndexer.cs
@@ -0,0 +1,298 @@
+//
+// BansheeIndexer.cs
+//
+// Author:
+//   Aaron Bockover <abockover@novell.com>
+//
+// Copyright (C) 2008 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.Collections.Generic;
+
+using Banshee.Collection.Indexer.RemoteHelper;
+
+using Beagle.Util;
+using Beagle.Daemon;
+using Stopwatch = Beagle.Util.Stopwatch;
+
+namespace Beagle.Daemon.BansheeQueryable
+{
+    // Field dump from GetExportFields in Banshee 1.3.2
+    //
+    // bit-rate, artist, rating, skip-count, artist-music-brainz-id, conductor, mime-type, 
+    // file-size, length, URI, music-brainz-id, name, play-count, license-uri, track-number, 
+    // disc-count, grouping, date-added, album-artist, last-played, genre, release-date, 
+    // local-path, is-compilation, media-attributes, more-info-uri, disc-number, comment, 
+    // year, copyright, bpm, composer, last-skipped, track-count, album, album-music-brainz-id
+    
+    public class BansheeIndexer : SimpleIndexerClient
+    {
+        private List<IDictionary<string, object>> indexed_items = new List<IDictionary<string, object>> ();
+        private BansheeQueryable queryable;
+        private Stopwatch stopwatch; 
+        private bool should_commit;
+    
+        public BansheeIndexer (BansheeQueryable queryable)
+        {
+            this.queryable = queryable;
+        }
+        
+        public IDictionary<string, object> [] CopyResults ()
+        {
+            return indexed_items.ToArray ();
+        }
+        
+#region SimpleIndexerClient Implementation Hooks
+        
+        protected override void OnStarted ()
+        {   
+            foreach (string field in GetAvailableExportFields ()) {
+                if (!ShouldSkipField (field, SkipType.Exclude)) {
+                    AddExportField (field);
+                }
+            }
+        }
+        
+        protected override void OnBeginUpdateIndex ()
+        {
+            Log.Info ("BansheeQueryable: Reading indexer results from DBus");
+            
+            stopwatch = new Stopwatch ();
+            stopwatch.Start ();
+            
+            indexed_items.Clear ();
+            should_commit = true;
+        }
+        
+        protected override void OnEndUpdateIndex ()
+        {
+            stopwatch.Stop ();
+            Log.Info ("BansheeQueryable: Finished reading {0} results in {1} over DBus", indexed_items.Count, stopwatch);
+            
+            // The indexing server terminated our read, probably because a user requested
+            // that Banshee start up as an application; in this case we discard any index
+            // results collected, and reset - the index process will trigger automatically
+            // when the application starts per the user's request
+            if (!should_commit) {
+                indexed_items.Clear ();
+                Log.Info ("BansheeQueryable: Discarding index results, OnShutdownWhileIndexing called");
+                return;
+            }
+            
+            queryable.OnIndexablesReady ();
+        }
+    
+        protected override void IndexResult (IDictionary<string, object> result)
+        {
+            indexed_items.Add (result);
+        }
+        
+        protected override void OnShutdownWhileIndexing ()
+        {
+            Log.Info ("BansheeQueryable: OnShutdownWhileIndexing - server has terminated the index operation");
+            should_commit = false;
+        }
+        
+#endregion
+
+#region SimpleIndexerClient Index Trigger Properties
+
+        // FIXME: These need implementing, but I have no idea how to store and read
+        // this data in Beagle. With these returning nothing, the entire index process
+        // will trigger every time!
+                                
+        protected override int CollectionCount { 
+            get { return 0; }
+        }
+        
+        protected override DateTime CollectionLastModified { 
+            get { return DateTime.MinValue; }
+        }
+        
+#endregion
+        
+#region Convert the remote a{sv} result into a Beagle Indexable
+
+        public static Indexable GetIndexable (IDictionary<string, object> result)
+        {
+            Uri uri = result.ContainsKey ("local-path") 
+                ? UriFu.PathToFileUri ((string)result["local-path"])
+                : UriFu.EscapedStringToUri ((string)result["URI"]);
+            
+            Indexable indexable = new Indexable (IndexableType.PropertyChange, uri);
+            
+            foreach (KeyValuePair<string, object> item in result) {
+                FieldAction action = GetFieldAction (item.Key);
+                if (action.Skip == SkipType.Ignore) {
+                    continue;
+                }
+                
+                string banshee_name = item.Key;
+                string beagle_name = action.BeagleName ?? MakeBeagleName (banshee_name);
+                Property property;
+                
+                switch (action.PropertyKind) {
+                    case PropertyKind.String:
+                        property = Beagle.Property.New (beagle_name, item.Value.ToString ());
+                        break;
+                    case PropertyKind.Date:
+                        property = Beagle.Property.NewDateFromString (beagle_name, item.Value.ToString ());
+                        break;
+                    case PropertyKind.Unsearched:
+                    default:
+                        property = Beagle.Property.NewUnsearched (beagle_name, item.Value);
+                        break;
+                }
+                
+                property.IsMutable = true;
+                property.IsPersistent = true;
+                indexable.AddProperty (property);
+            }
+            
+            return indexable;
+        }
+        
+#endregion
+
+#region Crazy Static stuff for magically translating, ignoring, and excluding fields from Banshee to Beagle        
+    
+        private enum PropertyKind
+        {
+            Unsearched,
+            String,
+            Date
+        }
+        
+        private enum SkipType
+        {
+            None,
+            Ignore,
+            Exclude
+        }
+    
+        private struct FieldAction
+        {
+            public static FieldAction Zero = new FieldAction ();
+        
+            public static FieldAction NewIgnore (string bansheeName)
+            {
+                FieldAction action = new FieldAction ();
+                action.BansheeName = bansheeName;
+                action.Skip = SkipType.Ignore;
+                return action;
+            }
+            
+            public static FieldAction NewExclude (string bansheeName)
+            {
+                FieldAction action = new FieldAction ();
+                action.BansheeName = bansheeName;
+                action.Skip = SkipType.Exclude;
+                return action;
+            }
+            
+            public static FieldAction NewMap (string bansheeName, string beagleName)
+            {
+                return NewMap (bansheeName, beagleName, PropertyKind.Unsearched);
+            }
+            
+            public static FieldAction NewMap (string bansheeName, string beagleName, PropertyKind kind)
+            {
+                FieldAction action = new FieldAction ();
+                action.BansheeName = bansheeName;
+                action.BeagleName = beagleName;
+                action.PropertyKind = kind;
+                return action;
+            }
+            
+            public static FieldAction NewOverride (string bansheeName, PropertyKind kind)
+            {
+                FieldAction action = new FieldAction ();
+                action.BansheeName = bansheeName;
+                action.PropertyKind = kind;
+                return action;
+            }
+        
+            public string BansheeName;
+            public string BeagleName;
+        
+            public SkipType Skip;
+            public PropertyKind PropertyKind;
+        }
+        
+        private static List<FieldAction> field_actions = new List<FieldAction> ();
+        
+        static BansheeIndexer ()
+        {
+            field_actions.Add (FieldAction.NewMap ("copyright", "dc:copyright", PropertyKind.String));
+            field_actions.Add (FieldAction.NewMap ("name", "dc:title", PropertyKind.String));
+            
+            field_actions.Add (FieldAction.NewOverride ("artist", PropertyKind.String));
+            field_actions.Add (FieldAction.NewOverride ("album-artist", PropertyKind.String));
+            field_actions.Add (FieldAction.NewOverride ("composer", PropertyKind.String));
+            field_actions.Add (FieldAction.NewOverride ("album", PropertyKind.String));
+            field_actions.Add (FieldAction.NewOverride ("conductor", PropertyKind.String));
+            field_actions.Add (FieldAction.NewOverride ("genre", PropertyKind.String));
+            field_actions.Add (FieldAction.NewOverride ("date-added", PropertyKind.Date));
+            field_actions.Add (FieldAction.NewOverride ("release-date", PropertyKind.Date));
+            field_actions.Add (FieldAction.NewOverride ("last-played", PropertyKind.Date));
+            field_actions.Add (FieldAction.NewOverride ("last-skipped", PropertyKind.Date));
+            
+            field_actions.Add (FieldAction.NewIgnore ("URI"));
+            field_actions.Add (FieldAction.NewIgnore ("local-path"));
+            
+            field_actions.Add (FieldAction.NewExclude ("file-size"));
+            field_actions.Add (FieldAction.NewExclude ("media-attributes"));
+            field_actions.Add (FieldAction.NewExclude ("mime-type"));
+        }
+        
+        private static bool ShouldSkipField (string field, SkipType skip)
+        {
+            foreach (FieldAction action in field_actions) {
+                if (action.Skip == skip && action.BansheeName == field) {
+                    return true;
+                }
+            }
+            
+            return false;
+        }
+        
+        private static FieldAction GetFieldAction (string field)
+        {
+            foreach (FieldAction action in field_actions) {
+                if (action.BansheeName == field) {
+                    return action;
+                }
+            }
+            
+            return FieldAction.Zero;
+        }
+        
+        private static string MakeBeagleName (string bansheeName)
+        {
+            return String.Format ("fixme:{0}", bansheeName.ToLower ().Replace ("-", String.Empty));
+        }
+        
+#endregion
+
+    }
+}
Index: beagled/BansheeQueryable/BansheeQueryable.sln
===================================================================
--- /dev/null
+++ beagled/BansheeQueryable/BansheeQueryable.sln
@@ -0,0 +1,18 @@
+﻿
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BansheeQueryable", "BansheeQueryable.csproj", "{D2AC3E46-E166-463B-8DB6-5E811D2D0B68}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{D2AC3E46-E166-463B-8DB6-5E811D2D0B68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D2AC3E46-E166-463B-8DB6-5E811D2D0B68}.Debug|Any CPU.Build.0 = Debug|Any CPU
+	EndGlobalSection
+	GlobalSection(MonoDevelopProperties) = preSolution
+		name = BansheeQueryable
+		StartupItem = BansheeQueryable.csproj
+	EndGlobalSection
+EndGlobal
Index: beagled/BansheeQueryable/BansheeIndexableGenerator.cs
===================================================================
--- /dev/null
+++ beagled/BansheeQueryable/BansheeIndexableGenerator.cs
@@ -0,0 +1,101 @@
+//
+// BansheeIndexableGenerator.cs
+//
+// Author:
+//   Aaron Bockover <abockover@novell.com>
+//
+// Copyright (C) 2008 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.Collections.Generic;
+
+using Beagle.Daemon;
+using Beagle.Util;
+
+namespace Beagle.Daemon.BansheeQueryable
+{
+    public class BansheeIndexableGenerator : IIndexableGenerator
+    {
+        internal const string Tag = "BansheeCollectionIndexer";
+        
+        private static int generator_count = 0;
+        
+        private IDictionary<string, object> [] index_results;
+        private int current_index;
+        private bool done;
+        private DateTime create_date;
+        private int create_id;
+        
+        public bool Done {
+            get { return done; }
+        }
+        
+        public BansheeIndexableGenerator (BansheeQueryable queryable)
+        {
+            this.index_results = queryable.Indexer.CopyResults ();
+            this.create_date = DateTime.Now;
+            this.create_id = generator_count++;
+            
+            Log.Info ("BansheeQueryable: New BansheeIndexableGenerator ({0})", this);
+        }
+        
+        public override string ToString ()
+        {
+            return String.Format ("{0}:{1} [{2}]", GetType (), create_id, create_date);
+        }
+        
+#region IIndexableGenerator
+
+        public string StatusName {
+            get { return String.Format ("Banshee object {0} of {1}", current_index, index_results.Length); }
+        }
+        
+        public void PostFlushHook () 
+        {
+        }
+        
+        public bool HasNextIndexable ()
+        {
+            if (current_index < index_results.Length) {
+                return true;
+            }
+            
+            done = true;
+            index_results = null;
+            current_index = 0;
+            return false;
+        }
+
+        public Indexable GetNextIndexable ()
+        {
+            if (!Done && current_index < index_results.Length) {
+                return BansheeIndexer.GetIndexable (index_results[current_index++]);
+            }
+            
+            return null;
+        }
+
+#endregion
+
+    }
+}
Index: beagled/BansheeQueryable/BansheeQueryable.csproj
===================================================================
--- /dev/null
+++ beagled/BansheeQueryable/BansheeQueryable.csproj
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <ProjectGuid>{D2AC3E46-E166-463B-8DB6-5E811D2D0B68}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AssemblyName>BansheeQueryable</AssemblyName>
+    <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>.</OutputPath>
+    <DefineConstants>DEBUG</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <EnvironmentVariables>
+      <EnvironmentVariables />
+    </EnvironmentVariables>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="BeagleDaemon, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\BeagleDaemon.exe</HintPath>
+    </Reference>
+    <Reference Include="BeagleDaemonLib, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\BeagleDaemonLib.dll</HintPath>
+    </Reference>
+    <Reference Include="BeagleDaemonPlugins, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\BeagleDaemonPlugins.dll</HintPath>
+    </Reference>
+    <Reference Include="NDesk.DBus, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f6716e4f9b2ed099" />
+    <Reference Include="NDesk.DBus.GLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f6716e4f9b2ed099" />
+    <Reference Include="Banshee.CollectionIndexer, Version=1.3.2.0, Culture=neutral, PublicKeyToken=null">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\..\..\..\usr\lib\banshee-1\Banshee.CollectionIndexer.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="BansheeQueryable.cs" />
+    <Compile Include="BansheeIndexer.cs" />
+    <Compile Include="BansheeIndexableGenerator.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ProjectExtensions>
+    <MonoDevelop>
+      <Properties>
+        <Deployment.LinuxDeployData generateScript="false" />
+      </Properties>
+    </MonoDevelop>
+  </ProjectExtensions>
+</Project>
\ No newline at end of file
Index: beagled/Makefile.am
===================================================================
--- beagled/Makefile.am.orig
+++ beagled/Makefile.am
@@ -403,6 +403,38 @@ $(THUNDERBIRD_TARGET): $(THUNDERBIRD_CSF
 
 ############################################################
 
+###
+### Banshee backend
+###
+
+BANSHEE_DIR = $(srcdir)/BansheeQueryable
+
+BANSHEE_TARGET = BansheeBackends.dll
+
+BANSHEE_CSFLAGS = $(BACKEND_CSFLAGS)
+
+BANSHEE_CSFILES =						\
+	$(BANSHEE_DIR)/BansheeQueryable.cs			\
+	$(BANSHEE_DIR)/BansheeIndexer.cs 		\
+	$(BANSHEE_DIR)/BansheeIndexableGenerator.cs
+
+BANSHEE_LOCAL_ASSEMBLIES =					\
+	../Util/Util.dll					\
+	../BeagleClient/Beagle.dll				\
+	./BeagleDaemonLib.dll
+
+BANSHEE_ASSEMBLIES =						\
+	-r:Mono.Posix						\
+	$(BEAGLED_LIBS)                 			\
+	$(BANSHEE_INDEXER_LIBS)					\
+	$(BANSHEE_LOCAL_ASSEMBLIES:%=-r:%)
+
+$(BANSHEE_TARGET): $(BANSHEE_CSFILES) $(BANSHEE_LOCAL_ASSEMBLIES)
+	$(CSC) -out:$@ $(BANSHEE_CSFLAGS) $(BANSHEE_CSFILES) $(BANSHEE_ASSEMBLIES)
+
+
+############################################################
+
 ### GMail and other Google backends
 
 XEMAIL_DIR = $(srcdir)/xemail-net/src
@@ -766,6 +798,10 @@ if ENABLE_THUNDERBIRD
 ALL_TARGETS += $(THUNDERBIRD_TARGET)
 endif
 
+if ENABLE_BANSHEE
+ALL_TARGETS += $(BANSHEE_TARGET)
+endif
+
 if ENABLE_EVOLUTION
 ALL_TARGETS +=				\
 	$(EVO_DLL_TARGET)
@@ -837,12 +873,26 @@ endif
 if ENABLE_GOOGLEBACKENDS
 	$(INSTALL_DATA) $(GOOGLE_BACKEND_TARGET) $(GOOGLE_BACKEND_TARGET).mdb $(DESTDIR)$(BACKENDDIR)
 endif
+if ENABLE_BANSHEE
+	$(INSTALL_DATA) $(BANSHEE_TARGET)                 $(DESTDIR)$(BACKENDDIR)
+	$(INSTALL_DATA) $(BANSHEE_TARGET).mdb             $(DESTDIR)$(BACKENDDIR)
+	for ASM in $(BANSHEE_INDEXER_ASSEMBLIES); do \
+		$(INSTALL_DATA) $$ASM $(DESTDIR)$(BACKENDDIR); \
+	done;
+endif
 
 uninstall-local:
 if ENABLE_THUNDERBIRD
 	rm -f $(DESTDIR)$(BACKENDDIR)/$(THUNDERBIRD_TARGET)
 	rm -f $(DESTDIR)$(BACKENDDIR)/$(THUNDERBIRD_TARGET).mdb
 endif
+if ENABLE_BANSHEE
+	rm -f $(DESTDIR)$(BACKENDDIR)/$(BANSHEE_TARGET)
+	rm -f $(DESTDIR)$(BACKENDDIR)/$(BANSHEE_TARGET).mdb
+	for ASM in $(BANSHEE_INDEXER_ASSEMBLIES); do \
+		rm -f $(DESTDIR)$(BACKENDDIR)/`basename $$ASM`; \
+	done;
+endif
 if ENABLE_EVOLUTION
 	rm -f $(DESTDIR)$(BACKENDDIR)/$(EVO_DLL_TARGET)
 	rm -f $(DESTDIR)$(BACKENDDIR)/$(EVO_DLL_TARGET).mdb
@@ -912,6 +962,7 @@ EXTRA_DIST = \
 	$(DAEMON_CSFILES)			\
 	$(EVO_DLL_CSFILES)			\
 	$(THUNDERBIRD_CSFILES)			\
+	$(BANSHEE_CSFILES)			\
 	$(GOOGLE_BACKEND_CSFILES)		\
 	$(EXTRACT_CONTENT_CSFILES)		\
 	$(DUMP_INDEX_CSFILES)			\
@@ -958,6 +1009,8 @@ CLEANFILES = \
 	$(REMOVABLE_INDEX_WRAPPER)			\
 	$(THUNDERBIRD_TARGET)			\
 	$(THUNDERBIRD_TARGET).mdb		\
+	$(BANSHEE_TARGET)			\
+	$(BANSHEE_TARGET).mdb			\
 	$(GOOGLE_BACKEND_TARGET)		\
 	$(GOOGLE_BACKEND_TARGET).mdb		\
 	$(WEBINTERFACE_INDEX_XML)
Index: configure.in
===================================================================
--- configure.in.orig
+++ configure.in
@@ -22,6 +22,7 @@ EVOLUTION_SHARP_REQUIRED=0.13.3
 GSF_SHARP_REQUIRED=0.6
 GTK_REQUIRED=2.10.0
 AVAHI_SHARP_REQUIRED=0.6.10
+BANSHEE_REQUIRED=1.3.2
 
 ########################################################################
 
@@ -572,6 +573,26 @@ fi
 AM_CONDITIONAL(ENABLE_QT, test "x$enable_qt" = "xyes")
 AC_SUBST(QYOTO_ASSEMBLY)
 
+dnl -------------------------------------------------------
+
+AC_ARG_ENABLE([banshee],
+	AC_HELP_STRING([--disable-banshee], [Disable Banshee indexing]),
+	enable_banshee=$enableval,
+	enable_banshee=yes)
+
+AM_CONDITIONAL(ENABLE_BANSHEE, test "x$enable_banshee" = "xyes")
+
+if test "x$enable_banshee" = "xyes"; then
+	PKG_CHECK_MODULES(BANSHEE_INDEXER,
+		banshee-1-collection-indexer >= $BANSHEE_REQUIRED
+		ndesk-dbus-glib-1.0 >= $NDESK_DBUS_GLIB_REQUIRED)
+	asms=`$PKG_CONFIG --variable=Libraries banshee-1-collection-indexer`
+	for asm in $asms; do
+		BANSHEE_INDEXER_ASSEMBLIES="$BANSHEE_INDEXER_ASSEMBLIES $asm $asm.mdb"
+	done
+	AC_SUBST(BANSHEE_INDEXER_ASSEMBLIES)
+fi
+
 dnl ----------------------------------------------
 
 dnl Monodoc
@@ -677,6 +698,7 @@ echo "
 	Firefox Extension?	  yes
 	Epiphany Extension?	  ${enable_epiphany_extension}
 	Thunderbird Extension? 	  ${enable_tbird}
+	Banshee Backend? 	  ${enable_banshee}
 	Google Backends?          ${enable_google}
 
 	Monitor screensaver       ${have_xss}
Index: Filters/FilterAudio.cs
===================================================================
--- Filters/FilterAudio.cs.orig
+++ Filters/FilterAudio.cs
@@ -38,7 +38,8 @@ namespace Beagle.Filters {
 		{
 			// 1: Added duration and bitrate property
 			// 2. Use TagLib-Sharp for filtering. Also index lots of new properties provided by TagLib#
-			SetVersion (2);
+			// 3. Index both album artist and track artist; the generic artist tag should be track artist
+			SetVersion (3);
 			SetFileType ("audio");
 		}
 
@@ -108,6 +109,9 @@ namespace Beagle.Filters {
 			AddProperty (Beagle.Property.New ("dc:title", tag.Title));
 
 			foreach (string artist in tag.AlbumArtists)
+				AddProperty (Beagle.Property.New ("fixme:albumartist", artist));
+
+			foreach (string artist in tag.Artists)
 				AddProperty (Beagle.Property.New ("fixme:artist", artist));
 
 			foreach (string performer in tag.Performers)
