OSDN Git Service

画像共有サービスに使用するインタフェースを設計し直し
authorKimura Youichi <kim.upsilon@bucyou.net>
Sat, 14 Jun 2014 00:11:41 +0000 (09:11 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Sat, 14 Jun 2014 07:51:57 +0000 (16:51 +0900)
 * IMultimediaShareService から IMediaUploadService に変更
 * 複数枚のメディアをアップロード可能なサービスを考慮
 * URLのために確保する文字数を取得出来るようにした

12 files changed:
OpenTween/Api/TwitterConfiguration.cs
OpenTween/Connection/IMediaUploadService.cs [new file with mode: 0644]
OpenTween/Connection/IMultimediaShareService.cs [deleted file]
OpenTween/Connection/Imgur.cs
OpenTween/Connection/TwipplePhoto.cs
OpenTween/Connection/TwitPic.cs
OpenTween/Connection/TwitterPhoto.cs
OpenTween/Connection/imgly.cs
OpenTween/Connection/yfrog.cs
OpenTween/MediaSelector.cs
OpenTween/OpenTween.csproj
OpenTween/Tween.cs

index f7d9e08..cdbb040 100644 (file)
@@ -41,7 +41,7 @@ namespace OpenTween.Api
         public int CharactersReservedPerMedia { get; set; }
 
         [DataMember(Name = "photo_size_limit")]
-        public int PhotoSizeLimit { get; set; }
+        public long PhotoSizeLimit { get; set; }
 
         [DataMember(Name = "photo_sizes")]
         public TwitterMediaSizes PhotoSizes { get; set; }
diff --git a/OpenTween/Connection/IMediaUploadService.cs b/OpenTween/Connection/IMediaUploadService.cs
new file mode 100644 (file)
index 0000000..b515d89
--- /dev/null
@@ -0,0 +1,84 @@
+// OpenTween - Client of Twitter
+// Copyright (c) 2014 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
+// All rights reserved.
+//
+// This file is part of OpenTween.
+//
+// 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 3 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, see <http://www.gnu.org/licenses/>, or write to
+// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using OpenTween.Api;
+
+namespace OpenTween.Connection
+{
+    /// <summary>
+    /// Twitterでの画像の共有に使用できるサービスを表すインタフェース
+    /// </summary>
+    public interface IMediaUploadService
+    {
+        /// <summary>
+        /// アップロード可能なメディアの最大枚数
+        /// </summary>
+        int MaxMediaCount { get; }
+
+        /// <summary>
+        /// アップロード可能なファイルの種類を表す文字列 (OpenFileDialog.Filter に使用)
+        /// </summary>
+        string SupportedFormatsStrForDialog { get; }
+
+        /// <summary>
+        /// ファイルの拡張子からアップロード可能なフォーマットであるかを判定します
+        /// </summary>
+        /// <param name="fileExtension">アップロードするファイルの拡張子 (ピリオドを含む)</param>
+        bool CheckFileExtension(string fileExtension);
+
+        /// <summary>
+        /// ファイルサイズがアップロード可能な範囲内であるかを判定します
+        /// </summary>
+        /// <param name="fileExtension">アップロードするファイルの拡張子 (ピリオドを含む)</param>
+        /// <param name="fileSize">アップロードするファイルのサイズ (バイト単位)</param>
+        bool CheckFileSize(string fileExtension, long fileSize);
+
+        /// <summary>
+        /// アップロード可能なファイルサイズの上限を返します
+        /// </summary>
+        /// <param name="fileExtension">アップロードするファイルの拡張子 (ピリオドを含む)</param>
+        /// <returns>ファイルサイズの上限 (バイト単位, nullの場合は上限なし)</returns>
+        long? GetMaxFileSize(string fileExtension);
+
+        /// <summary>
+        /// メディアのアップロードとツイートの投稿を行います
+        /// </summary>
+        /// <exception cref="WebApiException"/>
+        Task PostStatusAsync(string text, long? inReplyToStatusId, string[] filePaths);
+
+        /// <summary>
+        /// 画像URLのために確保する必要のある文字数を返します
+        /// </summary>
+        /// <param name="mediaCount">アップロードするメディアの個数</param>
+        int GetReservedTextLength(int mediaCount);
+
+        /// <summary>
+        /// IMediaUploadService で使用する /help/configuration.json の値を更新します
+        /// </summary>
+        void UpdateTwitterConfiguration(TwitterConfiguration config);
+    }
+}
diff --git a/OpenTween/Connection/IMultimediaShareService.cs b/OpenTween/Connection/IMultimediaShareService.cs
deleted file mode 100644 (file)
index fe8b039..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-// OpenTween - Client of Twitter
-// Copyright (c) 2011      kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
-//           (c) 2011      Egtra (@egtra) <http://dev.activebasic.com/egtra/>
-// All rights reserved.
-// 
-// This file is part of OpenTween.
-// 
-// 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 3 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, see <http://www.gnu.org/licenses/>, or write to
-// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
-// Boston, MA 02110-1301, USA.
-
-namespace OpenTween
-{
-    public interface IMultimediaShareService
-    {
-        string Upload(ref string filePath,
-                        ref string message,
-                        long? reply_to);
-        bool CheckValidExtension(string ext) ;
-        string GetFileOpenDialogFilter();
-        MyCommon.UploadFileType GetFileType(string ext);
-        bool IsSupportedFileType(MyCommon.UploadFileType type);
-        bool CheckValidFilesize(string ext, long fileSize);
-        bool Configuration(string key, object value);
-    }
-}
index 9b01834..a01c82a 100644 (file)
 
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
 using System.Text;
-using System.Net;
-using System.IO;
+using System.Threading.Tasks;
 using System.Xml.Linq;
-using System.Xml;
+using OpenTween.Api;
 
 namespace OpenTween.Connection
 {
-    public class Imgur : HttpConnectionOAuth, IMultimediaShareService
+    public class Imgur : IMediaUploadService
     {
         private readonly static long MaxFileSize = 10L * 1024 * 1024;
         private readonly static Uri UploadEndpoint = new Uri("https://api.imgur.com/3/image.xml");
@@ -48,132 +50,123 @@ namespace OpenTween.Connection
             ".xcf",
         };
 
-        private readonly Twitter _twitter;
+        private readonly Twitter twitter;
+        private TwitterConfiguration twitterConfig;
 
-        public Imgur(Twitter tw)
+        public Imgur(Twitter tw, TwitterConfiguration twitterConfig)
         {
-            this._twitter = tw;
-
-            Initialize(ApplicationSettings.TwitterConsumerKey, ApplicationSettings.TwitterConsumerSecret,
-                       tw.AccessToken, tw.AccessTokenSecret,
-                       "", "");
+            this.twitter = tw;
+            this.twitterConfig = twitterConfig;
         }
 
-        protected override void AppendOAuthInfo(HttpWebRequest webRequest, Dictionary<string, string> query, string token, string tokenSecret)
+        public int MaxMediaCount
         {
-            webRequest.Headers[HttpRequestHeader.Authorization] =
-                string.Format("Client-ID {0}", ApplicationSettings.ImgurClientID);
+            get { return 1; }
         }
 
-        public string Upload(ref string filePath, ref string message, long? reply_to)
+        public string SupportedFormatsStrForDialog
         {
-            if (!File.Exists(filePath))
-                return "Err:File isn't exists.";
-
-            var mediaFile = new FileInfo(filePath);
-            var content = "";
-            HttpStatusCode result;
-            try
-            {
-                result = this.UploadFile(mediaFile, message, ref content);
-            }
-            catch (Exception ex)
+            get
             {
-                return "Err:" + ex.Message;
-            }
+                var formats = new StringBuilder();
 
-            if (result != HttpStatusCode.OK)
-            {
-                return "Err:" + result;
-            }
+                foreach (var extension in SupportedExtensions)
+                    formats.AppendFormat("*{0};", extension);
 
-            var imageUrl = "";
-            try
-            {
-                var xdoc = XDocument.Parse(content);
-                var image = xdoc.Element("data");
-                if (image.Attribute("success").Value != "1")
-                {
-                    return "APIErr:" + image.Attribute("status").Value;
-                }
-                imageUrl = image.Element("link").Value;
-            }
-            catch (XmlException ex)
-            {
-                return "XmlErr:" + ex.Message;
+                return "Image Files(" + formats + ")|" + formats;
             }
+        }
 
-            filePath = "";
-            if (message == null)
-                message = "";
+        public bool CheckFileExtension(string fileExtension)
+        {
+            return SupportedExtensions.Contains(fileExtension, StringComparer.OrdinalIgnoreCase);
+        }
 
-            // Post to twitter
-            if (message.Length + AppendSettingDialog.Instance.TwitterConfiguration.CharactersReservedPerMedia + 1 > 140)
-            {
-                message = message.Substring(0, 140 - AppendSettingDialog.Instance.TwitterConfiguration.CharactersReservedPerMedia - 1) + " " + imageUrl;
-            }
-            else
-            {
-                message += " " + imageUrl;
-            }
-            return _twitter.PostStatus(message, reply_to);
+        public bool CheckFileSize(string fileExtension, long fileSize)
+        {
+            var maxFileSize = this.GetMaxFileSize(fileExtension);
+            return maxFileSize == null || fileSize <= maxFileSize.Value;
+        }
+
+        public long? GetMaxFileSize(string fileExtension)
+        {
+            return MaxFileSize;
         }
 
-        private HttpStatusCode UploadFile(FileInfo mediaFile, string message, ref string content)
+        public async Task PostStatusAsync(string text, long? inReplyToStatusId, string[] filePaths)
         {
-            if (!CheckValidExtension(mediaFile.Extension))
-                throw new ArgumentException("Service don't support this filetype", "mediaFile");
-            if (!CheckValidFilesize(mediaFile.Extension, mediaFile.Length))
-                throw new ArgumentException("File is too large", "mediaFile");
+            if (filePaths.Length != 1)
+                throw new ArgumentOutOfRangeException("filePaths");
+
+            var file = new FileInfo(filePaths[0]);
+
+            if (!file.Exists)
+                throw new ArgumentException("File isn't exists.", "filePaths[0]");
 
-            var param = new Dictionary<string, string>
+            XDocument xml;
+            try
             {
-                {"title", message},
-            };
-            var binary = new List<KeyValuePair<string, FileInfo>>
+                xml = await this.UploadFileAsync(file, text)
+                    .ConfigureAwait(false);
+            }
+            catch (HttpRequestException ex)
             {
-                new KeyValuePair<string, FileInfo>("image", mediaFile)
-            };
-            this.InstanceTimeout = 60000;
+                throw new WebApiException("Err:" + ex.Message, ex);
+            }
 
-            return this.GetContent(PostMethod, UploadEndpoint, param, binary, ref content, null, null);
-        }
+            var imageElm = xml.Element("data");
 
-        public bool CheckValidExtension(string ext)
-        {
-            return SupportedExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
-        }
+            if (imageElm.Attribute("success").Value != "1")
+                throw new WebApiException("Err:" + imageElm.Attribute("status").Value);
 
-        public string GetFileOpenDialogFilter()
-        {
-            var formats = new StringBuilder();
+            var imageUrl = imageElm.Element("link").Value;
 
-            foreach (var extension in SupportedExtensions)
-                formats.AppendFormat("*{0};", extension);
+            var textWithImageUrl = text + " " + imageUrl.Trim();
 
-            return "Image Files(" + formats + ")|" + formats;
+            await Task.Run(() => this.twitter.PostStatus(textWithImageUrl, inReplyToStatusId))
+                .ConfigureAwait(false);
         }
 
-        public MyCommon.UploadFileType GetFileType(string ext)
+        public int GetReservedTextLength(int mediaCount)
         {
-            return this.CheckValidExtension(ext)
-                ? MyCommon.UploadFileType.Picture
-                : MyCommon.UploadFileType.Invalid;
+            return this.twitterConfig.ShortUrlLength;
         }
 
-        public bool IsSupportedFileType(MyCommon.UploadFileType type)
+        public void UpdateTwitterConfiguration(TwitterConfiguration config)
         {
-            return type == MyCommon.UploadFileType.Picture;
+            this.twitterConfig = config;
         }
 
-        public bool CheckValidFilesize(string ext, long fileSize)
+        public async Task<XDocument> UploadFileAsync(FileInfo file, string title)
         {
-            return CheckValidExtension(ext) && fileSize <= MaxFileSize;
-        }
+            using (var content = new MultipartFormDataContent())
+            using (var fileStream = file.OpenRead())
+            using (var fileContent = new StreamContent(fileStream))
+            using (var titleContent = new StringContent(title))
+            {
+                content.Add(fileContent, "image", file.Name);
+                content.Add(titleContent, "title");
 
-        public bool Configuration(string key, object value)
-        {
-            throw new NotImplementedException();
+                using (var http = MyCommon.CreateHttpClient())
+                using (var request = new HttpRequestMessage(HttpMethod.Post, UploadEndpoint))
+                {
+                    http.Timeout = TimeSpan.FromMinutes(1);
+
+                    request.Headers.Authorization =
+                        new AuthenticationHeaderValue("Client-ID", ApplicationSettings.ImgurClientID);
+                    request.Content = content;
+
+                    using (var response = await http.SendAsync(request).ConfigureAwait(false))
+                    {
+                        response.EnsureSuccessStatusCode();
+
+                        using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
+                        {
+                            return XDocument.Load(stream);
+                        }
+                    }
+                }
+            }
         }
     }
 }
index c330b3b..e399867 100644 (file)
@@ -1,5 +1,6 @@
 // OpenTween - Client of Twitter
 // Copyright (c) 2013 ANIKITI (@anikiti07) <https://twitter.com/anikiti07>
+//           (c) 2014 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
 // All rights reserved.
 //
 // This file is part of OpenTween.
@@ -24,157 +25,158 @@ using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Net;
+using System.Threading.Tasks;
+using System.Windows.Forms;
 using System.Xml;
+using System.Xml.Linq;
+using System.Xml.XPath;
+using OpenTween.Api;
 
 namespace OpenTween.Connection
 {
-    public sealed class TwipplePhoto : HttpConnectionOAuthEcho,
-                                       IMultimediaShareService
+    public sealed class TwipplePhoto : IMediaUploadService
     {
-        private const long MaxFileSize = 4 * 1024 * 1024;
-
-        private readonly Twitter _twitter;
-        private readonly Uri _twipplePhotoUploadUri = new Uri("http://p.twipple.jp/api/upload2");
-        private readonly IEnumerable<string> _supportedPictureExtensions = new[]
+        private static readonly long MaxFileSize = 4L * 1024 * 1024;
+        private static readonly IEnumerable<string> SupportedPictureExtensions = new[]
         {
             ".gif",
             ".jpg",
-            ".png"
+            ".png",
         };
 
+        private readonly Twitter twitter;
+        private readonly TwippleApi twippleApi;
+
+        private TwitterConfiguration twitterConfig;
+
         #region Constructors
 
-        public TwipplePhoto(Twitter twitter)
-            : base(new Uri("http://api.twitter.com/"), new Uri("https://api.twitter.com/1.1/account/verify_credentials.json"))
+        public TwipplePhoto(Twitter twitter, TwitterConfiguration twitterConfig)
         {
             if (twitter == null)
                 throw new ArgumentNullException("twitter");
+            if (twitterConfig == null)
+                throw new ArgumentNullException("config");
+
+            this.twitter = twitter;
+            this.twitterConfig = twitterConfig;
 
-            _twitter = twitter;
-            Initialize(ApplicationSettings.TwitterConsumerKey, ApplicationSettings.TwitterConsumerSecret,
-                       _twitter.AccessToken, _twitter.AccessTokenSecret,
-                       "", "");
+            this.twippleApi = new TwippleApi(twitter.AccessToken, twitter.AccessTokenSecret);
         }
 
         #endregion
 
-        #region IMultimediaShareService Members
-
-        #region Upload Methods
-
-        public string Upload(ref string filePath, ref string message, long? reply_to)
+        public int MaxMediaCount
         {
-            if (!File.Exists(filePath))
-                return "Err:File isn't exists.";
-
-            var mediaFile = new FileInfo(filePath);
-            var content = "";
-            HttpStatusCode result;
-            try
-            {
-                result = UploadFile(mediaFile, ref content);
-            }
-            catch (Exception ex)
-            {
-                return "Err:" + ex.Message;
-            }
+            get { return 1; }
+        }
 
-            var imageUrl = "";
-            if (result == HttpStatusCode.OK)
+        public string SupportedFormatsStrForDialog
+        {
+            get
             {
-                try
+                var filterFormatExtensions = "";
+                foreach (var pictureExtension in SupportedPictureExtensions)
                 {
-                    var xdoc = new XmlDocument();
-                    xdoc.LoadXml(content);
-                    var urlNode = xdoc.SelectSingleNode("/rsp/mediaurl");
-                    if (urlNode != null)
-                    {
-                        imageUrl = urlNode.InnerText;
-                    }
+                    filterFormatExtensions += '*';
+                    filterFormatExtensions += pictureExtension;
+                    filterFormatExtensions += ';';
                 }
-                catch (XmlException ex)
-                {
-                    return "XmlErr:" + ex.Message;
-                }
-            }
-            else
-            {
-                return "Err:" + result;
+                return "Image Files(" + filterFormatExtensions + ")|" + filterFormatExtensions;
             }
-
-            filePath = "";
-            if (message == null)
-                message = "";
-
-            // Post to twitter
-            if (message.Length + AppendSettingDialog.Instance.TwitterConfiguration.CharactersReservedPerMedia + 1 > 140)
-            {
-                message = message.Substring(0, 140 - AppendSettingDialog.Instance.TwitterConfiguration.CharactersReservedPerMedia - 1) + " " + imageUrl;
-            }
-            else
-            {
-                message += " " + imageUrl;
-            }
-            return _twitter.PostStatus(message, reply_to);
         }
 
-        private HttpStatusCode UploadFile(FileInfo mediaFile, ref string content)
+        public bool CheckFileExtension(string fileExtension)
         {
-            if (!CheckValidExtension(mediaFile.Extension))
-                throw new ArgumentException("Service don't support this filetype", "mediaFile");
-            if (!CheckValidFilesize(mediaFile.Extension, mediaFile.Length))
-                throw new ArgumentException("File is too large", "mediaFile");
-
-            var binaly = new List<KeyValuePair<string, FileInfo>>
-            {
-                new KeyValuePair<string, FileInfo>("media", mediaFile)
-            };
-            InstanceTimeout = 60000;
-
-            return GetContent(PostMethod, _twipplePhotoUploadUri, null, binaly, ref content, null, null);
+            return SupportedPictureExtensions.Contains(fileExtension, StringComparer.OrdinalIgnoreCase);
         }
 
-        #endregion
-
-        public bool CheckValidExtension(string ext)
+        public bool CheckFileSize(string fileExtension, long fileSize)
         {
-            return _supportedPictureExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
+            var maxFileSize = this.GetMaxFileSize(fileExtension);
+            return maxFileSize == null || fileSize <= maxFileSize.Value;
         }
 
-        public string GetFileOpenDialogFilter()
+        public long? GetMaxFileSize(string fileExtension)
         {
-            string filterFormatExtensions = "";
-            foreach (var pictureExtension in _supportedPictureExtensions)
-            {
-                filterFormatExtensions += '*';
-                filterFormatExtensions += pictureExtension;
-                filterFormatExtensions += ';';
-            }
-            return "Image Files(" + filterFormatExtensions + ")|" + filterFormatExtensions;
+            return MaxFileSize;
         }
 
-        public MyCommon.UploadFileType GetFileType(string extension)
+        public async Task PostStatusAsync(string text, long? inReplyToStatusId, string[] filePaths)
         {
-            return CheckValidExtension(extension)
-                       ? MyCommon.UploadFileType.Picture
-                       : MyCommon.UploadFileType.Invalid;
+            if (filePaths.Length != 1)
+                throw new ArgumentOutOfRangeException("filePaths");
+
+            var file = new FileInfo(filePaths[0]);
+
+            if (!file.Exists)
+                throw new ArgumentException("Err:File isn't exists.", "filePaths[0]");
+
+            var xml = await this.twippleApi.UploadFileAsync(file)
+                .ConfigureAwait(false);
+
+            var imageUrlElm = xml.XPathSelectElement("/rsp/mediaurl");
+            if (imageUrlElm == null)
+                throw new WebApiException("Invalid API response", xml.ToString());
+
+            var textWithImageUrl = text + " " + imageUrlElm.Value.Trim();
+
+            await Task.Run(() => this.twitter.PostStatus(textWithImageUrl, inReplyToStatusId))
+                .ConfigureAwait(false);
         }
 
-        public bool IsSupportedFileType(MyCommon.UploadFileType type)
+        public int GetReservedTextLength(int mediaCount)
         {
-            return type == MyCommon.UploadFileType.Picture;
+            return this.twitterConfig.ShortUrlLength;
         }
 
-        public bool CheckValidFilesize(string extension, long fileSize)
+        public void UpdateTwitterConfiguration(TwitterConfiguration config)
         {
-            return CheckValidExtension(extension) && fileSize <= MaxFileSize;
+            this.twitterConfig = config;
         }
 
-        public bool Configuration(string key, object value)
+        public class TwippleApi : HttpConnectionOAuthEcho
         {
-            throw new NotImplementedException();
-        }
+            private static readonly Uri UploadEndpoint = new Uri("http://p.twipple.jp/api/upload2");
 
-        #endregion
+            public TwippleApi(string twitterAccessToken, string twitterAccessTokenSecret)
+                : base(new Uri("http://api.twitter.com/"), new Uri("https://api.twitter.com/1.1/account/verify_credentials.json"))
+            {
+                this.Initialize(ApplicationSettings.TwitterConsumerKey, ApplicationSettings.TwitterConsumerSecret,
+                    twitterAccessToken, twitterAccessTokenSecret, "", "");
+
+                this.InstanceTimeout = 60000;
+            }
+
+            /// <summary>
+            /// 画像のアップロードを行います
+            /// </summary>
+            /// <exception cref="WebApiException"/>
+            /// <exception cref="XmlException"/>
+            public async Task<XDocument> UploadFileAsync(FileInfo file)
+            {
+                // 参照: http://p.twipple.jp/wiki/API_Upload2/ja
+
+                var param = new Dictionary<string, string>
+                {
+                    {"upload_from", Application.ProductName},
+                };
+                var paramFiles = new List<KeyValuePair<string, FileInfo>>
+                {
+                    new KeyValuePair<string, FileInfo>("media", file),
+                };
+                var response = "";
+
+                var uploadTask = Task.Run(() => this.GetContent(HttpConnection.PostMethod,
+                    UploadEndpoint, param, paramFiles, ref response, null, null));
+
+                var ret = await uploadTask.ConfigureAwait(false);
+
+                if (ret != HttpStatusCode.OK)
+                    throw new WebApiException("Err:" + ret, response);
+
+                return XDocument.Parse(response);
+            }
+        }
     }
 }
\ No newline at end of file
index f8a0b6a..f5a0542 100644 (file)
 //           (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
 //           (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
 //           (c) 2011      spinor (@tplantd) <http://d.hatena.ne.jp/spinor/>
+//           (c) 2014      kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
 // All rights reserved.
-// 
+//
 // This file is part of OpenTween.
-// 
+//
 // 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 3 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. 
-// 
+// for more details.
+//
 // You should have received a copy of the GNU General Public License along
 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
 // Boston, MA 02110-1301, USA.
 
-using HttpConnectionOAuthEcho = OpenTween.HttpConnectionOAuthEcho;
-using IMultimediaShareService = OpenTween.IMultimediaShareService;
-using FileInfo = System.IO.FileInfo;
-using NotSupportedException = System.NotSupportedException;
-using HttpStatusCode = System.Net.HttpStatusCode;
-using Exception = System.Exception;
-using XmlDocument = System.Xml.XmlDocument;
-using XmlException = System.Xml.XmlException;
-using ArgumentException = System.ArgumentException;
-using System.Collections.Generic; // for Dictionary<TKey, TValue>, List<T>, KeyValuePair<TKey, TValue>
-using UploadFileType = OpenTween.MyCommon.UploadFileType;
-using Uri = System.Uri;
-using Array = System.Array;
-
-namespace OpenTween
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Threading.Tasks;
+using System.Xml;
+using System.Xml.Linq;
+using System.Xml.XPath;
+using OpenTween.Api;
+
+namespace OpenTween.Connection
 {
-       public class TwitPic : HttpConnectionOAuthEcho, IMultimediaShareService
-       {
-               private string[] pictureExt = new string[] { ".jpg", ".jpeg", ".gif", ".png" };
-
-               private string[] multimediaExt = new string[] { ".avi", ".wmv", ".flv", ".m4v", ".mov", ".mp4", ".rm", ".mpeg", ".mpg", ".3gp", ".3g2" };
-
-               private const long MaxFileSize = 10 * 1024 * 1024; // Image only
-               // Multimedia filesize limit unknown. But length limit is 1:30.
-
-               private Twitter tw;
-
-               public string Upload( ref string filePath, ref string message, long? reply_to )
-               {
-                       if ( string.IsNullOrEmpty( filePath ) )
-                               return "Err:File isn't specified.";
-                       if ( string.IsNullOrEmpty( message ) )
-                               message = "";
-
-                       FileInfo mediaFile;
-                       try
-                       {
-                               mediaFile = new FileInfo( filePath );
-                       }
-                       catch ( NotSupportedException ex )
-                       {
-                               return "Err:" + ex.Message;
-                       }
-                       if ( mediaFile == null || !mediaFile.Exists )
-                               return "Err:File isn't exists.";
-
-                       string content = "";
-                       HttpStatusCode ret;
-                       // TwitPicへの投稿
-                       try
-                       {
-                               ret = this.UploadFile( mediaFile, message, ref content );
-                       }
-                       catch ( Exception ex )
-                       {
-                               return "Err:" + ex.Message;
-                       }
-                       string url = "";
-                       if ( ret == HttpStatusCode.OK )
-                       {
-                               XmlDocument xd = new XmlDocument();
-                               try
-                               {
-                                       xd.LoadXml( content );
-                                       // URLの取得
-                                       url = xd.SelectSingleNode( "/image/url" ).InnerText;
-                               }
-                               catch ( XmlException ex )
-                               {
-                                       return "Err:" + ex.Message;
-                               }
-                               catch ( Exception ex )
-                               {
-                                       return "Err:" + ex.Message;
-                               }
-                       }
-                       else
-                               return "Err:" + ret.ToString();
-
-                       // アップロードまでは成功
-                       filePath = "";
-                       if ( string.IsNullOrEmpty( message ) )
-                               message = "";
-                       if ( string.IsNullOrEmpty( url ) )
-                               url = "";
-                       // Twitterへの投稿
-                       // 投稿メッセージの再構成
-                       if ( message.Length + AppendSettingDialog.Instance.TwitterConfiguration.CharactersReservedPerMedia + 1 > 140 )
-                               message = message.Substring( 0, 140 - AppendSettingDialog.Instance.TwitterConfiguration.CharactersReservedPerMedia - 1 ) + " " + url;
-                       else
-                               message += " " + url;
-
-                       return tw.PostStatus( message, reply_to );
-               }
-
-               private HttpStatusCode UploadFile( FileInfo mediaFile, string message, ref string content )
-               {
-                       // Message必須
-                       if ( string.IsNullOrEmpty( message ) )
-                               message = "";
-                       // Check filetype and size(Max 5MB)
-                       if ( !this.CheckValidExtension( mediaFile.Extension ) )
-                               throw new ArgumentException( "Service don't support this filetype." );
-                       if ( !this.CheckValidFilesize( mediaFile.Extension, mediaFile.Length ) )
-                               throw new ArgumentException( "File is too large." );
-
-                       Dictionary< string, string > param = new Dictionary< string, string >();
-                       param.Add( "key", ApplicationSettings.TwitpicApiKey );
-                       param.Add( "message", message );
-                       List< KeyValuePair< string, FileInfo > > binary = new List< KeyValuePair< string, FileInfo > >();
-                       binary.Add( new KeyValuePair< string, FileInfo >( "media", mediaFile ) );
-                       if ( this.GetFileType( mediaFile.Extension ) == UploadFileType.Picture )
-                               this.InstanceTimeout = 60000; // タイムアウト60秒
-                       else
-                               this.InstanceTimeout = 120000;
-
-                       return this.GetContent( HttpConnection.PostMethod, new Uri( "http://api.twitpic.com/2/upload.xml" ), param, binary, ref content, null, null );
-               }
-
-               public bool CheckValidExtension( string ext )
-               {
-                       if ( Array.IndexOf( this.pictureExt, ext.ToLower() ) > -1 )
-                               return true;
-                       if ( Array.IndexOf( this.multimediaExt, ext.ToLower() ) > -1 )
-                               return true;
-
-                       return false;
-               }
-
-               public string GetFileOpenDialogFilter()
-               {
-                       return "Image Files(*" + string.Join( ";*", this.pictureExt ) + ")|*" + string.Join( ";*", this.pictureExt )
-                              + "|Videos(*" + string.Join( ";*", this.multimediaExt ) + ")|*" + string.Join( ";*", this.multimediaExt );
-               }
-
-               public UploadFileType GetFileType( string ext )
-               {
-                       if ( Array.IndexOf( this.pictureExt, ext.ToLower() ) > -1 )
-                               return UploadFileType.Picture;
-                       if ( Array.IndexOf( this.multimediaExt, ext.ToLower() ) > -1 )
-                               return UploadFileType.MultiMedia;
-
-                       return UploadFileType.Invalid;
-               }
-
-               public bool IsSupportedFileType( UploadFileType type )
-               {
-                       return !type.Equals( UploadFileType.Invalid );
-               }
-
-               public bool CheckValidFilesize( string ext, long fileSize )
-               {
-                       if ( Array.IndexOf( this.pictureExt, ext.ToLower() ) > -1 )
-                               return fileSize <= TwitPic.MaxFileSize;
-                       if ( Array.IndexOf( this.multimediaExt, ext.ToLower() ) > -1 )
-                               return true; // Multimedia : no check
-
-                       return false;
-               }
-
-               public bool Configuration( string key, object value )
-               {
-                       return true;
-               }
-
-               public TwitPic( Twitter twitter )
-                       : base( new Uri( "http://api.twitter.com/" ), new Uri( "https://api.twitter.com/1.1/account/verify_credentials.json" ) )
-               {
-                       this.tw = twitter;
-            this.Initialize( ApplicationSettings.TwitterConsumerKey, ApplicationSettings.TwitterConsumerSecret, tw.AccessToken, tw.AccessTokenSecret, "", "" );
-               }
-       }
+    public class TwitPic : IMediaUploadService
+    {
+        private readonly string[] pictureExt = new[] { ".jpg", ".jpeg", ".gif", ".png" };
+
+        private readonly string[] multimediaExt = new[] { ".avi", ".wmv", ".flv", ".m4v", ".mov", ".mp4", ".rm", ".mpeg", ".mpg", ".3gp", ".3g2" };
+
+        private readonly long MaxFileSize = 10L * 1024 * 1024; // Image only
+        // Multimedia filesize limit unknown. But length limit is 1:30.
+
+        private readonly Twitter tw;
+        private readonly TwitpicApi twitpicApi;
+
+        private TwitterConfiguration twitterConfig;
+
+        public TwitPic(Twitter twitter, TwitterConfiguration twitterConfig)
+        {
+            this.tw = twitter;
+            this.twitterConfig = twitterConfig;
+
+            this.twitpicApi = new TwitpicApi(twitter.AccessToken, twitter.AccessTokenSecret);
+        }
+
+        public int MaxMediaCount
+        {
+            get { return 1; }
+        }
+
+        public string SupportedFormatsStrForDialog
+        {
+            get
+            {
+                return "Image Files(*" + string.Join(";*", this.pictureExt) + ")|*" + string.Join(";*", this.pictureExt)
+                    + "|Videos(*" + string.Join(";*", this.multimediaExt) + ")|*" + string.Join(";*", this.multimediaExt);
+            }
+        }
+
+        public bool CheckFileExtension(string fileExtension)
+        {
+            fileExtension = fileExtension.ToLower();
+
+            return this.pictureExt.Contains(fileExtension) ||
+                this.multimediaExt.Contains(fileExtension);
+        }
+
+        public bool CheckFileSize(string fileExtension, long fileSize)
+        {
+            var maxFileSize = this.GetMaxFileSize(fileExtension);
+            return maxFileSize == null || fileSize <= maxFileSize.Value;
+        }
+
+        public long? GetMaxFileSize(string fileExtension)
+        {
+            if (this.multimediaExt.Contains(fileExtension))
+                return null; // Multimedia : no check
+
+            return MaxFileSize;
+        }
+
+        public async Task PostStatusAsync(string text, long? inReplyToStatusId, string[] filePaths)
+        {
+            if (filePaths.Length != 1)
+                throw new ArgumentOutOfRangeException("filePaths");
+
+            var file = new FileInfo(filePaths[0]);
+
+            if (!file.Exists)
+                throw new ArgumentException("Err:File isn't exists.", "filePaths[0]");
+
+            var xml = await this.twitpicApi.UploadFileAsync(file, text)
+                .ConfigureAwait(false);
+
+            var imageUrlElm = xml.XPathSelectElement("/image/url");
+            if (imageUrlElm == null)
+                throw new WebApiException("Invalid API response", xml.ToString());
+
+            var textWithImageUrl = text + " " + imageUrlElm.Value.Trim();
+
+            await Task.Run(() => this.tw.PostStatus(textWithImageUrl, inReplyToStatusId))
+                .ConfigureAwait(false);
+        }
+
+        public int GetReservedTextLength(int mediaCount)
+        {
+            return this.twitterConfig.ShortUrlLength;
+        }
+
+        public void UpdateTwitterConfiguration(TwitterConfiguration config)
+        {
+            this.twitterConfig = config;
+        }
+
+        public class TwitpicApi : HttpConnectionOAuthEcho
+        {
+            private static readonly Uri UploadEndpoint = new Uri("http://api.twitpic.com/2/upload.xml");
+
+            public TwitpicApi(string twitterAccessToken, string twitterAccessTokenSecret)
+                : base(new Uri("http://api.twitter.com/"), new Uri("https://api.twitter.com/1.1/account/verify_credentials.json"))
+            {
+                this.Initialize(ApplicationSettings.TwitterConsumerKey, ApplicationSettings.TwitterConsumerSecret,
+                    twitterAccessToken, twitterAccessTokenSecret, "", "");
+
+                this.InstanceTimeout = 120000;
+            }
+
+            /// <summary>
+            /// 画像のアップロードを行います
+            /// </summary>
+            /// <exception cref="WebApiException"/>
+            /// <exception cref="XmlException"/>
+            public async Task<XDocument> UploadFileAsync(FileInfo file, string message)
+            {
+                // 参照: http://dev.twitpic.com/docs/2/upload/
+
+                var param = new Dictionary<string, string>
+                {
+                    {"key", ApplicationSettings.TwitpicApiKey},
+                    {"message", message},
+                };
+                var paramFiles = new List<KeyValuePair<string, FileInfo>>
+                {
+                    new KeyValuePair<string, FileInfo>("media", file),
+                };
+                var response = "";
+
+                var uploadTask = Task.Run(() => this.GetContent(HttpConnection.PostMethod,
+                    UploadEndpoint, param, paramFiles, ref response, null, null));
+
+                var ret = await uploadTask.ConfigureAwait(false);
+
+                if (ret != HttpStatusCode.OK)
+                    throw new WebApiException("Err:" + ret, response);
+
+                return XDocument.Parse(response);
+            }
+        }
+    }
 }
index 67e4bcf..1790bd7 100644 (file)
 //           (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
 //           (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
 //           (c) 2011      spinor (@tplantd) <http://d.hatena.ne.jp/spinor/>
+//           (c) 2014      kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
 // All rights reserved.
-// 
+//
 // This file is part of OpenTween.
-// 
+//
 // 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 3 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. 
-// 
+// for more details.
+//
 // You should have received a copy of the GNU General Public License along
 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
 // Boston, MA 02110-1301, USA.
 
-using IMultimediaShareService = OpenTween.IMultimediaShareService;
-using Array = System.Array;
-using Convert = System.Convert;
-using Exception = System.Exception;
-using UploadFileType = OpenTween.MyCommon.UploadFileType;
-using MyCommon = OpenTween.MyCommon;
-using FileInfo = System.IO.FileInfo;
-using NotSupportedException = System.NotSupportedException;
+using System;
 using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using OpenTween.Api;
 
-namespace OpenTween
+namespace OpenTween.Connection
 {
-       public class TwitterPhoto : IMultimediaShareService
-       {
-               private string[] pictureExt = new string[] { ".jpg", ".jpeg", ".gif", ".png" };
-
-               private const long MaxfilesizeDefault = 3145728;
-
-               // help/configurationにより取得されコンストラクタへ渡される
-               private long _MaxFileSize = 3145728;
-
-               private Twitter tw;
-
-               public bool CheckValidExtension( string ext )
-               {
-                       if ( Array.IndexOf( this.pictureExt, ext.ToLower() ) > -1 )
-                               return true;
-
-                       return false;
-               }
-
-               public bool CheckValidFilesize( string ext, long fileSize )
-               {
-                       if ( this.CheckValidExtension( ext ) )
-                               return fileSize <= this._MaxFileSize;
-
-                       return false;
-               }
-
-               public bool Configuration( string key, object value )
-               {
-                       if ( key == "MaxUploadFilesize" )
-                       {
-                               long val;
-                               try
-                               {
-                                       val = Convert.ToInt64( value );
-                                       if ( val > 0 )
-                                               this._MaxFileSize = val;
-                                       else
-                                       this._MaxFileSize = TwitterPhoto.MaxfilesizeDefault;
-                               }
-                               catch ( Exception )
-                               {
-                                       this._MaxFileSize = TwitterPhoto.MaxfilesizeDefault;
-                                       return false; // error
-                               }
-                               return true; // 正常に設定終了
-                       }
-                       return true; // 設定項目がない場合はとりあえずエラー扱いにしない
-               }
-
-               public string GetFileOpenDialogFilter()
-               {
-                       return "Image Files(*.gif;*.jpg;*.jpeg;*.png)|*.gif;*.jpg;*.jpeg;*.png";
-               }
-
-               public UploadFileType GetFileType( string ext )
-               {
-                       if ( this.CheckValidExtension( ext ) )
-                               return UploadFileType.Picture;
-
-                       return UploadFileType.Invalid;
-               }
-
-               public bool IsSupportedFileType( UploadFileType type )
-               {
-                       return type.Equals( UploadFileType.Picture );
-               }
-
-               public string Upload( ref string filePath, ref string message, long? reply_to )
-               {
-                       if ( string.IsNullOrEmpty( filePath ) )
-                               return "Err:File isn't specified.";
-
-                       if ( string.IsNullOrEmpty( message ) )
-                               message =  "";
-
-                       FileInfo mediaFile;
-                       try
-                       {
-                               mediaFile = new FileInfo( filePath );
-                       }
-                       catch ( NotSupportedException ex )
-                       {
-                               return "Err:" + ex.Message;
-                       }
-
-                       if ( !mediaFile.Exists )
-                               return "Err:File isn't exists.";
-
-                       if ( MyCommon.IsAnimatedGif( filePath ) )
-                               return "Err:Don't support animatedGIF.";
-
-                       return tw.PostStatusWithMedia( message, reply_to, mediaFile );
-               }
-
-        public string Upload(ref string[] filePaths, ref string message, long? reply_to)
+    public class TwitterPhoto : IMediaUploadService
+    {
+        private readonly string[] pictureExt = new[] { ".jpg", ".jpeg", ".gif", ".png" };
+
+        private readonly Twitter tw;
+        private TwitterConfiguration twitterConfig;
+
+        public TwitterPhoto(Twitter twitter, TwitterConfiguration twitterConfig)
         {
-            if (filePaths == null || filePaths.Length == 0 || string.IsNullOrEmpty(filePaths[0]))
-                return "Err:File isn't specified.";
+            this.tw = twitter;
+            this.twitterConfig = twitterConfig;
+        }
 
-            if (string.IsNullOrEmpty(message))
-                message = "";
+        public int MaxMediaCount
+        {
+            get { return 4; }
+        }
+
+        public string SupportedFormatsStrForDialog
+        {
+            get
+            {
+                return "Image Files(*.gif;*.jpg;*.jpeg;*.png)|*.gif;*.jpg;*.jpeg;*.png";
+            }
+        }
+
+        public bool CheckFileExtension(string fileExtension)
+        {
+            return this.pictureExt.Contains(fileExtension.ToLower());
+        }
+
+        public bool CheckFileSize(string fileExtension, long fileSize)
+        {
+            var maxFileSize = this.GetMaxFileSize(fileExtension);
+            return maxFileSize == null || fileSize <= maxFileSize.Value;
+        }
+
+        public long? GetMaxFileSize(string fileExtension)
+        {
+            return this.twitterConfig.PhotoSizeLimit;
+        }
+
+        public async Task PostStatusAsync(string text, long? inReplyToStatusId, string[] filePaths)
+        {
+            if (filePaths == null || filePaths.Length == 0 || string.IsNullOrEmpty(filePaths[0]))
+                throw new ArgumentException("Err:File isn't specified.", "filePaths");
 
             var mediaFiles = new List<FileInfo>();
 
@@ -145,31 +87,30 @@ namespace OpenTween
             {
                 if (string.IsNullOrEmpty(filePath)) continue;
 
-                FileInfo mediaFile;
-                try
-                {
-                    mediaFile = new FileInfo(filePath);
-                }
-                catch (NotSupportedException ex)
-                {
-                    return "Err:" + ex.Message;
-                }
+                var mediaFile = new FileInfo(filePath);
 
                 if (!mediaFile.Exists)
-                    return "Err:File isn't exists.";
+                    throw new ArgumentException("Err:File isn't exists.", "filePaths");
 
                 if (MyCommon.IsAnimatedGif(filePath))
-                    return "Err:Don't support animatedGIF.";
+                    throw new ArgumentException("Err:Don't support animatedGIF.", "filePaths");
 
                 mediaFiles.Add(mediaFile);
             }
 
-            return tw.PostStatusWithMultipleMedia(message, reply_to, mediaFiles);
+            await Task.Run(() => this.tw.PostStatusWithMultipleMedia(text, inReplyToStatusId, mediaFiles))
+                .ConfigureAwait(false);
+        }
+
+        public int GetReservedTextLength(int mediaCount)
+        {
+            // 枚数に関わらず文字数は一定
+            return this.twitterConfig.ShortUrlLength;
+        }
+
+        public void UpdateTwitterConfiguration(TwitterConfiguration config)
+        {
+            this.twitterConfig = config;
         }
-        
-        public TwitterPhoto(Twitter twitter)
-               {
-                       this.tw = twitter;
-               }
-       }
+    }
 }
index 5450019..d25175e 100644 (file)
 //           (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
 //           (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
 //           (c) 2011      spinor (@tplantd) <http://d.hatena.ne.jp/spinor/>
+//           (c) 2014      kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
 // All rights reserved.
-// 
+//
 // This file is part of OpenTween.
-// 
+//
 // 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 3 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. 
-// 
+// for more details.
+//
 // You should have received a copy of the GNU General Public License along
 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
 // Boston, MA 02110-1301, USA.
 
-using HttpConnectionOAuthEcho = OpenTween.HttpConnectionOAuthEcho;
-using IMultimediaShareService = OpenTween.IMultimediaShareService;
-using FileInfo = System.IO.FileInfo;
-using NotSupportedException = System.NotSupportedException;
-using HttpStatusCode = System.Net.HttpStatusCode;
-using Exception = System.Exception;
-using XmlDocument = System.Xml.XmlDocument;
-using XmlException = System.Xml.XmlException;
-using ArgumentException = System.ArgumentException;
-using System.Collections.Generic; // for Dictionary<TKey, TValue>, List<T>, KeyValuePair<TKey, TValue>
-using Uri = System.Uri;
-using Array = System.Array;
-using UploadFileType = OpenTween.MyCommon.UploadFileType;
-
-namespace OpenTween
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Threading.Tasks;
+using System.Xml;
+using System.Xml.Linq;
+using System.Xml.XPath;
+using OpenTween.Api;
+
+namespace OpenTween.Connection
 {
-       public class imgly : HttpConnectionOAuthEcho, IMultimediaShareService
-       {
-               private string[] pictureExt = new string[] { ".jpg", ".jpeg", ".gif", ".png" };
-
-               private const long MaxFileSize = 4 * 1024 * 1024;
-
-               private Twitter tw;
-
-               public string Upload( ref string filePath, ref string message, long? reply_to )
-               {
-                       if ( string.IsNullOrEmpty( filePath ) )
-                               return "Err:File isn't specified.";
-                       if ( string.IsNullOrEmpty( message ) )
-                               message = "";
-
-                       FileInfo mediaFile;
-                       try
-                       {
-                               mediaFile = new FileInfo( filePath );
-                       }
-                       catch ( NotSupportedException ex )
-                       {
-                               return "Err:" + ex.Message;
-                       }
-                       if ( mediaFile == null || !mediaFile.Exists )
-                               return "Err:File isn't exists.";
-
-                       string content = "";
-                       HttpStatusCode ret;
-                       // img.lyへの投稿
-                       try
-                       {
-                               ret = this.UploadFile( mediaFile, message, ref content );
-                       }
-                       catch ( Exception ex )
-                       {
-                               return "Err:" + ex.Message;
-                       }
-
-                       string url = "";
-                       if ( ret == HttpStatusCode.OK )
-                       {
-                               XmlDocument xd = new XmlDocument();
-                               try
-                               {
-                                       xd.LoadXml( content );
-                                       // URLの取得
-                                       url = xd.SelectSingleNode( "/image/url" ).InnerText;
-                               }
-                               catch ( XmlException ex )
-                               {
-                                       return "Err:" + ex.Message;
-                               }
-                               catch ( Exception ex )
-                               {
-                                       return "Err:" + ex.Message;
-                               }
-                       }
-                       else
-                       {
-                               return "Err:" + ret.ToString();
-                       }
-                       // アップロードまでは成功
-                       filePath = "";
-                       if ( string.IsNullOrEmpty( url ) )
-                               url = "";
-                       // Twitterへの投稿
-                       // 投稿メッセージの再構成
-                       if ( string.IsNullOrEmpty( message ) )
-                               message = "";
-                       if ( message.Length + AppendSettingDialog.Instance.TwitterConfiguration.CharactersReservedPerMedia + 1 > 140 )
-                               message = message.Substring( 0, 140 - AppendSettingDialog.Instance.TwitterConfiguration.CharactersReservedPerMedia - 1 ) + " " + url;
-                       else
-                               message += " " + url;
-
-                       return tw.PostStatus( message, reply_to );
-               }
-
-               private HttpStatusCode UploadFile( FileInfo mediaFile, string message, ref string content )
-               {
-                       // Message必須
-                       if ( string.IsNullOrEmpty( message ) )
-                               message = "";
-                       // Check filetype and size(Max 4MB)
-                       if ( !this.CheckValidExtension( mediaFile.Extension ) )
-                               throw new ArgumentException( "Service don't support this filetype." );
-                       if ( !this.CheckValidFilesize( mediaFile.Extension, mediaFile.Length ) )
-                               throw new ArgumentException( "File is too large." );
-
-                       Dictionary< string, string > param = new Dictionary< string, string >();
-                       param.Add( "message", message );
-                       List< KeyValuePair< string, FileInfo > > binary = new List< KeyValuePair< string, FileInfo > >();
-                       binary.Add( new KeyValuePair< string, FileInfo >( "media", mediaFile ) );
-                       this.InstanceTimeout = 60000; // タイムアウト60秒
-
-                       return this.GetContent( HttpConnection.PostMethod, new Uri( "http://img.ly/api/2/upload.xml" ), param, binary, ref content, null, null );
-               }
-
-               public bool CheckValidExtension( string ext )
-               {
-                       if ( Array.IndexOf( this.pictureExt, ext.ToLower() ) > -1 )
-                               return true;
-
-                       return false;
-               }
-
-               public string GetFileOpenDialogFilter()
-               {
-                       return "Image Files(*.gif;*.jpg;*.jpeg;*.png)|*.gif;*.jpg;*.jpeg;*.png";
-               }
-
-               public UploadFileType GetFileType( string ext )
-               {
-                       if ( this.CheckValidExtension( ext ) )
-                               return UploadFileType.Picture;
-
-                       return UploadFileType.Invalid;
-               }
-
-               public bool IsSupportedFileType( UploadFileType type )
-               {
-                       return type.Equals( UploadFileType.Picture );
-               }
-
-               public bool CheckValidFilesize( string ext, long fileSize )
-               {
-                       if ( this.CheckValidExtension( ext ) )
-                               return fileSize <= imgly.MaxFileSize;
-
-                       return false;
-               }
-
-               public bool Configuration( string key, object value )
-               {
-                       return true;
-               }
-
-               public imgly( Twitter twitter )
-                       : base( new Uri( "http://api.twitter.com/" ), new Uri( "https://api.twitter.com/1.1/account/verify_credentials.json" ) )
-               {
-                       this.tw = twitter;
-            this.Initialize( ApplicationSettings.TwitterConsumerKey, ApplicationSettings.TwitterConsumerSecret, tw.AccessToken, tw.AccessTokenSecret, "", "" );
-               }
-       }
+    public class imgly : IMediaUploadService
+    {
+        private readonly string[] pictureExt = new[] { ".jpg", ".jpeg", ".gif", ".png" };
+        private readonly long MaxFileSize = 4L * 1024 * 1024;
+
+        private readonly Twitter tw;
+        private readonly ImglyApi imglyApi;
+
+        private TwitterConfiguration twitterConfig;
+
+        public imgly(Twitter twitter, TwitterConfiguration twitterConfig)
+        {
+            this.tw = twitter;
+            this.twitterConfig = twitterConfig;
+
+            this.imglyApi = new ImglyApi(twitter.AccessToken, twitter.AccessTokenSecret);
+        }
+
+        public int MaxMediaCount
+        {
+            get { return 1; }
+        }
+
+        public string SupportedFormatsStrForDialog
+        {
+            get
+            {
+                return "Image Files(*.gif;*.jpg;*.jpeg;*.png)|*.gif;*.jpg;*.jpeg;*.png";
+            }
+        }
+
+        public bool CheckFileExtension(string fileExtension)
+        {
+            return this.pictureExt.Contains(fileExtension.ToLower());
+        }
+
+        public bool CheckFileSize(string fileExtension, long fileSize)
+        {
+            var maxFileSize = this.GetMaxFileSize(fileExtension);
+            return maxFileSize == null || fileSize <= maxFileSize.Value;
+        }
+
+        public long? GetMaxFileSize(string fileExtension)
+        {
+            return MaxFileSize;
+        }
+
+        public async Task PostStatusAsync(string text, long? inReplyToStatusId, string[] filePaths)
+        {
+            if (filePaths.Length != 1)
+                throw new ArgumentOutOfRangeException("filePaths");
+
+            var file = new FileInfo(filePaths[0]);
+
+            if (!file.Exists)
+                throw new ArgumentException("Err:File isn't exists.", "filePaths[0]");
+
+            var xml = await this.imglyApi.UploadFileAsync(file, text)
+                .ConfigureAwait(false);
+
+            var imageUrlElm = xml.XPathSelectElement("/image/url");
+            if (imageUrlElm == null)
+                throw new WebApiException("Invalid API response", xml.ToString());
+
+            var textWithImageUrl = text + " " + imageUrlElm.Value.Trim();
+
+            await Task.Run(() => this.tw.PostStatus(textWithImageUrl, inReplyToStatusId))
+                .ConfigureAwait(false);
+        }
+
+        public int GetReservedTextLength(int mediaCount)
+        {
+            return this.twitterConfig.ShortUrlLength;
+        }
+
+        public void UpdateTwitterConfiguration(TwitterConfiguration config)
+        {
+            this.twitterConfig = config;
+        }
+
+        public class ImglyApi : HttpConnectionOAuthEcho
+        {
+            private static readonly Uri UploadEndpoint = new Uri("http://img.ly/api/2/upload.xml");
+
+            public ImglyApi(string twitterAccessToken, string twitterAccessTokenSecret)
+                : base(new Uri("http://api.twitter.com/"), new Uri("https://api.twitter.com/1.1/account/verify_credentials.json"))
+            {
+                this.Initialize(ApplicationSettings.TwitterConsumerKey, ApplicationSettings.TwitterConsumerSecret,
+                    twitterAccessToken, twitterAccessTokenSecret, "", "");
+
+                this.InstanceTimeout = 60000;
+            }
+
+            /// <summary>
+            /// 画像のアップロードを行います
+            /// </summary>
+            /// <exception cref="WebApiException"/>
+            /// <exception cref="XmlException"/>
+            public async Task<XDocument> UploadFileAsync(FileInfo file, string message)
+            {
+                // 参照: http://img.ly/api
+
+                var param = new Dictionary<string, string>
+                {
+                    {"message", message},
+                };
+                var paramFiles = new List<KeyValuePair<string, FileInfo>>
+                {
+                    new KeyValuePair<string, FileInfo>("media", file),
+                };
+                var response = "";
+
+                var uploadTask = Task.Run(() => this.GetContent(HttpConnection.PostMethod,
+                    UploadEndpoint, param, paramFiles, ref response, null, null));
+
+                var ret = await uploadTask.ConfigureAwait(false);
+
+                if (ret != HttpStatusCode.OK)
+                    throw new WebApiException("Err:" + ret, response);
+
+                return XDocument.Parse(response);
+            }
+        }
+    }
 }
index ae18dca..0c3947e 100644 (file)
 //           (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
 //           (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
 //           (c) 2011      spinor (@tplantd) <http://d.hatena.ne.jp/spinor/>
+//           (c) 2014      kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
 // All rights reserved.
-// 
+//
 // This file is part of OpenTween.
-// 
+//
 // 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 3 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. 
-// 
+// for more details.
+//
 // You should have received a copy of the GNU General Public License along
 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
 // Boston, MA 02110-1301, USA.
 
-using HttpConnectionOAuthEcho = OpenTween.HttpConnectionOAuthEcho;
-using IMultimediaShareService = OpenTween.IMultimediaShareService;
-using FileInfo = System.IO.FileInfo;
-using NotSupportedException = System.NotSupportedException;
-using HttpStatusCode = System.Net.HttpStatusCode;
-using Exception = System.Exception;
-using XmlDocument = System.Xml.XmlDocument;
-using XmlException = System.Xml.XmlException;
-using ArgumentException = System.ArgumentException;
-using System.Collections.Generic; // for Dictionary<TKey, TValue>, List<T>, KeyValuePair<TKey, TValue>
-using Uri = System.Uri;
-using Array = System.Array;
-using UploadFileType = OpenTween.MyCommon.UploadFileType;
-
-namespace OpenTween
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Threading.Tasks;
+using System.Xml;
+using System.Xml.Linq;
+using System.Xml.XPath;
+using OpenTween.Api;
+
+namespace OpenTween.Connection
 {
-       public class yfrog : HttpConnectionOAuthEcho, IMultimediaShareService
-       {
-               private string[] pictureExt = new string[] { ".jpg", ".jpeg", ".gif", ".png" };
-
-               private const long MaxFileSize = 5 * 1024 * 1024;
-
-               private Twitter tw;
-
-               public string Upload( ref string filePath, ref string message, long? reply_to )
-               {
-                       if ( string.IsNullOrEmpty( filePath ) )
-                               return "Err:File isn't exists.";
-                       if ( string.IsNullOrEmpty( message ) )
-                               message = "";
-
-                       // FileInfo作成
-                       FileInfo mediaFile;
-                       try
-                       {
-                               mediaFile = new FileInfo( filePath );
-                       }
-                       catch ( NotSupportedException ex )
-                       {
-                               return "Err:" + ex.Message;
-                       }
-                       if ( mediaFile == null || !mediaFile.Exists )
-                               return "Err:File isn't exists.";
-
-                       string content = "";
-                       HttpStatusCode ret;
-                       // yfrogへの投稿
-                       try
-                       {
-                               ret = this.UploadFile( mediaFile, message, ref content );
-                       }
-                       catch ( Exception ex )
-                       {
-                               return "Err:" + ex.Message;
-                       }
-                       string url = "";
-                       if ( ret == HttpStatusCode.OK )
-                       {
-                               XmlDocument xd = new XmlDocument();
-                               try
-                               {
-                                       xd.LoadXml( content );
-                                       // URLの取得
-                    url = xd.SelectSingleNode( "/rsp/mediaurl" ).InnerText;
-                                       }
-                               catch ( XmlException ex )
-                               {
-                                       return "Err:" + ex.Message;
-                               }
-                               catch ( Exception ex )
-                               {
-                                       return "Err:" + ex.Message;
-                               }
-                       }
-                       else
-                               return "Err:" + ret.ToString();
-
-                       if ( string.IsNullOrEmpty( url ) )
-                               url = "";
-                       // アップロードまでは成功
-                       filePath = "";
-                       // Twitterへの投稿
-                       // 投稿メッセージの再構成
-                       if ( string.IsNullOrEmpty( message ) )
-                               message = "";
-                       if ( message.Length + AppendSettingDialog.Instance.TwitterConfiguration.CharactersReservedPerMedia + 1 > 140 )
-                               message = message.Substring(0, 140 - AppendSettingDialog.Instance.TwitterConfiguration.CharactersReservedPerMedia - 1) + " " + url;
-                       else
-                               message += " " + url;
-
-                       return this.tw.PostStatus( message, reply_to );
-               }
-
-               private HttpStatusCode UploadFile( FileInfo mediaFile, string message, ref string content )
-               {
-                       // Message必須
-                       if ( string.IsNullOrEmpty( message ) )
-                               message = "";
-                       // Check filetype and size(Max 5MB)
-                       if ( !this.CheckValidExtension( mediaFile.Extension ) )
-                               throw new ArgumentException( "Service don't support this filetype." );
-                       if ( !this.CheckValidFilesize( mediaFile.Extension, mediaFile.Length ) )
-                               throw new ArgumentException( "File is too large." );
-
-                       Dictionary< string, string > param = new Dictionary< string, string >();
-            param.Add( "key", ApplicationSettings.YfrogApiKey );
-                       param.Add( "message", message );
-                       List< KeyValuePair< string, FileInfo > > binary = new List< KeyValuePair< string, FileInfo > >();
-                       binary.Add( new KeyValuePair< string, FileInfo >( "media", mediaFile ) );
-                       this.InstanceTimeout = 60000; // タイムアウト60秒
-
-                       return this.GetContent( HttpConnection.PostMethod, new Uri( "http://yfrog.com/api/xauth_upload" ), param, binary, ref content, null, null );
-               }
-
-               public bool CheckValidExtension( string ext )
-               {
-                       if ( Array.IndexOf( this.pictureExt, ext.ToLower() ) > -1 )
-                               return true;
-
-                       return false;
-               }
-
-               public string GetFileOpenDialogFilter()
-               {
-                       return "Image Files(*.gif;*.jpg;*.jpeg;*.png)|*.gif;*.jpg;*.jpeg;*.png";
-               }
-
-               public UploadFileType GetFileType( string ext )
-               {
-                       if ( this.CheckValidExtension( ext ) )
-                               return UploadFileType.Picture;
-
-                       return UploadFileType.Invalid;
-               }
-
-               public bool IsSupportedFileType( UploadFileType type )
-               {
-                       return type.Equals( UploadFileType.Picture );
-               }
-
-               public bool CheckValidFilesize( string ext, long fileSize )
-               {
-                       if ( this.CheckValidExtension( ext ) )
-                return fileSize <= yfrog.MaxFileSize;
-
-                       return false;
-               }
-
-               public yfrog( Twitter twitter )
-                       : base( new Uri( "http://api.twitter.com/" ), new Uri( "https://api.twitter.com/1.1/account/verify_credentials.xml" ) )
-               {
-                       this.tw = twitter;
-            this.Initialize( ApplicationSettings.TwitterConsumerKey, ApplicationSettings.TwitterConsumerSecret, this.tw.AccessToken, this.tw.AccessTokenSecret, "", "" );
-               }
-
-               public bool Configuration( string key, object value )
-               {
-                       return true;
-               }
-       }
+    public class yfrog : IMediaUploadService
+    {
+        private readonly string[] pictureExt = new[] { ".jpg", ".jpeg", ".gif", ".png" };
+        private readonly long MaxFileSize = 5L * 1024 * 1024;
+
+        private readonly Twitter tw;
+        private readonly YfrogApi yfrogApi;
+
+        private TwitterConfiguration twitterConfig;
+
+        public yfrog(Twitter twitter, TwitterConfiguration twitterConfig)
+        {
+            this.tw = twitter;
+            this.twitterConfig = twitterConfig;
+
+            this.yfrogApi = new YfrogApi(twitter.AccessToken, twitter.AccessTokenSecret);
+        }
+
+        public int MaxMediaCount
+        {
+            get { return 1; }
+        }
+
+        public string SupportedFormatsStrForDialog
+        {
+            get
+            {
+                return "Image Files(*.gif;*.jpg;*.jpeg;*.png)|*.gif;*.jpg;*.jpeg;*.png";
+            }
+        }
+
+        public bool CheckFileExtension(string fileExtension)
+        {
+            return this.pictureExt.Contains(fileExtension.ToLower());
+        }
+
+        public bool CheckFileSize(string fileExtension, long fileSize)
+        {
+            var maxFileSize = this.GetMaxFileSize(fileExtension);
+            return maxFileSize == null || fileSize <= maxFileSize.Value;
+        }
+
+        public long? GetMaxFileSize(string fileExtension)
+        {
+            return MaxFileSize;
+        }
+
+        public async Task PostStatusAsync(string text, long? inReplyToStatusId, string[] filePaths)
+        {
+            if (filePaths.Length != 1)
+                throw new ArgumentOutOfRangeException("filePaths");
+
+            var file = new FileInfo(filePaths[0]);
+
+            if (!file.Exists)
+                throw new ArgumentException("Err:File isn't exists.", "filePaths[0]");
+
+            var xml = await this.yfrogApi.UploadFileAsync(file, text)
+                .ConfigureAwait(false);
+
+            var imageUrlElm = xml.XPathSelectElement("/rsp/mediaurl");
+            if (imageUrlElm == null)
+                throw new WebApiException("Invalid API response", xml.ToString());
+
+            var textWithImageUrl = text + " " + imageUrlElm.Value.Trim();
+
+            await Task.Run(() => this.tw.PostStatus(textWithImageUrl, inReplyToStatusId))
+                .ConfigureAwait(false);
+        }
+
+        public int GetReservedTextLength(int mediaCount)
+        {
+            return this.twitterConfig.ShortUrlLength;
+        }
+
+        public void UpdateTwitterConfiguration(TwitterConfiguration config)
+        {
+            this.twitterConfig = config;
+        }
+
+        public class YfrogApi : HttpConnectionOAuthEcho
+        {
+            private static readonly Uri UploadEndpoint = new Uri("https://yfrog.com/api/xauth_upload");
+
+            public YfrogApi(string twitterAccessToken, string twitterAccessTokenSecret)
+                : base(new Uri("http://api.twitter.com/"), new Uri("https://api.twitter.com/1.1/account/verify_credentials.xml"))
+            {
+                this.Initialize(ApplicationSettings.TwitterConsumerKey, ApplicationSettings.TwitterConsumerSecret,
+                    twitterAccessToken, twitterAccessTokenSecret, "", "");
+
+                this.InstanceTimeout = 60000;
+            }
+
+            /// <summary>
+            /// 画像のアップロードを行います
+            /// </summary>
+            /// <exception cref="WebApiException"/>
+            /// <exception cref="XmlException"/>
+            public async Task<XDocument> UploadFileAsync(FileInfo file, string message)
+            {
+                // 参照: http://twitter.yfrog.com/page/api#a1
+
+                var param = new Dictionary<string, string>
+                {
+                    {"key", ApplicationSettings.YfrogApiKey},
+                };
+                var paramFiles = new List<KeyValuePair<string, FileInfo>>
+                {
+                    new KeyValuePair<string, FileInfo>("media", file),
+                };
+                var response = "";
+
+                var uploadTask = Task.Run(() => this.GetContent(HttpConnection.PostMethod,
+                    UploadEndpoint, param, paramFiles, ref response, null, null));
+
+                var ret = await uploadTask.ConfigureAwait(false);
+
+                if (ret != HttpStatusCode.OK)
+                    throw new WebApiException("Err:" + ret, response);
+
+                return XDocument.Parse(response);
+            }
+        }
+    }
 }
index ca59144..47ee93c 100644 (file)
@@ -29,6 +29,7 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using System.Windows.Forms;
+using OpenTween.Api;
 using OpenTween.Connection;
 
 namespace OpenTween
@@ -68,15 +69,23 @@ namespace OpenTween
         }
 
         /// <summary>
-        /// 指定された投稿先名から、作成済みの IMultimediaShareService インスタンスを取得する。
+        /// 指定された投稿先名から、作成済みの IMediaUploadService インスタンスを取得する。
         /// </summary>
-        public IMultimediaShareService GetService(string serviceName)
+        public IMediaUploadService GetService(string serviceName)
         {
-            IMultimediaShareService service;
+            IMediaUploadService service;
             this.pictureService.TryGetValue(serviceName, out service);
             return service;
         }
 
+        /// <summary>
+        /// 利用可能な全ての IMediaUploadService インスタンスを取得する。
+        /// </summary>
+        public ICollection<IMediaUploadService> GetServices()
+        {
+            return this.pictureService.Values;
+        }
+
         private class SelectedMedia
         {
             public string Path { get; set; }
@@ -106,20 +115,20 @@ namespace OpenTween
             }
         }
 
-        private Dictionary<string, IMultimediaShareService> pictureService;
+        private Dictionary<string, IMediaUploadService> pictureService;
 
-        private void CreateServices(Twitter tw)
+        private void CreateServices(Twitter tw, TwitterConfiguration twitterConfig)
         {
             if (this.pictureService != null) this.pictureService.Clear();
             this.pictureService = null;
 
-            this.pictureService = new Dictionary<string, IMultimediaShareService> {
-                {"TwitPic", new TwitPic(tw)},
-                {"img.ly", new imgly(tw)},
-                {"yfrog", new yfrog(tw)},
-                {"Twitter", new TwitterPhoto(tw)},
-                {"ついっぷるフォト", new TwipplePhoto(tw)},
-                {"Imgur", new Imgur(tw)},
+            this.pictureService = new Dictionary<string, IMediaUploadService> {
+                {"TwitPic", new TwitPic(tw, twitterConfig)},
+                {"img.ly", new imgly(tw, twitterConfig)},
+                {"yfrog", new yfrog(tw, twitterConfig)},
+                {"Twitter", new TwitterPhoto(tw, twitterConfig)},
+                {"ついっぷるフォト", new TwipplePhoto(tw, twitterConfig)},
+                {"Imgur", new Imgur(tw, twitterConfig)},
             };
         }
 
@@ -133,9 +142,9 @@ namespace OpenTween
         /// <summary>
         /// 投稿先サービスなどを初期化する。
         /// </summary>
-        public void Initialize(Twitter tw, string svc, int? index = null)
+        public void Initialize(Twitter tw, TwitterConfiguration twitterConfig, string svc, int? index = null)
         {
-            CreateServices(tw);
+            CreateServices(tw, twitterConfig);
 
             SetImageServiceCombo();
             SetImagePageCombo();
@@ -146,9 +155,9 @@ namespace OpenTween
         /// <summary>
         /// 投稿先サービスを再作成する。
         /// </summary>
-        public void Reset(Twitter tw)
+        public void Reset(Twitter tw, TwitterConfiguration twitterConfig)
         {
-            CreateServices(tw);
+            CreateServices(tw, twitterConfig);
 
             SetImageServiceCombo();
         }
@@ -163,7 +172,7 @@ namespace OpenTween
 
             var serviceName = this.ServiceName;
             if (!string.IsNullOrEmpty(serviceName) &&
-                this.pictureService[serviceName].CheckValidFilesize(ext, fl.Length))
+                this.pictureService[serviceName].CheckFileSize(ext, fl.Length))
             {
                 return true;
             }
@@ -171,7 +180,7 @@ namespace OpenTween
             foreach (string svc in ImageServiceCombo.Items)
             {
                 if (!string.IsNullOrEmpty(svc) &&
-                    this.pictureService[svc].CheckValidFilesize(ext, fl.Length))
+                    this.pictureService[svc].CheckFileSize(ext, fl.Length))
                 {
                     return true;
                 }
@@ -277,7 +286,7 @@ namespace OpenTween
         private void FilePickButton_Click(object sender, EventArgs e)
         {
             if (FilePickDialog == null || string.IsNullOrEmpty(this.ServiceName)) return;
-            FilePickDialog.Filter = this.pictureService[this.ServiceName].GetFileOpenDialogFilter();
+            FilePickDialog.Filter = this.pictureService[this.ServiceName].SupportedFormatsStrForDialog;
             FilePickDialog.Title = Properties.Resources.PickPictureDialog1;
             FilePickDialog.FileName = "";
 
@@ -328,7 +337,7 @@ namespace OpenTween
                 string ext = fl.Extension;
                 var imageService = this.pictureService[serviceName];
 
-                if (!imageService.CheckValidExtension(ext))
+                if (!imageService.CheckFileExtension(ext))
                 {
                     //画像以外の形式
                     ClearSelectedImagePage();
@@ -343,7 +352,7 @@ namespace OpenTween
                     return;
                 }
 
-                if (!imageService.CheckValidFilesize(ext, fl.Length))
+                if (!imageService.CheckFileSize(ext, fl.Length))
                 {
                     // ファイルサイズが大きすぎる
                     ClearSelectedImagePage();
@@ -358,21 +367,17 @@ namespace OpenTween
                     return;
                 }
 
-                switch (imageService.GetFileType(ext))
+                try
                 {
-                    case MyCommon.UploadFileType.Picture:
-                        using (var fs = File.OpenRead(fileName))
-                        {
-                            ImageSelectedPicture.Image = MemoryImage.CopyFromStream(fs);
-                        }
-                        SetSelectedImagePage(fileName, MyCommon.UploadFileType.Picture);
-                        break;
-                    case MyCommon.UploadFileType.MultiMedia:
-                        SetSelectedImagePage(fileName, MyCommon.UploadFileType.MultiMedia);
-                        break;
-                    default:
-                        ClearSelectedImagePage();
-                        break;
+                    using (var fs = File.OpenRead(fileName))
+                    {
+                        ImageSelectedPicture.Image = MemoryImage.CopyFromStream(fs);
+                    }
+                    SetSelectedImagePage(fileName, MyCommon.UploadFileType.Picture);
+                }
+                catch (InvalidImageException)
+                {
+                    SetSelectedImagePage(fileName, MyCommon.UploadFileType.MultiMedia);
                 }
             }
             catch (FileNotFoundException)
@@ -391,7 +396,7 @@ namespace OpenTween
         {
             var text = string.Join(", ",
                 ImageServiceCombo.Items.Cast<string>()
-                    .Where(x => !string.IsNullOrEmpty(x) && this.pictureService[x].CheckValidFilesize(ext, fileSize)));
+                    .Where(x => !string.IsNullOrEmpty(x) && this.pictureService[x].CheckFileSize(ext, fileSize)));
 
             if (string.IsNullOrEmpty(text))
                 return Properties.Resources.PostPictureWarn6;
@@ -513,7 +518,7 @@ namespace OpenTween
                                     FileInfo fi = new FileInfo(ImagefilePathText.Text.Trim());
                                     string ext = fi.Extension;
                                     var imageService = this.pictureService[serviceName];
-                                    if (!imageService.CheckValidFilesize(ext, fi.Length))
+                                    if (!imageService.CheckFileSize(ext, fi.Length))
                                     {
                                         ClearImageSelectedPicture();
                                         ClearSelectedImagePage();
index 24d3410..fa3f226 100644 (file)
     <Compile Include="Connection\HttpConnectionOAuth.cs" />
     <Compile Include="Connection\HttpConnectionOAuthEcho.cs" />
     <Compile Include="Connection\IHttpConnection.cs" />
+    <Compile Include="Connection\IMediaUploadService.cs" />
     <Compile Include="Connection\imgly.cs" />
     <Compile Include="Connection\Imgur.cs" />
-    <Compile Include="Connection\IMultimediaShareService.cs" />
     <Compile Include="Connection\TwipplePhoto.cs" />
     <Compile Include="EventViewerDialog.cs">
       <SubType>Form</SubType>
index d71d35e..eb7585a 100644 (file)
@@ -1015,7 +1015,7 @@ namespace OpenTween
             AllrepliesToolStripMenuItem.Checked = tw.AllAtReply;
 
             //画像投稿サービス
-            ImageSelector.Initialize(tw, _cfgCommon.UseImageServiceName, _cfgCommon.UseImageService);
+            ImageSelector.Initialize(tw, SettingDialog.TwitterConfiguration, _cfgCommon.UseImageServiceName, _cfgCommon.UseImageService);
 
             //ウィンドウ設定
             this.ClientSize = _cfgLocal.FormSize;
@@ -2518,19 +2518,14 @@ namespace OpenTween
                     else
                     {
                         var service = ImageSelector.GetService(args.status.imageService);
-                        if (args.status.imagePath.Length > 1 &&
-                            args.status.imageService.Equals("Twitter"))
+                        try
                         {
-                            //複数画像投稿
-                            ret = ((TwitterPhoto)service).Upload(ref args.status.imagePath,
-                                                                 ref args.status.status,
-                                                                 args.status.inReplyToId);
+                            service.PostStatusAsync(args.status.status, args.status.inReplyToId, args.status.imagePath)
+                                .Wait();
                         }
-                        else
+                        catch (AggregateException ex)
                         {
-                            ret = service.Upload(ref args.status.imagePath[0],
-                                                 ref args.status.status,
-                                                 args.status.inReplyToId);
+                            ret = ex.InnerException.Message;
                         }
                     }
                     bw.ReportProgress(300);
@@ -3068,9 +3063,10 @@ namespace OpenTween
                     //_waitFollower = false
                     if (SettingDialog.TwitterConfiguration.PhotoSizeLimit != 0)
                     {
-                        var service = ImageSelector.GetService("Twitter");
-                        if (service != null)
-                            service.Configuration("MaxUploadFilesize", SettingDialog.TwitterConfiguration.PhotoSizeLimit);
+                        foreach (var service in this.ImageSelector.GetServices())
+                        {
+                            service.UpdateTwitterConfiguration(this.SettingDialog.TwitterConfiguration);
+                        }
                     }
                     this.PurgeListViewItemCache();
                     if (_curList != null) _curList.Refresh();
@@ -3928,7 +3924,7 @@ namespace OpenTween
                                                         SettingDialog.ProxyUser,
                                                         SettingDialog.ProxyPassword);
 
-                    ImageSelector.Reset(tw);
+                    ImageSelector.Reset(tw, SettingDialog.TwitterConfiguration);
 
                     try
                     {