I store many of my photographs on smugmug (see http://pitonyak.smugmug.com/). They gave me a "coupon" to use that will save you $5 on your renewal (and if you use it, I save $10 on mine). The code is: Rl0h94ubYv13o
The upload client from Linux does not work well, so I am investigating accessing the website using restful web services. Step 1, obtain an account. Step 2, request a key that allows me to use the web services. Note that the key is free for the asking and they respond promptly.
For my first attempt, I connected directly from my web browser. Obviously, my login email address is not x@y.com, my password is not 1234, and my APIKey is not abcdefg, but, if it were, I can go to this URL to login.
https://api.smugmug.com/hack/rest/1.2.0/?method=smugmug.login.withPasswo...
I received the following reply:
<rsp stat="ok"><method>smugmug.login.withPassword</method>
<Login PasswordHash="xyzzy" AccountType="Power" FileSizeLimit="12582912" SmugVault="0"> <Session id="gfedcba"/> <User id="94628" NickName="pitonyak" DisplayName="pitonyak"/> </Login></rsp>After parsing the XML, I made another call to obtain information regarding all of my albums:
https://api.smugmug.com/hack/rest/1.2.0/?SessionID=gfedcba&Heavy=1&metho...
A representative reply showing only a single album is shown below:
<rsp stat="ok"><method>smugmug.albums.get</method>
<Albums> <Album id="1" Key="2" Position="1" ImageCount="2" Title="Lib 1" Description="Whatever" Keywords="" Public="1" Password="" PasswordHint="" Printable="1" Filenames="0" Comments="1" External="1" Originals="1" EXIF="1" Share="1" SortMethod="Position" SortDirection="0" LastUpdated="2007-08-21 19:53:25" FamilyEdit="0" FriendEdit="0" HideOwner="0" CanRank="1" Clean="0" Geography="1" SmugSearchable="1" WorldSearchable="1" SquareThumbs="0" ColorCorrection="2" X2Larges="1" X3Larges="1" Header="0" Protected="0" UnsharpRadius="1" UnsharpSigma="1" UnsharpAmount="0.2" UnsharpThreshold="0.05"> <Highlight id="0"/> <Community id="0"/> <Template id="0"/> <Category id="0" Name="Other"/> </Album> </Albums></rsp>Don't forget to logout
https://api.smugmug.com/hack/rest/1.2.0/?SessionID=gfedcba&method=smugmu...
My first attempt was using Java. The HashMap contained a list of key/value pairs, such as APIKey/abcdefg. The method is a string such as "smugmug.logout".
public String callMethod(HashMap<String, String> parameters, String method)
{if (parameters == null)
{parameters = new HashMap<String, String>();
}if (method != null && method.length() > 0)
{if (parameters.containsKey(SmugMugConstants.XmlMethod))
{parameters.remove(SmugMugConstants.XmlMethod);
}parameters.put(SmugMugConstants.XmlMethod, method);
}if (!parameters.containsKey(SmugMugConstants.ArgAPIKey))
{parameters.put(SmugMugConstants.ArgAPIKey, apiKey);
}String response = null;
try {URL url = new URL(baseEndPoint + EncoderHelper.buildEncodedURL(parameters, "?", encodeArguments));
System.out.println("Using URL: " + url.toString());
//make connection, use post mode, and send queryURLConnection urlc = url.openConnection();
urlc.setDoOutput(true);
urlc.setAllowUserInteraction(false);
PrintStream ps = new PrintStream(urlc.getOutputStream());
//ps.print(EncoderHelper.buildEncodedURL(parameters, "?", false));ps.close();
//retrieve resultBufferedReader br = new BufferedReader(new InputStreamReader(urlc.getInputStream()));
String str;
StringBuffer sb = new StringBuffer();
while ((str = br.readLine()) != null)
{sb.append(str);
sb.append("\n");
}br.close();
response = sb.toString();
logger.info("Response = " + response);
}catch (Exception e)
{logger.severe("Failed REST service call.\n" + exceptionStacktraceToString(e));
response = null;
}return response;
}This is the encoder helper class.
public class EncoderHelper
{public static String Encoding = "UTF-8";
/** * Build the argument portion of a URL. Iterate through all entries in the hash table and * build a string such as "?key1=value1&key2=value2&key3=value3". * @param parameters Map of key/value pairs that will become the argument string. * @param leadingString Usually a "?", this is the first character in the string. * @param encodeValues Determines if values are URL encoded. * @return * @throws java.io.UnsupportedEncodingException */public static String buildEncodedURL(HashMap<String, String> parameters, String leadingString, boolean encodeValues) throws UnsupportedEncodingException
{StringBuilder sb = new StringBuilder();
if (parameters != null)
{String value = null;
for (String key : parameters.keySet())
{value = parameters.get(key);
if (key != null && key.length() > 0 && value != null)
{if (sb.length() == 0)
{if (leadingString != null)
{sb.append(leadingString);
} } else {sb.append("&");
}sb.append(key + "=");
if (encodeValues)
{sb.append(URLEncoder.encode(value, Encoding));
} else {sb.append(value);
} } } }return sb.toString();
}}The driver code sets the arguments and makes the call to process the arguments:
public SmugMugLoginEntity login(String emailAddress, String password) throws XMLStreamException, IllegalAccessException
{SmugMugLoginEntity entity = new SmugMugLoginEntity();
HashMap<String, String> parameters = new HashMap<String, String>();
setArgumentValue(parameters, SmugMugConstants.ArgEmailAddress, emailAddress, true);
setArgumentValue(parameters, SmugMugConstants.ArgPassword, password, true);
String result = callMethod(parameters, CmdLoginWithPassword);
if (!entity.processXML(result, CmdLoginWithPassword, true))
{return null;
}return entity;
}public SmugMugAlbumsEntity getAlbumsForAccount(String session, boolean verboseInformation) throws XMLStreamException, IllegalAccessException
{SmugMugAlbumsEntity entity = new SmugMugAlbumsEntity();
HashMap<String, String> parameters = new HashMap<String, String>();
setArgumentValue(parameters, SmugMugConstants.ArgSessionID, session, true);
if (verboseInformation)
{setArgumentValue(parameters, SmugMugConstants.ArgHeavy, "1", true);
}String result = callMethod(parameters, CmdAlbumsGet);
if (!entity.processXML(result, CmdAlbumsGet, true))
{return null;
}return entity;
}public SmugMugImagesEntity getImagesForAlbum(String session, boolean verboseInformation, String sitePassword, SmugMugAlbumEntity entity) throws XMLStreamException, IllegalAccessException
{String albumKey = entity.getAlbumKey();
String albumId = entity.getAlbumId();
String albumPassword = entity.getAlbumPassword();
return getImagesForAlbum(session, albumId, verboseInformation, albumPassword, sitePassword, albumKey);
} /** * Retrieves a list of images for a given album. * @param session * @param albumId * @param verboseInformation * @param albumPassword * @param sitePassword * @param albumKey * @return * @throws javax.xml.stream.XMLStreamException * @throws java.lang.IllegalAccessException */public SmugMugImagesEntity getImagesForAlbum(String session, String albumId, boolean verboseInformation, String albumPassword, String sitePassword, String albumKey) throws XMLStreamException, IllegalAccessException
{SmugMugImagesEntity entity = new SmugMugImagesEntity();
HashMap<String, String> parameters = new HashMap<String, String>();
setArgumentValue(parameters, SmugMugConstants.ArgSessionID, session, true);
setArgumentValue(parameters, SmugMugConstants.ArgAlbumID, albumId, true);
setArgumentValue(parameters, SmugMugConstants.ArgAlbumKey, albumKey, true);
if (albumPassword != null)
{setArgumentValue(parameters, SmugMugConstants.ArgPassword, albumPassword, true);
}if (sitePassword != null)
{setArgumentValue(parameters, SmugMugConstants.ArgSitePassword, sitePassword, true);
}if (verboseInformation)
{setArgumentValue(parameters, SmugMugConstants.ArgHeavy, "1", true);
}String result = callMethod(parameters, CmdImagesGet);
if (!entity.processXML(result, CmdImagesGet, true))
{return null;
}return entity;
} /** * This method will return camera and photograph details about the image * specified by ImageID. The Album must be owned by the Session holder, * or else be Public (if password-protected, a Password must be provided), * to return results. Otherwise, an "invalid user" faultCode will result. * Additionally, the album owner must have specified that EXIF data is * allowed. Note that many photos have no EXIF data, so an empty or * partially returned result is normal. * @param session Current Session Id * @param imageId Desired Image Id * @param albumPassword Password for the album, or NULL of not required. * @param sitePassword Password for the site, or NULL if not required. * @param imageKey Key for the desired Image. * @return Image EXIF information. * @throws javax.xml.stream.XMLStreamException * @throws java.lang.IllegalAccessException */public SmugMugImageEntity getImageExif(String session, String imageId, String albumPassword, String sitePassword, String imageKey) throws XMLStreamException, IllegalAccessException
{SmugMugImageEntity entity = new SmugMugImageEntity();
HashMap<String, String> parameters = new HashMap<String, String>();
setArgumentValue(parameters, SmugMugConstants.ArgSessionID, session, true);
setArgumentValue(parameters, SmugMugConstants.ArgImageID, imageId, true);
setArgumentValue(parameters, SmugMugConstants.ArgImageKey, imageKey, true);
if (albumPassword != null)
{setArgumentValue(parameters, SmugMugConstants.ArgPassword, albumPassword, true);
}if (sitePassword != null)
{setArgumentValue(parameters, SmugMugConstants.ArgSitePassword, sitePassword, true);
}String result = callMethod(parameters, CmdImagesGetExif);
if (!entity.processXML(result, CmdImagesGetExif, true))
{return null;
}return entity;
} /** * This method will return details about the image specified by ImageID. * The Album must be owned by the Session holder, or else be Public * (if password-protected, a Password must be provided), to return results.. * Otherwise, an "invalid user" faultCode will result. Additionally, * some fields are only returned to the Album owner. * @param session Current Session Id * @param imageId Desired Image Id * @param albumPassword Password for the album, or NULL of not required. * @param sitePassword Password for the site, or NULL if not required. * @param imageKey Key for the desired Image. * @return Information for a specific image. * @throws javax.xml.stream.XMLStreamException * @throws java.lang.IllegalAccessException */public SmugMugImageEntity getImageInfo(String session, String imageId, String albumPassword, String sitePassword, String imageKey) throws XMLStreamException, IllegalAccessException
{SmugMugImageEntity entity = new SmugMugImageEntity();
HashMap<String, String> parameters = new HashMap<String, String>();
setArgumentValue(parameters, SmugMugConstants.ArgSessionID, session, true);
setArgumentValue(parameters, SmugMugConstants.ArgImageID, imageId, true);
setArgumentValue(parameters, SmugMugConstants.ArgImageKey, imageKey, true);
if (albumPassword != null)
{setArgumentValue(parameters, SmugMugConstants.ArgPassword, albumPassword, true);
}if (sitePassword != null)
{setArgumentValue(parameters, SmugMugConstants.ArgSitePassword, sitePassword, true);
}String result = callMethod(parameters, CmdImagesGetInfo);
if (!entity.processXML(result, CmdImagesGetInfo, true))
{return null;
}return entity;
} /** * Logout a session ID. * @param session Current session ID. * @throws javax.xml.stream.XMLStreamException */public void logout(String session) throws XMLStreamException
{HashMap<String, String> parameters = new HashMap<String, String>();
setArgumentValue(parameters, SmugMugConstants.ArgSessionID, session, true);
String x = callMethod(parameters, CmdLogout);
}public SmugMugAlbumEntity getAlbumInfo(String session, String albumID, String albumKey, String albumPassword) throws XMLStreamException, IllegalAccessException
{SmugMugAlbumEntity entity = new SmugMugAlbumEntity();
HashMap<String, String> parameters = new HashMap<String, String>();
setArgumentValue(parameters, SmugMugConstants.ArgSessionID, session, true);
setArgumentValue(parameters, SmugMugConstants.ArgAlbumKey, albumKey, false);
setArgumentValue(parameters, SmugMugConstants.ArgAlbumID, albumID, false);
setArgumentValue(parameters, SmugMugConstants.ArgPassword, albumPassword, false);
String result = callMethod(parameters, CmdAlbumsGetInfo);
if (!entity.processXML(result, CmdAlbumsGetInfo, true))
{return null;
}return entity;
} /** * Set a key/value pair, overwriting any existing key/value pair. * @param parameters key/value pairs * @param key * @param value * @param forceValue If true, then value can not be null. */public static void setArgumentValue(HashMap<String, String> parameters, String key, String value, boolean forceValue)
{if (parameters == null)
{throw new NullPointerException("Parameters can not be null in setArgumentValue");
}if (key == null)
{throw new NullPointerException("Key can not be null in setArgumentValue");
}if (value == null)
{if (forceValue)
{throw new NullPointerException("Value can not be null in setArgumentValue for key (" + key + ")");
}return;
}if (parameters.containsKey(key))
{parameters.remove(key);
}parameters.put(key, value);
}Pizza's here, so I will post a follow-up later where I use C++ and QT rather than Java.