<%@ Page Language="C#" %>
<%@ Import Namespace="System.Collections.Generic" %>
<script runat="server">
/*
* The code below was hacked together quite quickly - it is not an example
* of well structured, efficient c#. The string manipulation could probably
* have been done more neatly with Regular Expressions - it was faster for
* me to write the Extract() method than lookup the regex syntax... I can
* never remember that stuff.
*
* It was inspired by these blog posts
* http://conceptdev.blogspot.com/2008/12/using-seadragon-iphone-with-photozoom.html
* http://conceptdev.blogspot.com/2008/12/seadragon-returns-deep-zoom-on-iphone.html
* and the instructions here
* http://livelabs.com/seadragon-mobile/using-your-own-images/
*
* Upload your photos to
* http://photozoom.mslivelabs.com/
* via the website or Deep Zoom Composer to give it a try.
*
* Feel free to modify the code below for your own use.
*
* Craig Dunn 29-Dec-2008
*/
/// <summary>
/// Represents a specific DeepZoom image on PhotoZoom
/// eg. http://photozoom.mslivelabs.com/Album.aspx?alias=mike&album=1
/// </summary>
class Album
{
public string Name;
public string Thumbnail;
public string SilverlightPageUrl;
public string DeepZoomCollectionUrl;
public string UniqueIdentifier;
public string SourceUrl;
/// <summary>Useful for debugging</summary>
public string ToHtml() {
return String.Format("album [{0}] preview <img src='{1}' /> dzi <a href='http://photozoom.mslivelabs.com/{2}'>silverlight</a> <a href='{3}'>xml</a><br />", Name, Thumbnail, SilverlightPageUrl, DeepZoomCollectionUrl);
}
}
/// <summary>
/// Collection of albums to display in the RSS feed.
/// Extracted from a PhotoZoom 'user' page,
/// eg. http://photozoom.mslivelabs.com/Albums.aspx?alias=eflaten
/// </summary>
List<Album> Albums = new List<Album>();
/// <summary>
/// PhotoZoom user name eg. craig
/// </summary>
string Author = "";
/// <summary>
/// 1. Get the username from querystring parameter
/// 2. Download the PhotoZoom 'index' page for that username
/// 3. Extract all the album data (Url, thumbnail image) from the 'index' page
/// 4. Download each individual album page to extract the Deep Zoom image/collection Xml Url
/// 5. Display as an RSS feed according to http://livelabs.com/seadragon-mobile/using-your-own-images/
/// </summary>
void Page_Load()
{
Author = Convert.ToString(Request.QueryString["user"]);
if (String.IsNullOrEmpty(Author)) Author = "craig"; // that's me
Uri uri = new Uri("http://photozoom.mslivelabs.com/Albums.aspx?alias=" + Author);
string content = DownloadUri(uri);
string div; int last = 0;
do /* for each Album in the user index */
{
div = Extract(content, @"<div class=""individualAlbumView"">", "</div>", ref last);
string h2 = Extract(div, @"<h2>", "</h2>");
string p = Extract(div, @"<p>", "</p>");
if (p.Length > 0 && h2.Length > 0)
{ // we have album _with_ content (ie. not empty)
string albumName = "";
Album album = new Album();
album.SilverlightPageUrl = AHref(h2).Replace("&", "&");
album.Thumbnail = ImgSrc(p, ref albumName).Replace("&", "&");
album.Name = Server.HtmlEncode(albumName).Replace("&", "&");
string silverlightPageUrl = "http://photozoom.mslivelabs.com/" + album.SilverlightPageUrl;
Uri uri2 = new Uri(silverlightPageUrl);
div = DownloadUri(uri2);
string objectTag = Extract(div, @"<object id=""PhotoZoomCollectionViewer""", "</object>");
string param = Extract(objectTag, @"collectionUrl=", @"""");
album.DeepZoomCollectionUrl = Server.UrlDecode(Server.HtmlDecode(param));
album.UniqueIdentifier = Guid.NewGuid().ToString();
album.SourceUrl = (silverlightPageUrl + "&indPics=true").Replace("&", "&");
Albums.Add(album);
//Response.Write(album.ToHtml()); // debug
}
else
{
// empty album / test albums can appear in PhotoZoom - but are not useful
}
} while (div.Length > 0);
Response.ContentType = "text/xml";
}
/// <summary>
/// Download content (as text) from a supplied link
/// </summary>
/// <remarks>
/// Copied this chunk of code from www.searcharoo.net code base.
/// </remarks>
/// <param name="uri">Html page to retrieve</param>
/// <returns>Html string</returns>
private string DownloadUri(Uri uri)
{
string content = "", Encoding = "";
System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(uri.AbsoluteUri);
req.AllowAutoRedirect = true;
req.MaximumAutomaticRedirections = 3;
req.UserAgent = "Mozilla/6.0 (MSIE 6.0; Windows NT 5.1; ROBOT; DeepZoomPublisher.com)";
req.KeepAlive = true;
req.Timeout = 3 * 1000; // 3 secinds
// Get the stream from the returned web response
System.Net.HttpWebResponse webresponse = null;
try
{
webresponse = (System.Net.HttpWebResponse)req.GetResponse();
}
catch { }
if (webresponse != null)
{
string enc = "utf-8"; // default
if (webresponse.ContentEncoding != String.Empty)
{
// Use the HttpHeader Content-Type in preference to the one set in META
Encoding = webresponse.ContentEncoding;
}
else if (Encoding == String.Empty)
{
Encoding = enc; // default
}
//http://www.c-sharpcorner.com/Code/2003/Dec/ReadingWebPageSources.asp
using (System.IO.StreamReader stream = new System.IO.StreamReader
(webresponse.GetResponseStream(), System.Text.Encoding.GetEncoding(Encoding)))
{
content = stream.ReadToEnd();//this.All = stream.ReadToEnd();
}
}
return content;
}
/// <summary>
/// Find and return the characters between two strings
/// </summary>
/// <returns>string found between the supplied strings, or String.Empty</returns>
private string Extract(string from, string start, string to)
{
int i = 0;
return Extract(from, start, to, ref i);
}
/// <summary>
/// Find and return the characters between two strings
/// </summary>
/// <returns>string found between the supplied strings, or String.Empty</returns>
/// <param name="last">
/// returns the 'last' found index, so subsequent calls to this method
/// can begin searching _after_ that match
/// </param>
private string Extract(string from, string start, string to, ref int last)
{
string ret = "";
int startPos = from.IndexOf(start, last);
if (startPos > 0)
{
int endPos = from.IndexOf(to, startPos);
if (endPos > startPos)
{
ret = from.Substring(startPos + start.Length, endPos - startPos - start.Length );
last = endPos + to.Length;
}
}
return ret;
}
/// <summary>
/// Extract the url from a link tag
/// </summary>
/// <remarks>
/// Copied this chunk of code from www.searcharoo.net code base.
/// </remarks>
/// <param name="from">string containing an html anchor tag</param>
/// <returns>the href from the anchor tag</returns>
private string AHref(string from)
{
string link = String.Empty;
foreach (Match match in Regex.Matches(from
, @"(?<anchor><\s*(a|area|frame|iframe|img)\s*(?:(?:\b\w+\b\s*(?:=\s*(?:""[^""]*""|'[^']*'|[^""'<> ]+)\s*)?)*)?\s*>)"
, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture))
{
// Parse ALL attributes from within tags... IMPORTANT when they're out of order!!
// in addition to the 'href' attribute, there might also be 'alt', 'class', 'style', 'area', etc...
// there might also be 'spaces' between the attributes and they may be ", ', or unquoted
foreach (Match submatch in Regex.Matches(match.Value.ToString()
, @"(?<name>\b\w+\b)\s*=\s*(""(?<value>[^""]*)""|'(?<value>[^']*)'|(?<value>[^""'<> \s]+)\s*)+"
, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture))
{
if ("href" == submatch.Groups[1].ToString().ToLower())
{
link = submatch.Groups[2].ToString();
}
}
if (link != String.Empty) break;
}
return link;
}
/// <summary>
/// Extract the source and alt-text from an image tag
/// </summary>
/// <remarks>
/// Copied this chunk of code from www.searcharoo.net code base.
/// </remarks>
/// <param name="from">string containing an html image tag</param>
/// <param name="alt">returns the alt text of the image, if present</param>
/// <returns>the url to the image source</returns>
private string ImgSrc(string from, ref string alt)
{
string link = String.Empty;
foreach (Match match in Regex.Matches(from
, @"(?<anchor><\s*(a|area|frame|iframe|img)\s*(?:(?:\b\w+\b\s*(?:=\s*(?:""[^""]*""|'[^']*'|[^""'<> ]+)\s*)?)*)?\s*/>)"
, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture))
{
// Parse ALL attributes from within tags... IMPORTANT when they're out of order!!
// in addition to the 'href' attribute, there might also be 'alt', 'class', 'style', 'area', etc...
// there might also be 'spaces' between the attributes and they may be ", ', or unquoted
foreach (Match submatch in Regex.Matches(match.Value.ToString()
, @"(?<name>\b\w+\b)\s*=\s*(""(?<value>[^""]*)""|'(?<value>[^']*)'|(?<value>[^""'<> \s]+)\s*)+"
, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture))
{
if ("src" == submatch.Groups[1].ToString().ToLower())
{ // [v6] indexes images <img src="???">
link = submatch.Groups[2].ToString();
}
if ("alt" == submatch.Groups[1].ToString().ToLower())
{
alt = submatch.Groups[2].ToString();
}
}
if (link != String.Empty) break;
}
return link;
}
</script><?xml version="1.0"?>
<rss version="2.0">
<channel>
<title>PhotoZoom <%=Author %></title>
<link>deepzoompublisher.com/PhotoZoom</link>
<description>Rss feed generator for Microsoft Labs PhotoZoom</description>
<language>en-us</language>
<%foreach (Album album in Albums)
{%>
<item>
<category>Photos</category>
<guid><%=album.UniqueIdentifier%></guid>
<title><%=album.Name %></title>
<source url="<%=album.SourceUrl %>"><%=Author %> on PhotoZoom</source>
<enclosure type="text/xml" length="0"
url="<%=album.DeepZoomCollectionUrl%>" />
<enclosure type="image/jpeg" length="0"
url="<%=album.Thumbnail %>" />
</item>
<%} %>
</channel>
</rss>