beagle r4871 - branches/beagle-abock-branch/beagled/BansheeQueryable



Author: abock
Date: Sat Oct 11 03:52:20 2008
New Revision: 4871
URL: http://svn.gnome.org/viewvc/beagle?rev=4871&view=rev

Log:
First pass at implementing a Queryable to consume the new Banshee Collection Indexer DBus API through the light weight helper library, Banshee.CollectionIndexer.dll

Added:
   branches/beagle-abock-branch/beagled/BansheeQueryable/
   branches/beagle-abock-branch/beagled/BansheeQueryable/BansheeIndexableGenerator.cs
   branches/beagle-abock-branch/beagled/BansheeQueryable/BansheeIndexer.cs
   branches/beagle-abock-branch/beagled/BansheeQueryable/BansheeQueryable.cs
   branches/beagle-abock-branch/beagled/BansheeQueryable/BansheeQueryable.csproj
   branches/beagle-abock-branch/beagled/BansheeQueryable/BansheeQueryable.sln

Added: branches/beagle-abock-branch/beagled/BansheeQueryable/BansheeIndexableGenerator.cs
==============================================================================
--- (empty file)
+++ branches/beagle-abock-branch/beagled/BansheeQueryable/BansheeIndexableGenerator.cs	Sat Oct 11 03:52:20 2008
@@ -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
+
+    }
+}

Added: branches/beagle-abock-branch/beagled/BansheeQueryable/BansheeIndexer.cs
==============================================================================
--- (empty file)
+++ branches/beagle-abock-branch/beagled/BansheeQueryable/BansheeIndexer.cs	Sat Oct 11 03:52:20 2008
@@ -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
+
+    }
+}

Added: branches/beagle-abock-branch/beagled/BansheeQueryable/BansheeQueryable.cs
==============================================================================
--- (empty file)
+++ branches/beagle-abock-branch/beagled/BansheeQueryable/BansheeQueryable.cs	Sat Oct 11 03:52:20 2008
@@ -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 ();
+            }
+        }
+    }
+}

Added: branches/beagle-abock-branch/beagled/BansheeQueryable/BansheeQueryable.csproj
==============================================================================
--- (empty file)
+++ branches/beagle-abock-branch/beagled/BansheeQueryable/BansheeQueryable.csproj	Sat Oct 11 03:52:20 2008
@@ -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

Added: branches/beagle-abock-branch/beagled/BansheeQueryable/BansheeQueryable.sln
==============================================================================
--- (empty file)
+++ branches/beagle-abock-branch/beagled/BansheeQueryable/BansheeQueryable.sln	Sat Oct 11 03:52:20 2008
@@ -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



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