diff --git a/GreenshotPhotobucketPlugin/PhotobucketDestination.cs b/GreenshotPhotobucketPlugin/PhotobucketDestination.cs index db3c031bb..b4641791f 100644 --- a/GreenshotPhotobucketPlugin/PhotobucketDestination.cs +++ b/GreenshotPhotobucketPlugin/PhotobucketDestination.cs @@ -19,7 +19,9 @@ * along with this program. If not, see . */ using System.ComponentModel; +using System.Collections.Generic; using System.Drawing; + using Greenshot.IniFile; using Greenshot.Plugin; using GreenshotPlugin.Core; @@ -32,9 +34,16 @@ namespace GreenshotPhotobucketPlugin { private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(PhotobucketDestination)); private static PhotobucketConfiguration config = IniConfig.GetIniSection(); private PhotobucketPlugin plugin = null; + private string albumPath = null; - public PhotobucketDestination(PhotobucketPlugin plugin) { + /// + /// Create a Photobucket destination, which also has the path to the album in it + /// + /// + /// path to the album, null for default + public PhotobucketDestination(PhotobucketPlugin plugin, string albumPath) { this.plugin = plugin; + this.albumPath = albumPath; } public override string Designation { @@ -45,6 +54,9 @@ namespace GreenshotPhotobucketPlugin { public override string Description { get { + if (albumPath != null) { + return albumPath; + } return Language.GetString("photobucket", LangKey.upload_menu_item); } } @@ -55,11 +67,35 @@ namespace GreenshotPhotobucketPlugin { return (Image)resources.GetObject("Photobucket"); } } + + public override bool isDynamic { + get { + return true; + } + } + public override IEnumerable DynamicDestinations() { + List albums = PhotobucketUtils.RetrievePhotobucketAlbums(); + + if (albums == null || albums.Count == 0) { + yield break; + } + foreach(string album in albums) { + yield return new PhotobucketDestination(plugin, album); + } + } + + /// + /// Export the capture to Photobucket + /// + /// + /// + /// + /// public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { ExportInformation exportInformation = new ExportInformation(this.Designation, this.Description); string uploadURL = null; - bool uploaded = plugin.Upload(captureDetails, surface, out uploadURL); + bool uploaded = plugin.Upload(captureDetails, surface, albumPath, out uploadURL); if (uploaded) { exportInformation.ExportMade = true; exportInformation.Uri = uploadURL; diff --git a/GreenshotPhotobucketPlugin/PhotobucketInfo.cs b/GreenshotPhotobucketPlugin/PhotobucketInfo.cs index 9f639aab5..89c6010fa 100644 --- a/GreenshotPhotobucketPlugin/PhotobucketInfo.cs +++ b/GreenshotPhotobucketPlugin/PhotobucketInfo.cs @@ -26,7 +26,7 @@ namespace GreenshotPhotobucketPlugin /// /// Description of PhotobucketInfo. /// - public class PhotobucketInfo : IDisposable { + public class PhotobucketInfo { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(PhotobucketInfo)); private string original; @@ -51,25 +51,11 @@ namespace GreenshotPhotobucketPlugin } /// - /// The public accessible Dispose - /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + /// Parse the upload response /// - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// This Dispose is called from the Dispose and the Destructor. - /// When disposing==true all non-managed resources should be freed too! - /// - /// - protected virtual void Dispose(bool disposing) { - if (disposing) { - } - } - - public static PhotobucketInfo ParseResponse(string response) { + /// XML + /// PhotobucketInfo object + public static PhotobucketInfo FromUploadResponse(string response) { LOG.Debug(response); PhotobucketInfo PhotobucketInfo = new PhotobucketInfo(); try { diff --git a/GreenshotPhotobucketPlugin/PhotobucketPlugin.cs b/GreenshotPhotobucketPlugin/PhotobucketPlugin.cs index cd1f8418f..f1d0b1568 100644 --- a/GreenshotPhotobucketPlugin/PhotobucketPlugin.cs +++ b/GreenshotPhotobucketPlugin/PhotobucketPlugin.cs @@ -45,7 +45,7 @@ namespace GreenshotPhotobucketPlugin { } public IEnumerable Destinations() { - yield return new PhotobucketDestination(this); + yield return new PhotobucketDestination(this, null); } public IEnumerable Processors() { @@ -114,7 +114,7 @@ namespace GreenshotPhotobucketPlugin { /// ISurface /// out string for the url /// true if the upload succeeded - public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadURL) { + public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, string albumPath, out string uploadURL) { SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(config.UploadFormat, config.UploadJpegQuality, config.UploadReduceColors); try { string filename = Path.GetFileName(FilenameHelper.GetFilename(config.UploadFormat, captureDetails)); @@ -123,7 +123,7 @@ namespace GreenshotPhotobucketPlugin { // Run upload in the background new PleaseWaitForm().ShowAndWait(Attributes.Name, Language.GetString("photobucket", LangKey.communication_wait), delegate() { - photobucketInfo = PhotobucketUtils.UploadToPhotobucket(surfaceToUpload, outputSettings, captureDetails.Title, filename); + photobucketInfo = PhotobucketUtils.UploadToPhotobucket(surfaceToUpload, outputSettings, albumPath, captureDetails.Title, filename); } ); // This causes an exeption if the upload failed :) diff --git a/GreenshotPhotobucketPlugin/PhotobucketUtils.cs b/GreenshotPhotobucketPlugin/PhotobucketUtils.cs index 5dcfbf980..1d84bad89 100644 --- a/GreenshotPhotobucketPlugin/PhotobucketUtils.cs +++ b/GreenshotPhotobucketPlugin/PhotobucketUtils.cs @@ -21,6 +21,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using System.Xml; using Greenshot.IniFile; using Greenshot.Plugin; using GreenshotPlugin.Core; @@ -29,21 +30,69 @@ namespace GreenshotPhotobucketPlugin { /// /// Description of PhotobucketUtils. /// - public class PhotobucketUtils { + public static class PhotobucketUtils { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(PhotobucketUtils)); - private static PhotobucketConfiguration config = IniConfig.GetIniSection(); - - private PhotobucketUtils() { - } + private static readonly PhotobucketConfiguration config = IniConfig.GetIniSection(); /// /// Do the actual upload to Photobucket /// For more details on the available parameters, see: http://api.Photobucket.com/resources_anon /// /// PhotobucketResponse - public static PhotobucketInfo UploadToPhotobucket(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) { + public static PhotobucketInfo UploadToPhotobucket(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string albumPath, string title, string filename) { string responseString; + + if (string.IsNullOrEmpty(albumPath)) { + albumPath = "!"; + } + OAuthSession oAuth = createSession(); + + IDictionary signedParameters = new Dictionary(); + // add album + if (albumPath == null) { + signedParameters.Add("id", config.Username); + } else { + signedParameters.Add("id", albumPath); + } + // add type + signedParameters.Add("type", "image"); + // add title + if (title != null) { + signedParameters.Add("title", title); + } + // add filename + if (filename != null) { + signedParameters.Add("filename", filename); + } + IDictionary unsignedParameters = new Dictionary(); + // Add image + unsignedParameters.Add("uploadfile", new SurfaceContainer(surfaceToUpload, outputSettings, filename)); + try { + string apiUrl = "http://api.photobucket.com/album/!/upload"; + responseString = oAuth.MakeOAuthRequest(HTTPMethod.POST, apiUrl, apiUrl.Replace("api.photobucket.com", config.SubDomain), signedParameters, unsignedParameters, null); + } catch (Exception ex) { + LOG.Error("Error uploading to Photobucket.", ex); + throw ex; + } finally { + if (!string.IsNullOrEmpty(oAuth.Token)) { + config.Token = oAuth.Token; + } + if (!string.IsNullOrEmpty(oAuth.TokenSecret)) { + config.TokenSecret = oAuth.TokenSecret; + } + } + LOG.Info(responseString); + PhotobucketInfo PhotobucketInfo = PhotobucketInfo.FromUploadResponse(responseString); + LOG.Debug("Upload to Photobucket was finished"); + return PhotobucketInfo; + } + + /// + /// Helper method to create an OAuth session object for contacting the Photobucket API + /// + /// OAuthSession + private static OAuthSession createSession() { OAuthSession oAuth = new OAuthSession(PhotobucketCredentials.ConsumerKey, PhotobucketCredentials.ConsumerSecret); oAuth.CheckVerifier = false; // This url is configured in the Photobucket API settings in the Photobucket site!! @@ -77,26 +126,22 @@ namespace GreenshotPhotobucketPlugin { } oAuth.Token = config.Token; oAuth.TokenSecret = config.TokenSecret; + return oAuth; + } + + /// + /// Get list of photobucket albums + /// + /// List + public static List RetrievePhotobucketAlbums() { + string responseString; + + OAuthSession oAuth = createSession(); IDictionary signedParameters = new Dictionary(); - // add album - signedParameters.Add("id", config.Username); - // add type - signedParameters.Add("type", "image"); - // add title - if (title != null) { - signedParameters.Add("title", title); - } - // add filename - if (filename != null) { - signedParameters.Add("filename", filename); - } - IDictionary unsignedParameters = new Dictionary(); - // Add image - unsignedParameters.Add("uploadfile", new SurfaceContainer(surfaceToUpload, outputSettings, filename)); try { - string apiUrl = "http://api.photobucket.com/album/!/upload"; - responseString = oAuth.MakeOAuthRequest(HTTPMethod.POST, apiUrl, apiUrl.Replace("api.photobucket.com", config.SubDomain), signedParameters, unsignedParameters, null); + string apiUrl = string.Format("http://api.photobucket.com/album/{0}", config.Username); + responseString = oAuth.MakeOAuthRequest(HTTPMethod.GET, apiUrl, apiUrl.Replace("api.photobucket.com", config.SubDomain), signedParameters, null, null); } catch (Exception ex) { LOG.Error("Error uploading to Photobucket.", ex); throw ex; @@ -108,10 +153,43 @@ namespace GreenshotPhotobucketPlugin { config.TokenSecret = oAuth.TokenSecret; } } - LOG.Info(responseString); - PhotobucketInfo PhotobucketInfo = PhotobucketInfo.ParseResponse(responseString); + try { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(responseString); + List albums = new List(); + recurseAlbums(albums, null, doc.GetElementsByTagName("content").Item(0).ChildNodes); + LOG.DebugFormat("Albums: {0}", string.Join(",", albums.ToArray())); + return albums; + } catch(Exception e) { + LOG.Error("Error while Reading albums: ", e); + } + LOG.Debug("Upload to Photobucket was finished"); - return PhotobucketInfo; + return null; + } + + /// + /// Parse the album nodes recursively + /// + /// + /// + /// + private static void recurseAlbums(Listalbums, string path, XmlNodeList nodes) { + foreach(XmlNode node in nodes) { + if (node.Name != "album") { + continue; + } + string currentAlbum = node.Attributes["name"].Value; + string currentPath = currentAlbum; + if (path != null && path.Length > 0) { + currentPath = string.Format("{0}/{1}", path, currentAlbum); + } + + albums.Add(currentPath); + if (node.Attributes["subalbum_count"] != null && node.Attributes["subalbum_count"].Value != "0") { + recurseAlbums(albums, currentPath, node.ChildNodes); + } + } } } }