OSDN Git Service

HttpTwitter.SendDirectMessageメソッドをTwitterApiクラスに置き換え
[opentween/open-tween.git] / OpenTween / Connection / TwipplePhoto.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2013 ANIKITI (@anikiti07) <https://twitter.com/anikiti07>
3 //           (c) 2014 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
4 // All rights reserved.
5 //
6 // This file is part of OpenTween.
7 //
8 // This program is free software; you can redistribute it and/or modify it
9 // under the terms of the GNU General Public License as published by the Free
10 // Software Foundation; either version 3 of the License, or (at your option)
11 // any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 // for more details.
17 //
18 // You should have received a copy of the GNU General Public License along
19 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
20 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
21 // Boston, MA 02110-1301, USA.
22
23 using System;
24 using System.Collections.Generic;
25 using System.IO;
26 using System.Linq;
27 using System.Net;
28 using System.Threading.Tasks;
29 using System.Windows.Forms;
30 using System.Xml;
31 using System.Xml.Linq;
32 using System.Xml.XPath;
33 using OpenTween.Api.DataModel;
34
35 namespace OpenTween.Connection
36 {
37     public sealed class TwipplePhoto : IMediaUploadService
38     {
39         private static readonly long MaxFileSize = 4L * 1024 * 1024;
40         private static readonly IEnumerable<string> SupportedPictureExtensions = new[]
41         {
42             ".gif",
43             ".jpg",
44             ".png",
45         };
46
47         private readonly Twitter twitter;
48         private readonly TwippleApi twippleApi;
49
50         private TwitterConfiguration twitterConfig;
51
52         #region Constructors
53
54         public TwipplePhoto(Twitter twitter, TwitterConfiguration twitterConfig)
55         {
56             if (twitter == null)
57                 throw new ArgumentNullException(nameof(twitter));
58             if (twitterConfig == null)
59                 throw new ArgumentNullException(nameof(twitterConfig));
60
61             this.twitter = twitter;
62             this.twitterConfig = twitterConfig;
63
64             this.twippleApi = new TwippleApi(twitter.AccessToken, twitter.AccessTokenSecret);
65         }
66
67         #endregion
68
69         public int MaxMediaCount
70         {
71             get { return 1; }
72         }
73
74         public string SupportedFormatsStrForDialog
75         {
76             get
77             {
78                 var filterFormatExtensions = "";
79                 foreach (var pictureExtension in SupportedPictureExtensions)
80                 {
81                     filterFormatExtensions += '*';
82                     filterFormatExtensions += pictureExtension;
83                     filterFormatExtensions += ';';
84                 }
85                 return "Image Files(" + filterFormatExtensions + ")|" + filterFormatExtensions;
86             }
87         }
88
89         public bool CheckFileExtension(string fileExtension)
90         {
91             return SupportedPictureExtensions.Contains(fileExtension, StringComparer.OrdinalIgnoreCase);
92         }
93
94         public bool CheckFileSize(string fileExtension, long fileSize)
95         {
96             var maxFileSize = this.GetMaxFileSize(fileExtension);
97             return maxFileSize == null || fileSize <= maxFileSize.Value;
98         }
99
100         public long? GetMaxFileSize(string fileExtension)
101         {
102             return MaxFileSize;
103         }
104
105         public async Task PostStatusAsync(string text, long? inReplyToStatusId, IMediaItem[] mediaItems)
106         {
107             if (mediaItems == null)
108                 throw new ArgumentNullException(nameof(mediaItems));
109
110             if (mediaItems.Length != 1)
111                 throw new ArgumentOutOfRangeException(nameof(mediaItems));
112
113             var item = mediaItems[0];
114
115             if (item == null)
116                 throw new ArgumentException("Err:Media not specified.");
117
118             if (!item.Exists)
119                 throw new ArgumentException("Err:Media not found.");
120
121             var xml = await this.twippleApi.UploadFileAsync(item)
122                 .ConfigureAwait(false);
123
124             var imageUrlElm = xml.XPathSelectElement("/rsp/mediaurl");
125             if (imageUrlElm == null)
126                 throw new WebApiException("Invalid API response", xml.ToString());
127
128             var textWithImageUrl = text + " " + imageUrlElm.Value.Trim();
129
130             await this.twitter.PostStatus(textWithImageUrl, inReplyToStatusId)
131                 .ConfigureAwait(false);
132         }
133
134         public int GetReservedTextLength(int mediaCount)
135         {
136             return this.twitterConfig.ShortUrlLength;
137         }
138
139         public void UpdateTwitterConfiguration(TwitterConfiguration config)
140         {
141             this.twitterConfig = config;
142         }
143
144         public class TwippleApi : HttpConnectionOAuthEcho
145         {
146             private static readonly Uri UploadEndpoint = new Uri("http://p.twipple.jp/api/upload2");
147
148             public TwippleApi(string twitterAccessToken, string twitterAccessTokenSecret)
149                 : base(new Uri("http://api.twitter.com/"), new Uri("https://api.twitter.com/1.1/account/verify_credentials.json"))
150             {
151                 this.Initialize(ApplicationSettings.TwitterConsumerKey, ApplicationSettings.TwitterConsumerSecret,
152                     twitterAccessToken, twitterAccessTokenSecret, "", "");
153
154                 this.InstanceTimeout = 60000;
155             }
156
157             /// <summary>
158             /// 画像のアップロードを行います
159             /// </summary>
160             /// <exception cref="WebApiException"/>
161             /// <exception cref="XmlException"/>
162             public async Task<XDocument> UploadFileAsync(IMediaItem item)
163             {
164                 // 参照: http://p.twipple.jp/wiki/API_Upload2/ja
165
166                 var param = new Dictionary<string, string>
167                 {
168                     ["upload_from"] = Application.ProductName,
169                 };
170                 var paramFiles = new List<KeyValuePair<string, IMediaItem>>
171                 {
172                     new KeyValuePair<string, IMediaItem>("media", item),
173                 };
174                 var response = "";
175
176                 var uploadTask = Task.Run(() => this.GetContent(HttpConnection.PostMethod,
177                     UploadEndpoint, param, paramFiles, ref response, null, null));
178
179                 var ret = await uploadTask.ConfigureAwait(false);
180
181                 if (ret != HttpStatusCode.OK)
182                     throw new WebApiException("Err:" + ret, response);
183
184                 return XDocument.Parse(response);
185             }
186         }
187     }
188 }