Thumbnail file hits. Based on a patch from D Bera
[beagle.git] / beagled / BlamQueryable / BlamQueryable.cs
blob0f84d731817fc976a54076bfbc2c953c41b4ce5e
1 //
2 // BlamQueryable.cs
3 //
4 // Copyright (C) 2004 Novell, Inc.
5 //
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 // DEALINGS IN THE SOFTWARE.
27 using System;
28 using System.IO;
29 using System.Collections;
30 using System.Threading;
32 using System.Xml;
33 using System.Xml.Serialization;
35 using Beagle.Daemon;
36 using Beagle.Util;
38 namespace Beagle.Daemon.BlamQueryable {
40 [QueryableFlavor (Name="Blam", Domain=QueryDomain.Local, RequireInotify=false)]
41 public class BlamQueryable : LuceneFileQueryable, IIndexableGenerator {
43 private static Logger log = Logger.Get ("BlamQueryable");
45 string blam_dir;
46 FileInfo blam_file;
48 public BlamQueryable () : base ("BlamIndex")
50 blam_dir = Path.Combine (Path.Combine (PathFinder.HomeDir, ".gnome2"), "blam");
51 blam_file = new FileInfo (Path.Combine (blam_dir, "collection.xml"));
54 /////////////////////////////////////////////////
56 public override void Start ()
58 base.Start ();
60 ExceptionHandlingThread.Start (new ThreadStart (StartWorker));
63 private void StartWorker ()
65 if (!Directory.Exists (blam_dir)) {
66 GLib.Timeout.Add (60000, new GLib.TimeoutHandler (CheckForExistence));
67 return;
70 if (Inotify.Enabled) {
71 Inotify.EventType mask = Inotify.EventType.CloseWrite;
72 Inotify.Subscribe (blam_dir, OnInotifyEvent, mask);
73 } else {
74 FileSystemWatcher fsw = new FileSystemWatcher ();
75 fsw.Path = blam_dir;
76 fsw.Filter = blam_file.Name;
78 fsw.Changed += new FileSystemEventHandler (OnChangedEvent);
79 fsw.Created += new FileSystemEventHandler (OnChangedEvent);
81 fsw.EnableRaisingEvents = true;
84 if (File.Exists (blam_file.FullName))
85 Index ();
88 private bool CheckForExistence ()
90 if (!Directory.Exists (blam_dir))
91 return true;
93 this.Start ();
95 return false;
98 /////////////////////////////////////////////////
100 // Modified event using Inotify
101 private void OnInotifyEvent (Inotify.Watch watch,
102 string path,
103 string subitem,
104 string srcpath,
105 Inotify.EventType type)
107 if (subitem != blam_file.Name)
108 return;
110 Index ();
113 // Modified/Created event using FSW
114 private void OnChangedEvent (object o, FileSystemEventArgs args)
116 Index ();
119 /////////////////////////////////////////////////
121 private void Index ()
123 log.Debug ("Creating blam indexable generator");
124 Scheduler.Task task = NewAddTask (this);
125 task.Tag = "Blam";
126 ThisScheduler.Add (task);
129 /////////////////////////////////////////////////
131 // IIndexableGenerator implementation
133 private ChannelCollection collection = null;
134 private IEnumerator channel_enumerator = null;
135 private IEnumerator item_enumerator = null;
137 public Indexable GetNextIndexable ()
139 Channel channel = (Channel) this.channel_enumerator.Current;
140 Item item = (Item) this.item_enumerator.Current;
142 Uri uri = new Uri (String.Format ("feed:{0};item={1}", channel.Url, item.Id));
144 Indexable indexable = new Indexable (uri);
145 indexable.ParentUri = UriFu.PathToFileUri (blam_file.FullName);
146 indexable.MimeType = "text/html";
147 indexable.Type = "FeedItem";
148 indexable.Timestamp = item.PubDate;
150 indexable.AddProperty (Property.New ("dc:title", item.Title));
151 indexable.AddProperty (Property.New ("fixme:author", item.Author));
152 indexable.AddProperty (Property.NewDate ("fixme:published", item.PubDate));
153 indexable.AddProperty (Property.NewKeyword ("fixme:itemuri", item.Link));
154 indexable.AddProperty (Property.NewKeyword ("fixme:webloguri", channel.Url));
156 string img = null;
157 int i = item.Text.IndexOf ("<img src=\"");
158 if (i != -1) {
159 i += "<img src=\"".Length;
160 int j = item.Text.IndexOf ("\"", i);
161 if (j != -1)
162 img = item.Text.Substring (i, j-i);
165 if (img != null) {
166 string path = Path.Combine (Path.Combine (blam_dir, "Cache"),
167 img.GetHashCode ().ToString ());
168 indexable.AddProperty (Property.NewUnsearched ("fixme:cachedimg", path));
171 StringReader reader = new StringReader (item.Text);
172 indexable.SetTextReader (reader);
174 return indexable;
177 public bool HasNextIndexable ()
179 if (this.collection == null) {
180 if (IsUpToDate (blam_file.FullName))
181 return false;
183 try {
184 this.collection = ChannelCollection.LoadFromFile (blam_file.FullName);
185 } catch (Exception e) {
186 log.Warn ("Could not open Blam! channel list: " + e);
187 return false;
190 if (this.collection.Channels == null || this.collection.Channels.Count == 0) {
191 this.collection = null;
192 return false;
195 this.channel_enumerator = this.collection.Channels.GetEnumerator ();
198 while (this.item_enumerator == null || !this.item_enumerator.MoveNext ()) {
199 Channel channel;
201 do {
202 if (!this.channel_enumerator.MoveNext ()) {
203 this.collection = null;
204 this.channel_enumerator = null;
205 return false;
208 channel = (Channel) this.channel_enumerator.Current;
209 } while (channel.Items == null || channel.Items.Count == 0);
211 this.item_enumerator = channel.Items.GetEnumerator ();
214 return true;
217 public string StatusName {
218 get { return null; }
222 /////////////////////////////////////////////////
224 // Classes from Blam! sources for deserialization
226 public class ChannelCollection {
228 private ArrayList mChannels;
230 [XmlElement ("Channel", typeof (Channel))]
231 public ArrayList Channels {
232 get { return mChannels; }
233 set { mChannels = value; }
236 public static ChannelCollection LoadFromFile (string filename)
238 XmlSerializer serializer = new XmlSerializer (typeof (ChannelCollection));
239 ChannelCollection collection;
241 Stream stream = new FileStream (filename,
242 FileMode.Open,
243 FileAccess.Read,
244 FileShare.ReadWrite);
245 XmlTextReader reader = new XmlTextReader (stream);
247 collection = (ChannelCollection) serializer.Deserialize (reader);
248 reader.Close ();
249 stream.Close ();
251 return collection;
255 public class Channel
257 [XmlAttribute] public string Name = "";
258 [XmlAttribute] public string Url = "";
260 [XmlAttribute] public string LastModified = "";
261 [XmlAttribute] public string ETag = "";
263 ArrayList mItems;
265 [XmlElement ("Item", typeof (Item))]
266 public ArrayList Items {
267 get { return mItems; }
268 set { mItems = value; }
272 public class Item
274 [XmlAttribute] public string Id = "";
275 [XmlAttribute] public bool Unread = true;
276 [XmlAttribute] public string Title = "";
277 [XmlAttribute] public string Text = "";
278 [XmlAttribute] public string Link = "";
279 [XmlAttribute] public DateTime PubDate;
280 [XmlAttribute] public string Author = "";