1 // OpenTween - Client of Twitter
2 // Copyright (c) 2013 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
5 // This file is part of OpenTween.
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)
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
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.
23 using System.Collections.Generic;
26 using System.Net.Http;
27 using System.Net.Http.Headers;
29 using System.Threading.Tasks;
30 using System.Xml.Linq;
31 using OpenTween.Api.DataModel;
33 namespace OpenTween.Connection
35 public class Imgur : IMediaUploadService
37 private readonly static long MaxFileSize = 10L * 1024 * 1024;
39 private readonly static IEnumerable<string> SupportedExtensions = new[]
52 private readonly Twitter twitter;
53 private readonly ImgurApi imgurApi;
55 private TwitterConfiguration twitterConfig;
57 public Imgur(Twitter tw, TwitterConfiguration twitterConfig)
60 this.twitterConfig = twitterConfig;
62 this.imgurApi = new ImgurApi();
65 public int MaxMediaCount
70 public string SupportedFormatsStrForDialog
74 var formats = new StringBuilder();
76 foreach (var extension in SupportedExtensions)
77 formats.AppendFormat("*{0};", extension);
79 return "Image Files(" + formats + ")|" + formats;
83 public bool CanUseAltText => false;
85 public bool CheckFileExtension(string fileExtension)
87 return SupportedExtensions.Contains(fileExtension, StringComparer.OrdinalIgnoreCase);
90 public bool CheckFileSize(string fileExtension, long fileSize)
92 var maxFileSize = this.GetMaxFileSize(fileExtension);
93 return maxFileSize == null || fileSize <= maxFileSize.Value;
96 public long? GetMaxFileSize(string fileExtension)
101 public async Task PostStatusAsync(string text, long? inReplyToStatusId, IMediaItem[] mediaItems)
103 if (mediaItems == null)
104 throw new ArgumentNullException(nameof(mediaItems));
106 if (mediaItems.Length != 1)
107 throw new ArgumentOutOfRangeException(nameof(mediaItems));
109 var item = mediaItems[0];
112 throw new ArgumentException("Err:Media not specified.");
115 throw new ArgumentException("Err:Media not found.");
120 xml = await this.imgurApi.UploadFileAsync(item, text)
121 .ConfigureAwait(false);
123 catch (HttpRequestException ex)
125 throw new WebApiException("Err:" + ex.Message, ex);
127 catch (OperationCanceledException ex)
129 throw new WebApiException("Err:Timeout", ex);
132 var imageElm = xml.Element("data");
134 if (imageElm.Attribute("success").Value != "1")
135 throw new WebApiException("Err:" + imageElm.Attribute("status").Value);
137 var imageUrl = imageElm.Element("link").Value;
139 var textWithImageUrl = text + " " + imageUrl.Trim();
141 await this.twitter.PostStatus(textWithImageUrl, inReplyToStatusId)
142 .ConfigureAwait(false);
145 public int GetReservedTextLength(int mediaCount)
146 => this.twitterConfig.ShortUrlLength + 1;
148 public void UpdateTwitterConfiguration(TwitterConfiguration config)
150 this.twitterConfig = config;
153 public class ImgurApi
155 private readonly HttpClient http;
157 private static readonly Uri UploadEndpoint = new Uri("https://api.imgur.com/3/image.xml");
161 this.http = Networking.CreateHttpClient(Networking.CreateHttpClientHandler());
162 this.http.Timeout = Networking.UploadImageTimeout;
165 public async Task<XDocument> UploadFileAsync(IMediaItem item, string title)
167 using (var content = new MultipartFormDataContent())
168 using (var mediaStream = item.OpenRead())
169 using (var mediaContent = new StreamContent(mediaStream))
170 using (var titleContent = new StringContent(title))
172 content.Add(mediaContent, "image", item.Name);
173 content.Add(titleContent, "title");
175 using (var request = new HttpRequestMessage(HttpMethod.Post, UploadEndpoint))
177 request.Headers.Authorization =
178 new AuthenticationHeaderValue("Client-ID", ApplicationSettings.ImgurClientID);
179 request.Content = content;
181 using (var response = await this.http.SendAsync(request).ConfigureAwait(false))
183 response.EnsureSuccessStatusCode();
185 using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
187 return XDocument.Load(stream);