|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionGoogle has a number of services available for which no APIs exist currently. I aim to make APIs for such services, the first of those being Google Bookmarks. After lots of hours spent intercepting HTTP requests, I have finally created a class capable of retrieving, adding, and modifying bookmarks for a given account. To date, I have not found a single piece of code outside of FireFox extensions for utilizing the Google Bookmarks service. I hope you find this of use. I have some rather interesting ideas for this class so watch out for more articles. Using the ClassThere are only 5 steps to implementing this control, 4 if you only intend to read items.
Declare an InstanceBecause we will assign an event handler to this, you will want to declare it globally: GBDemoClass.GoogleBookmarks GBookmarks = new GoogleBookmarks();
Define an event handler in the Form private void Form1_Load(object sender, EventArgs e)
{
GBookmarks.BookmarksRefreshed += new EventHandler
Handle the EventIn the event handler, the only var passed is void GBookmarks_BookmarksRefreshed(object sender, BookmarksRefreshedEventArgs e)
{
listView1.Items.Clear();
foreach (GBDemoClass.BookmarkProperties bookmark in GBookmarks)
{
ListViewItem iBookmark = new ListViewItem();
iBookmark.Text = bookmark.Title;
iBookmark.SubItems.Add(bookmark.URL);
iBookmark.SubItems.Add(bookmark.Category);
iBookmark.Subitems.Add(bookmark.Id);
listView1.Items.Add(iBookmark);
}
}
Now we just need to initialize the class, call GBookmarks.Init("UserName", "Password");
GBookmarks.Refresh();
When the bookmarks have been retrieved, the Add / Edit / RemoveGBookmarks.Add(string Category, string Title, string URL);
GBookmarks.Remove(string ID);
The Additionally, Google has integrity checks on the server side and you are unable to add a URL that would not be valid. How It All WorksFor those who want to know more about how this works behind the scenes, read on. Initializing the ClassDuring initialization, the public void Init(string username, string password)
{
if (string.IsNullOrEmpty(username))
{
throw new ArgumentNullException("username");
}
if (string.IsNullOrEmpty(password))
{
throw new ArgumentNullException("password");
}
_Username = username;
_Password = password;
}
Before calling Let's move on to the next function, public bool Refresh()
{
if (string.IsNullOrEmpty(_Username) || string.IsNullOrEmpty(_Password))
{
throw new InvalidOperationException("Username or Password not set");
}
_Bookmarks.Clear();
if (!UpdateBookmarks())
return false;
OnBookmarksRefreshed(_Username);
UpdateTimer();
return true;
}
Prior to triggering the private bool UpdateBookmarks()
{
CheckLogin();
DownloadBookmarksRSS();
return ParseRSS();
}
private void CheckLogin()
{
if (!ValidateCookies())
Login();
}
In this function, we first determine if we are logged in already or not. This is done with the use of cookies and the Our next step is to perform the login. We do this in private void Login()
{
string PostData = EncodePostData(
new string[] { "service", "nui", "hl", "Email", "Passwd",
"PersistentCookie", "rmShown", "continue" },
new string[] { "bookmarks", "1", "en", _Username, _Password, "yes", "1",
"http://www.google.com/bookmarks/lookup%3Foutput%3Dxml%26num%3D10000&" }
);
POST(_BookmarksLoginURL, PostData);
}
This function URLEncodes the post data and calls Now it is time to actually retrieve the bookmarks. This is done in the private void DownloadBookmarksRSS()
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_BookmarksRssUri);
request.CookieContainer = _CookieContainer;
using (WebResponse response = request.GetResponse())
using (StreamReader reader =
new StreamReader(response.GetResponseStream(), Encoding.UTF8))
{
_Data = reader.ReadToEnd();
}
}
catch
{
_Data = string.Empty;
}
}
Pretty simple huh? Lucky for us, Google now includes the private bool ParseRSS()
{
if (!string.IsNullOrEmpty(_Data))
{
string title = string.Empty;
string url = string.Empty;
string category = string.Empty;
string guid = string.Empty;
string id = string.Empty;
using (XmlReader reader = XmlReader.Create(new StringReader(_Data)))
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "item":
//New Item
if (title != string.Empty)
if (id != string.Empty)
_Bookmarks.Add(new BookmarkProperties(id, guid, title, category, url));
title = string.Empty;
url = string.Empty;
category = string.Empty;
guid = string.Empty;
id = string.Empty;
break;
case "title":
title = reader.ReadString();
break;
case "link":
url = reader.ReadString();
break;
case "smh:signature":
_Signature = reader.ReadString();
break;
case "guid":
guid = reader.ReadString();
break;
case "smh:bkmk_id":
id = reader.ReadString();
break;
case "smh:bkmk_label":
category = reader.ReadString();
break;
}
}
}
if (title != string.Empty)
if (id != string.Empty)
_Bookmarks.Add(new BookmarkProperties(id, guid, title, category, url));
}
return true;
}
return false;
}
We must check for the existence of an The RSS data is received as XML, so here we use an After all of these functions have executed, the Adding and EditingAs mentioned before, the public string Add(string Category, string Name, string URL)
{
CheckLogin();
string PostString = EncodePostData(
new string[] { "q", "title", "labels", "zx" },
new string[]
{ URL, Name, Category, Convert.ToString(DateTime.Now.Second * 3175) }
);
WebResponse response = POST("http://www.google.com/bookmarks/mark", PostString);
string respData;
if (response == null)
respData = "";
else
using (StreamReader reader =
new StreamReader(response.GetResponseStream(), Encoding.UTF8))
{
respData = reader.ReadToEnd();
}
return respData;
}
You'll notice the var Previously (less than 24 hours ago!) I found that adding an existing URL with a blank category and title caused it to be removed; this does not seem to be the case anymore and if done now will only cause the category to be cleared. Through some more sniffing, I determined that removing an entry is identical to adding except the Thanks to Steven HansenOk, so you saw the
private List
Additionally, the public class GoogleBookmarks : IEnumerable
Have a look at the code for any details I have not mentioned in here. In ClosingThis class took a lot of trial and error and a lot of research to complete. As stated previously, I know of no other control, documentation, or so much as an example of accomplishing this task in any .NET language. I hope you find this article useful and if you do, please vote! I also welcome any and all feedback or comments. Find a bug? Know of a way to improve it? Post it here and I will most likely incorporate it into the next release. Enjoy! Current Limitations
History
|
||||||||||||||||||||||