OSDN Git Service

PostingStatusクラスをPostStatusParamsに名前変更しTwitter.PostStatusメソッドの引数として直接扱う
[opentween/open-tween.git] / OpenTween / Connection / Imgur.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2013 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
4 //
5 // This file is part of OpenTween.
6 //
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by the Free
9 // Software Foundation; either version 3 of the License, or (at your option)
10 // any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 // for more details.
16 //
17 // You should have received a copy of the GNU General Public License along
18 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
19 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 // Boston, MA 02110-1301, USA.
21
22 using System;
23 using System.Collections.Generic;
24 using System.IO;
25 using System.Linq;
26 using System.Net.Http;
27 using System.Net.Http.Headers;
28 using System.Text;
29 using System.Threading.Tasks;
30 using System.Xml.Linq;
31 using OpenTween.Api.DataModel;
32
33 namespace OpenTween.Connection
34 {
35     public class Imgur : IMediaUploadService
36     {
37         private readonly static long MaxFileSize = 10L * 1024 * 1024;
38
39         private readonly static IEnumerable<string> SupportedExtensions = new[]
40         {
41             ".jpg",
42             ".jpeg",
43             ".gif",
44             ".png",
45             ".tif",
46             ".tiff",
47             ".bmp",
48             ".pdf",
49             ".xcf",
50         };
51
52         private readonly Twitter twitter;
53         private readonly ImgurApi imgurApi;
54
55         private TwitterConfiguration twitterConfig;
56
57         public Imgur(Twitter tw, TwitterConfiguration twitterConfig)
58         {
59             this.twitter = tw;
60             this.twitterConfig = twitterConfig;
61
62             this.imgurApi = new ImgurApi();
63         }
64
65         public int MaxMediaCount
66         {
67             get { return 1; }
68         }
69
70         public string SupportedFormatsStrForDialog
71         {
72             get
73             {
74                 var formats = new StringBuilder();
75
76                 foreach (var extension in SupportedExtensions)
77                     formats.AppendFormat("*{0};", extension);
78
79                 return "Image Files(" + formats + ")|" + formats;
80             }
81         }
82
83         public bool CanUseAltText => false;
84
85         public bool CheckFileExtension(string fileExtension)
86         {
87             return SupportedExtensions.Contains(fileExtension, StringComparer.OrdinalIgnoreCase);
88         }
89
90         public bool CheckFileSize(string fileExtension, long fileSize)
91         {
92             var maxFileSize = this.GetMaxFileSize(fileExtension);
93             return maxFileSize == null || fileSize <= maxFileSize.Value;
94         }
95
96         public long? GetMaxFileSize(string fileExtension)
97         {
98             return MaxFileSize;
99         }
100
101         public async Task<PostStatusParams> UploadAsync(IMediaItem[] mediaItems, PostStatusParams postParams)
102         {
103             if (mediaItems == null)
104                 throw new ArgumentNullException(nameof(mediaItems));
105
106             if (mediaItems.Length != 1)
107                 throw new ArgumentOutOfRangeException(nameof(mediaItems));
108
109             var item = mediaItems[0];
110
111             if (item == null)
112                 throw new ArgumentException("Err:Media not specified.");
113
114             if (!item.Exists)
115                 throw new ArgumentException("Err:Media not found.");
116
117             XDocument xml;
118             try
119             {
120                 xml = await this.imgurApi.UploadFileAsync(item, postParams.Text)
121                     .ConfigureAwait(false);
122             }
123             catch (HttpRequestException ex)
124             {
125                 throw new WebApiException("Err:" + ex.Message, ex);
126             }
127             catch (OperationCanceledException ex)
128             {
129                 throw new WebApiException("Err:Timeout", ex);
130             }
131
132             var imageElm = xml.Element("data");
133
134             if (imageElm.Attribute("success").Value != "1")
135                 throw new WebApiException("Err:" + imageElm.Attribute("status").Value);
136
137             var imageUrl = imageElm.Element("link").Value;
138
139             postParams.Text += " " + imageUrl.Trim();
140
141             return postParams;
142         }
143
144         public int GetReservedTextLength(int mediaCount)
145             => this.twitterConfig.ShortUrlLength + 1;
146
147         public void UpdateTwitterConfiguration(TwitterConfiguration config)
148         {
149             this.twitterConfig = config;
150         }
151
152         public class ImgurApi
153         {
154             private readonly HttpClient http;
155
156             private static readonly Uri UploadEndpoint = new Uri("https://api.imgur.com/3/image.xml");
157
158             public ImgurApi()
159             {
160                 this.http = Networking.CreateHttpClient(Networking.CreateHttpClientHandler());
161                 this.http.Timeout = Networking.UploadImageTimeout;
162             }
163
164             public async Task<XDocument> UploadFileAsync(IMediaItem item, string title)
165             {
166                 using (var content = new MultipartFormDataContent())
167                 using (var mediaStream = item.OpenRead())
168                 using (var mediaContent = new StreamContent(mediaStream))
169                 using (var titleContent = new StringContent(title))
170                 {
171                     content.Add(mediaContent, "image", item.Name);
172                     content.Add(titleContent, "title");
173
174                     using (var request = new HttpRequestMessage(HttpMethod.Post, UploadEndpoint))
175                     {
176                         request.Headers.Authorization =
177                             new AuthenticationHeaderValue("Client-ID", ApplicationSettings.ImgurClientID);
178                         request.Content = content;
179
180                         using (var response = await this.http.SendAsync(request).ConfigureAwait(false))
181                         {
182                             response.EnsureSuccessStatusCode();
183
184                             using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
185                             {
186                                 return XDocument.Load(stream);
187                             }
188                         }
189                     }
190                 }
191             }
192         }
193     }
194 }