#region License Information (GPL v3) /* ShareX - A program that allows you to take screenshots and share any file type Copyright (c) 2007-2017 ShareX Team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Optionally you can also view the license at . */ #endregion License Information (GPL v3) using ShareX.HelpersLib; using ShareX.UploadersLib.Properties; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; using System.Linq; using System.Windows.Forms; using System.Xml.Linq; namespace ShareX.UploadersLib.ImageUploaders { public class FlickrImageUploaderService : ImageUploaderService { public override ImageDestination EnumValue { get; } = ImageDestination.Flickr; public override Icon ServiceIcon => Resources.Flickr; public override bool CheckConfig(UploadersConfig config) { return !string.IsNullOrEmpty(config.FlickrAuthInfo.Token); } public override GenericUploader CreateUploader(UploadersConfig config, TaskReferenceHelper taskInfo) { return new FlickrUploader(APIKeys.FlickrKey, APIKeys.FlickrSecret, config.FlickrAuthInfo, config.FlickrSettings); } public override TabPage GetUploadersConfigTabPage(UploadersConfigForm form) => form.tpFlickr; } // TODO: Implement oauth public class FlickrUploader : ImageUploader { private string API_Key, API_Secret; private const string API_URL = "https://api.flickr.com/services/rest/"; private const string API_Auth_URL = "https://www.flickr.com/services/auth/"; public FlickrAuthInfo Auth = new FlickrAuthInfo(); public FlickrSettings Settings = new FlickrSettings(); public string Frob; public FlickrUploader(string key, string secret) { API_Key = key; API_Secret = secret; } public FlickrUploader(string key, string secret, FlickrAuthInfo auth, FlickrSettings settings) : this(key, secret) { Auth = auth; Settings = settings; } #region Auth /// /// Returns the credentials attached to an authentication token. /// http://www.flickr.com/services/api/flickr.auth.checkToken.html /// public FlickrAuthInfo CheckToken(string token) { Dictionary args = new Dictionary(); args.Add("method", "flickr.auth.checkToken"); args.Add("api_key", API_Key); args.Add("auth_token", token); args.Add("api_sig", GetAPISig(args)); string response = SendRequestMultiPart(API_URL, args); Auth = new FlickrAuthInfo(ParseResponse(response, "auth")); return Auth; } /// /// Returns a frob to be used during authentication. /// http://www.flickr.com/services/api/flickr.auth.getFrob.html /// public string GetFrob() { Dictionary args = new Dictionary(); args.Add("method", "flickr.auth.getFrob"); args.Add("api_key", API_Key); args.Add("api_sig", GetAPISig(args)); string response = SendRequestMultiPart(API_URL, args); XElement eFrob = ParseResponse(response, "frob"); if (eFrob == null) { string errorMessage = ToErrorString(); if (string.IsNullOrEmpty(errorMessage)) { throw new Exception("getFrob failed."); } throw new Exception(errorMessage); } Frob = eFrob.Value; return Frob; } /// /// Get the full authentication token for a mini-token. /// http://www.flickr.com/services/api/flickr.auth.getFullToken.html /// public FlickrAuthInfo GetFullToken(string frob) { Dictionary args = new Dictionary(); args.Add("method", "flickr.auth.getFullToken"); args.Add("api_key", API_Key); args.Add("mini_token", frob); args.Add("api_sig", GetAPISig(args)); string response = SendRequestMultiPart(API_URL, args); Auth = new FlickrAuthInfo(ParseResponse(response, "auth")); return Auth; } /// /// Returns the auth token for the given frob, if one has been attached. /// http://www.flickr.com/services/api/flickr.auth.getToken.html /// /// public FlickrAuthInfo GetToken(string frob) { Dictionary args = new Dictionary(); args.Add("method", "flickr.auth.getToken"); args.Add("api_key", API_Key); args.Add("frob", frob); args.Add("api_sig", GetAPISig(args)); string response = SendRequestMultiPart(API_URL, args); Auth = new FlickrAuthInfo(ParseResponse(response, "auth")); return Auth; } public FlickrAuthInfo GetToken() { return GetToken(Frob); } public string GetAuthLink() { return GetAuthLink(FlickrPermission.Write); } public string GetAuthLink(FlickrPermission perm) { if (!string.IsNullOrEmpty(Frob)) { Dictionary args = new Dictionary(); args.Add("api_key", API_Key); args.Add("perms", perm.ToString().ToLowerInvariant()); args.Add("frob", Frob); args.Add("api_sig", GetAPISig(args)); return string.Format("{0}?{1}", API_Auth_URL, string.Join("&", args.Select(x => x.Key + "=" + x.Value).ToArray())); } return null; } public string GetPhotosLink(string userID) { return URLHelpers.CombineURL("https://www.flickr.com/photos", userID); } public string GetPhotosLink() { return GetPhotosLink(Auth.UserID); } #endregion Auth #region Helpers private string GetAPISig(Dictionary args) { return TranslatorHelper.TextToHash(args.OrderBy(x => x.Key).Aggregate(API_Secret, (x, x2) => x + x2.Key + x2.Value), HashType.MD5); } private XElement ParseResponse(string response, string field) { if (!string.IsNullOrEmpty(response)) { XDocument xdoc = XDocument.Parse(response); XElement xele = xdoc.Element("rsp"); if (xele != null) { switch (xele.GetAttributeFirstValue("status", "stat")) { case "ok": return xele.Element(field); case "fail": XElement err = xele.Element("err"); string code = err.GetAttributeValue("code"); string msg = err.GetAttributeValue("msg"); // throw new Exception(string.Format("Code: {0}, Message: {1}", code, msg)); Errors.Add(msg); break; } } } return null; } #endregion Helpers public override UploadResult Upload(Stream stream, string fileName) { Dictionary args = new Dictionary(); args.Add("api_key", API_Key); args.Add("auth_token", Auth.Token); if (!string.IsNullOrEmpty(Settings.Title)) args.Add("title", Settings.Title); if (!string.IsNullOrEmpty(Settings.Description)) args.Add("description", Settings.Description); if (!string.IsNullOrEmpty(Settings.Tags)) args.Add("tags", Settings.Tags); if (!string.IsNullOrEmpty(Settings.IsPublic)) args.Add("is_public", Settings.IsPublic); if (!string.IsNullOrEmpty(Settings.IsFriend)) args.Add("is_friend", Settings.IsFriend); if (!string.IsNullOrEmpty(Settings.IsFamily)) args.Add("is_family", Settings.IsFamily); if (!string.IsNullOrEmpty(Settings.SafetyLevel)) args.Add("safety_level", Settings.SafetyLevel); if (!string.IsNullOrEmpty(Settings.ContentType)) args.Add("content_type", Settings.ContentType); if (!string.IsNullOrEmpty(Settings.Hidden)) args.Add("hidden", Settings.Hidden); args.Add("api_sig", GetAPISig(args)); UploadResult result = SendRequestFile("https://up.flickr.com/services/upload/", stream, fileName, "photo", args); if (result.IsSuccess) { XElement xele = ParseResponse(result.Response, "photoid"); if (null != xele) { string photoid = xele.Value; string url = URLHelpers.CombineURL(GetPhotosLink(), photoid); result.URL = URLHelpers.CombineURL(url, "sizes/o"); } } return result; } } public class FlickrAuthInfo { [Description("Token string"), ReadOnly(true), PasswordPropertyText(true)] public string Token { get; set; } [Description("Permission"), ReadOnly(true)] public string Permission { get; set; } [Description("User ID that can be used in a URL")] public string UserID { get; set; } [Description("Your Flickr username"), ReadOnly(true)] public string Username { get; set; } [Description("Full name"), ReadOnly(true)] public string Fullname { get; set; } public FlickrAuthInfo() { } public FlickrAuthInfo(XElement element) { Token = element.GetElementValue("token"); Permission = element.GetElementValue("perms"); XElement user = element.Element("user"); UserID = user.GetAttributeValue("nsid"); Username = user.GetAttributeValue("username"); Fullname = user.GetAttributeValue("fullname"); } } public class FlickrSettings { /// /// The title of the photo. /// [Description("The title of the photo.")] public string Title { get; set; } /// /// A description of the photo. May contain some limited HTML. /// [Description("A description of the photo. May contain some limited HTML.")] public string Description { get; set; } /// /// A space-seperated list of tags to apply to the photo. /// [Description("A space-seperated list of tags to apply to the photo.")] public string Tags { get; set; } /// /// Set to 0 for no, 1 for yes. Specifies who can view the photo. /// [Description("Set to 0 for no, 1 for yes. Specifies who can view the photo.")] public string IsPublic { get; set; } /// /// Set to 0 for no, 1 for yes. Specifies who can view the photo. /// [Description("Set to 0 for no, 1 for yes. Specifies who can view the photo.")] public string IsFriend { get; set; } /// /// Set to 0 for no, 1 for yes. Specifies who can view the photo. /// [Description("Set to 0 for no, 1 for yes. Specifies who can view the photo.")] public string IsFamily { get; set; } /// /// Set to 1 for Safe, 2 for Moderate, or 3 for Restricted. /// [Description("Set to 1 for Safe, 2 for Moderate, or 3 for Restricted.")] public string SafetyLevel { get; set; } /// /// Set to 1 for Photo, 2 for Screenshot, or 3 for Other. /// [Description("Set to 1 for Photo, 2 for Screenshot, or 3 for Other.")] public string ContentType { get; set; } /// /// Set to 1 to keep the photo in global search results, 2 to hide from public searches. /// [Description("Set to 1 to keep the photo in global search results, 2 to hide from public searches.")] public string Hidden { get; set; } } public enum FlickrPermission { None, /// /// Permission to read private information /// Read, /// /// Permission to add, edit and delete photo metadata (includes 'read') /// Write, /// /// Permission to delete photos (includes 'write' and 'read') /// Delete } }