protected HttpWebRequest CreateRequest(string method,
Uri requestUri,
Dictionary<string, string> param,
- List<KeyValuePair<String, FileInfo>> binaryFileInfo)
+ List<KeyValuePair<String, IMediaItem>> binaryFileInfo)
{
Networking.CheckInitialized();
//POST送信するバイナリデータを作成
if (binaryFileInfo != null)
{
- foreach (KeyValuePair<string, FileInfo> kvp in binaryFileInfo)
+ foreach (KeyValuePair<string, IMediaItem> kvp in binaryFileInfo)
{
string postData = "";
byte[] crlfByte = Encoding.UTF8.GetBytes("\r\n");
byte[] postBytes = Encoding.UTF8.GetBytes(postData);
reqStream.Write(postBytes, 0, postBytes.Length);
//ファイルを読み出してHTTPのストリームに書き込み
- using (FileStream fs = new FileStream(kvp.Value.FullName, FileMode.Open, FileAccess.Read))
- {
- int readSize = 0;
- byte[] readBytes = new byte[0x1000];
- while (true)
- {
- readSize = fs.Read(readBytes, 0, readBytes.Length);
- if (readSize == 0) break;
- reqStream.Write(readBytes, 0, readSize);
- }
- }
+ kvp.Value.CopyTo(reqStream);
reqStream.Write(crlfByte, 0, crlfByte.Length);
}
}
public HttpStatusCode GetContent( string method,
Uri requestUri,
Dictionary< string, string > param,
- List< KeyValuePair< string, FileInfo > > binary,
+ List< KeyValuePair< string, IMediaItem > > binary,
ref string content,
Dictionary< string, string > headerInfo,
CallbackDelegate callback )
null);
}
- public HttpStatusCode UpdateStatusWithMedia(string status, long? replyToId, FileInfo mediaFile, ref string content)
+ public HttpStatusCode UpdateStatusWithMedia(string status, long? replyToId, IMediaItem item, ref string content)
{
//画像投稿用エンドポイント
Dictionary<string, string> param = new Dictionary<string, string>();
param.Add("include_entities", "true");
//if (AppendSettingDialog.Instance.ShortenTco && AppendSettingDialog.Instance.UrlConvertAuto) param.Add("wrap_links", "true")
- List<KeyValuePair<string, FileInfo>> binary = new List<KeyValuePair<string, FileInfo>>();
- binary.Add(new KeyValuePair<string, FileInfo>("media[]", mediaFile));
+ var binary = new List<KeyValuePair<string, IMediaItem>>();
+ binary.Add(new KeyValuePair<string, IMediaItem>("media[]", item));
return httpCon.GetContent(PostMethod,
this.CreateTwitterUri("/1.1/statuses/update_with_media.json"),
this.CreateApiCalllback("/statuses/update_with_media"));
}
- public HttpStatusCode UploadMedia(FileInfo mediaFile, ref string content)
+ public HttpStatusCode UploadMedia(IMediaItem item, ref string content)
{
//画像投稿専用エンドポイント
- List<KeyValuePair<string, FileInfo>> binary = new List<KeyValuePair<string, FileInfo>>();
- binary.Add(new KeyValuePair<string, FileInfo>("media", mediaFile));
+ var binary = new List<KeyValuePair<string, IMediaItem>>();
+ binary.Add(new KeyValuePair<string, IMediaItem>("media", item));
return httpCon.GetContent(PostMethod,
this.CreateTwitterUploadUri("/1.1/media/upload.json"),
public HttpStatusCode UpdateProfileImage(FileInfo imageFile, ref string content)
{
- List<KeyValuePair<string, FileInfo>> binary = new List<KeyValuePair<string, FileInfo>>();
- binary.Add(new KeyValuePair<string, FileInfo>("image", imageFile));
+ var binary = new List<KeyValuePair<string, IMediaItem>>();
+ binary.Add(new KeyValuePair<string, IMediaItem>("image", new FileMediaItem(imageFile)));
return httpCon.GetContent(PostMethod,
this.CreateTwitterUri("/1.1/account/update_profile_image.json"),
HttpStatusCode GetContent(string method,
Uri requestUri,
Dictionary<string, string> param,
- List<KeyValuePair<string, FileInfo>> binary,
+ List<KeyValuePair<string, IMediaItem>> binary,
ref string content,
Dictionary<string, string> headerInfo,
CallbackDelegate callback);
/// メディアのアップロードとツイートの投稿を行います
/// </summary>
/// <exception cref="WebApiException"/>
- Task PostStatusAsync(string text, long? inReplyToStatusId, string[] filePaths);
+ Task PostStatusAsync(string text, long? inReplyToStatusId, IMediaItem[] mediaItems);
/// <summary>
/// 画像URLのために確保する必要のある文字数を返します
return MaxFileSize;
}
- public async Task PostStatusAsync(string text, long? inReplyToStatusId, string[] filePaths)
+ public async Task PostStatusAsync(string text, long? inReplyToStatusId, IMediaItem[] mediaItems)
{
- if (filePaths.Length != 1)
- throw new ArgumentOutOfRangeException("filePaths");
+ if (mediaItems.Length != 1)
+ throw new ArgumentOutOfRangeException("mediaItems");
- var file = new FileInfo(filePaths[0]);
+ var item = mediaItems[0] as FileMediaItem;
- if (!file.Exists)
- throw new ArgumentException("File isn't exists.", "filePaths[0]");
+ if (item == null)
+ throw new NotImplementedException();
+
+ if (!item.Exists)
+ throw new ArgumentException("File isn't exists.", "mediaItems[0]");
XDocument xml;
try
{
- xml = await this.UploadFileAsync(file, text)
+ xml = await this.UploadFileAsync(item.FileInfo, text)
.ConfigureAwait(false);
}
catch (HttpRequestException ex)
return MaxFileSize;
}
- public async Task PostStatusAsync(string text, long? inReplyToStatusId, string[] filePaths)
+ public async Task PostStatusAsync(string text, long? inReplyToStatusId, IMediaItem[] mediaItems)
{
- if (filePaths.Length != 1)
- throw new ArgumentOutOfRangeException("filePaths");
+ if (mediaItems.Length != 1)
+ throw new ArgumentOutOfRangeException("mediaItems");
- var file = new FileInfo(filePaths[0]);
+ var item = mediaItems[0];
- if (!file.Exists)
+ if (!item.Exists)
throw new ArgumentException("Err:File isn't exists.", "filePaths[0]");
- var xml = await this.mobypictureApi.UploadFileAsync(file, text)
+ var xml = await this.mobypictureApi.UploadFileAsync(item, text)
.ConfigureAwait(false);
var imageUrlElm = xml.XPathSelectElement("/rsp/media/mediaurl");
/// </summary>
/// <exception cref="WebApiException"/>
/// <exception cref="XmlException"/>
- public async Task<XDocument> UploadFileAsync(FileInfo file, string message)
+ public async Task<XDocument> UploadFileAsync(IMediaItem item, string message)
{
// 参照: http://developers.mobypicture.com/documentation/2-0/upload/
{"key", ApplicationSettings.MobypictureKey},
{"message", message},
};
- var paramFiles = new List<KeyValuePair<string, FileInfo>>
+ var paramFiles = new List<KeyValuePair<string, IMediaItem>>
{
- new KeyValuePair<string, FileInfo>("media", file),
+ new KeyValuePair<string, IMediaItem>("media", item),
};
var response = "";
return MaxFileSize;
}
- public async Task PostStatusAsync(string text, long? inReplyToStatusId, string[] filePaths)
+ public async Task PostStatusAsync(string text, long? inReplyToStatusId, IMediaItem[] mediaItems)
{
- if (filePaths.Length != 1)
- throw new ArgumentOutOfRangeException("filePaths");
+ if (mediaItems.Length != 1)
+ throw new ArgumentOutOfRangeException("mediaItems");
- var file = new FileInfo(filePaths[0]);
+ var item = mediaItems[0];
- if (!file.Exists)
+ if (!item.Exists)
throw new ArgumentException("Err:File isn't exists.", "filePaths[0]");
- var xml = await this.twippleApi.UploadFileAsync(file)
+ var xml = await this.twippleApi.UploadFileAsync(item)
.ConfigureAwait(false);
var imageUrlElm = xml.XPathSelectElement("/rsp/mediaurl");
/// </summary>
/// <exception cref="WebApiException"/>
/// <exception cref="XmlException"/>
- public async Task<XDocument> UploadFileAsync(FileInfo file)
+ public async Task<XDocument> UploadFileAsync(IMediaItem item)
{
// 参照: http://p.twipple.jp/wiki/API_Upload2/ja
{
{"upload_from", Application.ProductName},
};
- var paramFiles = new List<KeyValuePair<string, FileInfo>>
+ var paramFiles = new List<KeyValuePair<string, IMediaItem>>
{
- new KeyValuePair<string, FileInfo>("media", file),
+ new KeyValuePair<string, IMediaItem>("media", item),
};
var response = "";
return this.twitterConfig.PhotoSizeLimit;
}
- public async Task PostStatusAsync(string text, long? inReplyToStatusId, string[] filePaths)
+ public async Task PostStatusAsync(string text, long? inReplyToStatusId, IMediaItem[] mediaItems)
{
- if (filePaths == null || filePaths.Length == 0 || string.IsNullOrEmpty(filePaths[0]))
- throw new ArgumentException("Err:File isn't specified.", "filePaths");
+ if (mediaItems == null || mediaItems.Length == 0)
+ throw new ArgumentException("Err:Media isn't specified.", "mediaItems");
- var mediaFiles = new List<FileInfo>();
-
- foreach (var filePath in filePaths)
+ foreach (var item in mediaItems)
{
- if (string.IsNullOrEmpty(filePath)) continue;
-
- var mediaFile = new FileInfo(filePath);
-
- if (!mediaFile.Exists)
- throw new ArgumentException("Err:File isn't exists.", "filePaths");
+ if (item == null)
+ throw new ArgumentException("Err:Media isn't specified.", "mediaItems");
- mediaFiles.Add(mediaFile);
+ if (!item.Exists)
+ throw new ArgumentException("Err:File isn't exists.", "mediaItems");
}
await Task.Run(() =>
{
- var res = this.tw.PostStatusWithMultipleMedia(text, inReplyToStatusId, mediaFiles);
+ var res = this.tw.PostStatusWithMultipleMedia(text, inReplyToStatusId, mediaItems);
if (!string.IsNullOrEmpty(res))
throw new WebApiException(res);
})
return MaxFileSize;
}
- public async Task PostStatusAsync(string text, long? inReplyToStatusId, string[] filePaths)
+ public async Task PostStatusAsync(string text, long? inReplyToStatusId, IMediaItem[] mediaItems)
{
- if (filePaths.Length != 1)
- throw new ArgumentOutOfRangeException("filePaths");
+ if (mediaItems.Length != 1)
+ throw new ArgumentOutOfRangeException("mediaItems");
- var file = new FileInfo(filePaths[0]);
+ var item = mediaItems[0];
- if (!file.Exists)
+ if (!item.Exists)
throw new ArgumentException("Err:File isn't exists.", "filePaths[0]");
- var xml = await this.imglyApi.UploadFileAsync(file, text)
+ var xml = await this.imglyApi.UploadFileAsync(item, text)
.ConfigureAwait(false);
var imageUrlElm = xml.XPathSelectElement("/image/url");
/// </summary>
/// <exception cref="WebApiException"/>
/// <exception cref="XmlException"/>
- public async Task<XDocument> UploadFileAsync(FileInfo file, string message)
+ public async Task<XDocument> UploadFileAsync(IMediaItem item, string message)
{
// 参照: http://img.ly/api
{
{"message", message},
};
- var paramFiles = new List<KeyValuePair<string, FileInfo>>
+ var paramFiles = new List<KeyValuePair<string, IMediaItem>>
{
- new KeyValuePair<string, FileInfo>("media", file),
+ new KeyValuePair<string, IMediaItem>("media", item),
};
var response = "";
return MaxFileSize;
}
- public async Task PostStatusAsync(string text, long? inReplyToStatusId, string[] filePaths)
+ public async Task PostStatusAsync(string text, long? inReplyToStatusId, IMediaItem[] mediaItems)
{
- if (filePaths.Length != 1)
- throw new ArgumentOutOfRangeException("filePaths");
+ if (mediaItems.Length != 1)
+ throw new ArgumentOutOfRangeException("mediaItems");
- var file = new FileInfo(filePaths[0]);
+ var item = mediaItems[0];
- if (!file.Exists)
+ if (!item.Exists)
throw new ArgumentException("Err:File isn't exists.", "filePaths[0]");
- var xml = await this.yfrogApi.UploadFileAsync(file, text)
+ var xml = await this.yfrogApi.UploadFileAsync(item, text)
.ConfigureAwait(false);
var imageUrlElm = xml.XPathSelectElement("/rsp/mediaurl");
/// </summary>
/// <exception cref="WebApiException"/>
/// <exception cref="XmlException"/>
- public async Task<XDocument> UploadFileAsync(FileInfo file, string message)
+ public async Task<XDocument> UploadFileAsync(IMediaItem item, string message)
{
// 参照: http://twitter.yfrog.com/page/api#a1
{
{"key", ApplicationSettings.YfrogApiKey},
};
- var paramFiles = new List<KeyValuePair<string, FileInfo>>
+ var paramFiles = new List<KeyValuePair<string, IMediaItem>>
{
- new KeyValuePair<string, FileInfo>("media", file),
+ new KeyValuePair<string, IMediaItem>("media", item),
};
var response = "";
--- /dev/null
+// OpenTween - Client of Twitter
+// Copyright (c) 2015 spx (@5px)
+// 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.Drawing;
+using System.IO;
+using System.Linq;
+using System.Threading;
+
+namespace OpenTween
+{
+ public interface IMediaItem
+ {
+ /// <summary>
+ /// メディアへの絶対パス
+ /// </summary>
+ string Path { get; }
+
+ /// <summary>
+ /// メディア名
+ /// </summary>
+ string Name { get; }
+
+ /// <summary>
+ /// メディアの拡張子
+ /// </summary>
+ string Extension { get; }
+
+ /// <summary>
+ /// メディアが存在するかどうかを示す真偽値
+ /// </summary>
+ bool Exists { get; }
+
+ /// <summary>
+ /// メディアのサイズ(バイト単位)
+ /// </summary>
+ long Size { get; }
+
+ /// <summary>
+ /// 表示用の MemoryImage を作成する
+ /// </summary>
+ MemoryImage CreateImage();
+
+ /// <summary>
+ /// メディアの内容を Stream へ書き込む
+ /// </summary>
+ void CopyTo(Stream stream);
+ }
+
+ /// <summary>
+ /// ファイル用の MediaItem クラス
+ /// </summary>
+ public class FileMediaItem : IMediaItem
+ {
+ private FileInfo _fileInfo = null;
+
+ public FileMediaItem(string path)
+ {
+ this._fileInfo = new FileInfo(path);
+ }
+
+ public FileMediaItem(FileInfo fileInfo)
+ : this(fileInfo.FullName)
+ {
+ }
+
+ public virtual string Path
+ {
+ get { return this._fileInfo.FullName; }
+ }
+
+ public virtual string Name
+ {
+ get { return this._fileInfo.Name; }
+ }
+
+ public virtual string Extension
+ {
+ get { return this._fileInfo.Extension; }
+ }
+
+ public virtual bool Exists
+ {
+ get { return this._fileInfo.Exists; }
+ }
+
+ public virtual long Size
+ {
+ get { return this._fileInfo.Length; }
+ }
+
+ public virtual MemoryImage CreateImage()
+ {
+ using (var fs = this._fileInfo.OpenRead())
+ {
+ return MemoryImage.CopyFromStream(fs);
+ }
+ }
+
+ public virtual void CopyTo(Stream stream)
+ {
+ using (var fs = this._fileInfo.OpenRead())
+ {
+ fs.CopyTo(stream);
+ }
+ }
+
+ public FileInfo FileInfo
+ {
+ get { return this._fileInfo; }
+ }
+ }
+
+ /// <summary>
+ /// MemoryImage 用の MediaItem クラス
+ /// </summary>
+ /// <remarks>
+ /// 用途の関係上、メモリ使用量が大きくなるため、不要になればできるだけ破棄すること
+ /// </remarks>
+ public class MemoryImageMediaItem : IMediaItem, IDisposable
+ {
+ public static readonly string PathPrefix = "<>MemoryImage://";
+ private static int _fileNumber = 0;
+
+ private bool _disposed = false;
+
+ private string _path;
+ private MemoryImage _image;
+
+ public MemoryImageMediaItem(Image image)
+ {
+ if (image == null)
+ throw new ArgumentNullException("image");
+
+ // image から png 形式の MemoryImage を生成
+ using (var bitmap = new Bitmap(image))
+ {
+ this._image = MemoryImage.CopyFromBitmap(bitmap);
+ }
+
+ var num = Interlocked.Increment(ref _fileNumber);
+ this._path = PathPrefix + num + this._image.ImageFormatExt;
+ }
+
+ public virtual string Path
+ {
+ get { return this._path; }
+ }
+
+ public virtual string Name
+ {
+ get { return this._path.Substring(PathPrefix.Length); }
+ }
+
+ public virtual string Extension
+ {
+ get { return this._image.ImageFormatExt; }
+ }
+
+ public virtual bool Exists
+ {
+ get { return this._image != null; }
+ }
+
+ public virtual long Size
+ {
+ get { return this._image.Stream.Length; }
+ }
+
+ public virtual MemoryImage CreateImage()
+ {
+ return this._image.Clone();
+ }
+
+ public virtual void CopyTo(Stream stream)
+ {
+ this._image.Stream.Seek(0, SeekOrigin.Begin);
+ this._image.Stream.CopyTo(stream);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (this._disposed) return;
+
+ if (disposing)
+ {
+ this._image.Dispose();
+ }
+
+ this._disposed = true;
+ }
+
+ public void Dispose()
+ {
+ this.Dispose(true);
+
+ // 明示的にDisposeが呼ばれた場合はファイナライザを使用しない
+ GC.SuppressFinalize(this);
+ }
+
+ ~MemoryImageMediaItem()
+ {
+ this.Dispose(false);
+ }
+ }
+}
private class SelectedMedia
{
- public string Path { get; set; }
+ public IMediaItem Item { get; set; }
public MyCommon.UploadFileType Type { get; set; }
public string Text { get; set; }
- public SelectedMedia(string path, MyCommon.UploadFileType type, string text)
+ public SelectedMedia(IMediaItem item, MyCommon.UploadFileType type, string text)
{
- this.Path = path;
+ this.Item = item;
this.Type = type;
this.Text = text;
}
public SelectedMedia(string text)
- : this("", MyCommon.UploadFileType.Invalid, text)
+ : this(null, MyCommon.UploadFileType.Invalid, text)
{
}
public bool IsValid
{
- get { return this.Type != MyCommon.UploadFileType.Invalid; }
+ get
+ {
+ return this.Item != null && this.Type != MyCommon.UploadFileType.Invalid;
+ }
+ }
+
+ public string Path
+ {
+ get
+ {
+ return (this.Item != null) ? this.Item.Path : "";
+ }
}
public override string ToString()
/// <summary>
/// 投稿するファイルとその投稿先を選択するためのコントロールを表示する。
- /// D&Dをサポートする場合は引数にドロップされたファイル名を指定して呼ぶこと。
/// </summary>
- public void BeginSelection(string[] fileNames = null)
+ private void BeginSelection(IMediaItem[] items)
{
- if (fileNames != null && fileNames.Length > 0)
+ if (items == null || items.Length == 0)
{
- var serviceName = this.ServiceName;
- if (string.IsNullOrEmpty(serviceName)) return;
- var service = this.pictureService[serviceName];
+ BeginSelection();
+ return;
+ }
- var count = Math.Min(fileNames.Length, service.MaxMediaCount);
- if (!this.Visible || count > 1)
- {
- // 非表示時または複数のファイル指定は新規選択として扱う
- SetImagePageCombo();
+ var serviceName = this.ServiceName;
+ if (string.IsNullOrEmpty(serviceName)) return;
+ var service = this.pictureService[serviceName];
- if (this.BeginSelecting != null)
- this.BeginSelecting(this, EventArgs.Empty);
+ var count = Math.Min(items.Length, service.MaxMediaCount);
+ if (!this.Visible || count > 1)
+ {
+ // 非表示時または複数のファイル指定は新規選択として扱う
+ SetImagePageCombo();
- this.Visible = true;
- }
- this.Enabled = true;
+ if (this.BeginSelecting != null)
+ this.BeginSelecting(this, EventArgs.Empty);
- if (count == 1)
- {
- ImagefilePathText.Text = fileNames[0];
- ImageFromSelectedFile(false);
- }
- else
- {
- for (int i = 0; i < count; i++)
- {
- var index = ImagePageCombo.Items.Count - 1;
- if (index == 0) ImagefilePathText.Text = fileNames[i];
- ImageFromSelectedFile(index, fileNames[i], false);
- }
- }
+ this.Visible = true;
+ }
+ this.Enabled = true;
+
+ if (count == 1)
+ {
+ ImagefilePathText.Text = items[0].Path;
+ ImageFromSelectedFile(items[0], false);
}
else
{
- if (!this.Visible)
+ for (int i = 0; i < count; i++)
{
- if (this.BeginSelecting != null)
- this.BeginSelecting(this, EventArgs.Empty);
-
- this.Visible = true;
- this.Enabled = true;
- ImageFromSelectedFile(true);
- ImagefilePathText.Focus();
+ var index = ImagePageCombo.Items.Count - 1;
+ if (index == 0) ImagefilePathText.Text = items[i].Path;
+ ImageFromSelectedFile(index, items[i], false);
}
}
}
/// <summary>
+ /// 投稿するファイルとその投稿先を選択するためのコントロールを表示する(主にD&D用)。
+ /// </summary>
+ public void BeginSelection(string[] fileNames)
+ {
+ if (fileNames == null || fileNames.Length == 0)
+ {
+ BeginSelection();
+ return;
+ }
+
+ var items = fileNames.Select(x => CreateFileMediaItem(x, false)).OfType<IMediaItem>().ToArray();
+ BeginSelection(items);
+ }
+
+ /// <summary>
+ /// 投稿するファイルとその投稿先を選択するためのコントロールを表示する。
+ /// </summary>
+ public void BeginSelection(Image image)
+ {
+ if (image == null)
+ {
+ BeginSelection();
+ return;
+ }
+
+ var items = new [] { CreateMemoryImageMediaItem(image, false) }.OfType<IMediaItem>().ToArray();
+ BeginSelection(items);
+ }
+
+ /// <summary>
+ /// 投稿するファイルとその投稿先を選択するためのコントロールを表示する。
+ /// </summary>
+ public void BeginSelection()
+ {
+ if (!this.Visible)
+ {
+ if (this.BeginSelecting != null)
+ this.BeginSelecting(this, EventArgs.Empty);
+
+ this.Visible = true;
+ this.Enabled = true;
+
+ var media = (SelectedMedia)ImagePageCombo.SelectedItem;
+ ImageFromSelectedFile(media.Item, true);
+ ImagefilePathText.Focus();
+ }
+ }
+
+ /// <summary>
/// 選択処理を終了してコントロールを隠す。
/// </summary>
public void EndSelection()
}
/// <summary>
- /// é\81¸æ\8a\9eã\81\95ã\82\8cã\81\9fæ\8a\95稿å\85\88å\90\8dã\81¨æ\8a\95稿ã\83\95ã\82¡ã\82¤ã\83«å\90\8dã\82\92å\8f\96å¾\97ã\81\99ã\82\8b。
+ /// é\81¸æ\8a\9eã\81\95ã\82\8cã\81\9fæ\8a\95稿å\85\88å\90\8dã\81¨æ\8a\95稿ã\81\99ã\82\8b MediaItem ã\82\92å\8f\96å¾\97ã\81\99ã\82\8bã\80\82MediaItem ã\81¯ä¸\8dè¦\81ã\81«ã\81ªã\81£ã\81\9fã\82\89å\91¼ã\81³å\87ºã\81\97å\81´ã\81«ã\81¦ç ´æ£\84ã\81\99ã\82\8bã\81\93ã\81¨。
/// </summary>
- public bool TryGetSelectedMedia(out string imageService, out string[] imagePaths)
+ public bool TryGetSelectedMedia(out string imageService, out IMediaItem[] mediaItems)
{
- var validPaths = ImagePageCombo.Items.Cast<SelectedMedia>()
- .Where(x => x.IsValid).Select(x => x.Path).ToArray();
+ var validItems = ImagePageCombo.Items.Cast<SelectedMedia>()
+ .Where(x => x.IsValid).Select(x => x.Item).OfType<IMediaItem>().ToArray();
- if (validPaths.Length > 0 &&
+ if (validItems.Length > 0 &&
ImageServiceCombo.SelectedIndex > -1)
{
var serviceName = this.ServiceName;
- if (MessageBox.Show(string.Format(Properties.Resources.PostPictureConfirm1, serviceName, validPaths.Length),
+ if (MessageBox.Show(string.Format(Properties.Resources.PostPictureConfirm1, serviceName, validItems.Length),
Properties.Resources.PostPictureConfirm2,
MessageBoxButtons.OKCancel,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1)
== DialogResult.OK)
{
+ //収集した MediaItem が破棄されないように、予め null を代入しておく
+ foreach (SelectedMedia media in ImagePageCombo.Items)
+ {
+ if (media != null) media.Item = null;
+ }
+
imageService = serviceName;
- imagePaths = validPaths;
+ mediaItems = validItems;
EndSelection();
SetImagePageCombo();
return true;
EndSelection();
imageService = null;
- imagePaths = null;
+ mediaItems = null;
return false;
}
+ private IMediaItem CreateMemoryImageMediaItem(Image image, bool noMsgBox)
+ {
+ if (image == null) return null;
+
+ try
+ {
+ return new MemoryImageMediaItem(image);
+ }
+ catch
+ {
+ if (!noMsgBox) MessageBox.Show("Unable to create MemoryImage.");
+ return null;
+ }
+ }
+
+ private IMediaItem CreateFileMediaItem(string path, bool noMsgBox)
+ {
+ if (string.IsNullOrEmpty(path)) return null;
+
+ try
+ {
+ return new FileMediaItem(path);
+ }
+ catch
+ {
+ if (!noMsgBox) MessageBox.Show("Invalid file path: " + path);
+ return null;
+ }
+ }
+
+ private void ValidateNewFileMediaItem(string path, bool noMsgBox)
+ {
+ var media = (SelectedMedia)ImagePageCombo.SelectedItem;
+ var item = media.Item;
+
+ if (path != media.Path)
+ {
+ DisposeMediaItem(media.Item);
+ media.Item = null;
+
+ item = CreateFileMediaItem(path, noMsgBox);
+ }
+
+ ImagefilePathText.Text = path;
+ ImageFromSelectedFile(item, noMsgBox);
+ }
+
+ private void DisposeMediaItem(IMediaItem item)
+ {
+ if (item != null)
+ {
+ var disposableItem = item as IDisposable;
+ if (disposableItem != null) disposableItem.Dispose();
+ }
+ }
+
private void FilePickButton_Click(object sender, EventArgs e)
{
if (FilePickDialog == null || string.IsNullOrEmpty(this.ServiceName)) return;
this.FilePickDialogClosed(this, EventArgs.Empty);
}
- ImagefilePathText.Text = FilePickDialog.FileName;
- ImageFromSelectedFile(false);
+ ValidateNewFileMediaItem(FilePickDialog.FileName, false);
}
private void ImagefilePathText_Validating(object sender, CancelEventArgs e)
return;
}
- ImageFromSelectedFile(false);
+ ValidateNewFileMediaItem(ImagefilePathText.Text.Trim(), false);
}
- private void ImageFromSelectedFile(bool suppressMsgBox)
+ private void ImageFromSelectedFile(IMediaItem item, bool noMsgBox)
{
- ImagefilePathText.Text = ImagefilePathText.Text.Trim();
- ImageFromSelectedFile(-1, ImagefilePathText.Text, suppressMsgBox);
+ ImageFromSelectedFile(-1, item, noMsgBox);
}
- private void ImageFromSelectedFile(int index, string fileName, bool suppressMsgBox)
+ private void ImageFromSelectedFile(int index, IMediaItem item, bool noMsgBox)
{
- var serviceName = this.ServiceName;
- if (string.IsNullOrEmpty(serviceName)) return;
+ var valid = false;
- var selectedIndex = ImagePageCombo.SelectedIndex;
- if (index < 0) index = selectedIndex;
+ try
+ {
+ var serviceName = this.ServiceName;
+ if (string.IsNullOrEmpty(serviceName)) return;
- if (index >= ImagePageCombo.Items.Count)
- throw new ArgumentOutOfRangeException("index");
+ var selectedIndex = ImagePageCombo.SelectedIndex;
+ if (index < 0) index = selectedIndex;
- var imageService = this.pictureService[serviceName];
- var isSelectedPage = (index == selectedIndex);
+ if (index >= ImagePageCombo.Items.Count)
+ throw new ArgumentOutOfRangeException("index");
- if (isSelectedPage)
- this.ClearImageSelectedPicture();
+ var imageService = this.pictureService[serviceName];
+ var isSelectedPage = (index == selectedIndex);
- if (string.IsNullOrEmpty(fileName))
- {
- ClearImagePage(index);
- return;
- }
+ if (isSelectedPage)
+ this.ClearImageSelectedPicture();
- try
- {
- FileInfo fl = new FileInfo(fileName);
- string ext = fl.Extension;
+ if (item == null || string.IsNullOrEmpty(item.Path)) return;
- if (!imageService.CheckFileExtension(ext))
+ try
{
- //画像以外の形式
- ClearImagePage(index);
- if (!suppressMsgBox)
+ var ext = item.Extension;
+ var size = item.Size;
+
+ if (!imageService.CheckFileExtension(ext))
{
- MessageBox.Show(
- string.Format(Properties.Resources.PostPictureWarn3, serviceName, MakeAvailableServiceText(ext, fl.Length), ext, fl.Name),
- Properties.Resources.PostPictureWarn4,
- MessageBoxButtons.OK,
- MessageBoxIcon.Warning);
+ //画像以外の形式
+ if (!noMsgBox)
+ {
+ MessageBox.Show(
+ string.Format(Properties.Resources.PostPictureWarn3, serviceName, MakeAvailableServiceText(ext, size), ext, item.Name),
+ Properties.Resources.PostPictureWarn4,
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Warning);
+ }
+ return;
}
- return;
- }
- if (!imageService.CheckFileSize(ext, fl.Length))
- {
- // ファイルサイズが大きすぎる
- ClearImagePage(index);
- if (!suppressMsgBox)
+ if (!imageService.CheckFileSize(ext, size))
{
- MessageBox.Show(
- string.Format(Properties.Resources.PostPictureWarn5, serviceName, MakeAvailableServiceText(ext, fl.Length), fl.Name),
- Properties.Resources.PostPictureWarn4,
- MessageBoxButtons.OK,
- MessageBoxIcon.Warning);
+ // ファイルサイズが大きすぎる
+ if (!noMsgBox)
+ {
+ MessageBox.Show(
+ string.Format(Properties.Resources.PostPictureWarn5, serviceName, MakeAvailableServiceText(ext, size), item.Name),
+ Properties.Resources.PostPictureWarn4,
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Warning);
+ }
+ return;
}
- return;
- }
- try
- {
- using (var fs = File.OpenRead(fileName))
+ if (item is MemoryImageMediaItem)
{
- var image = MemoryImage.CopyFromStream(fs);
if (isSelectedPage)
- ImageSelectedPicture.Image = image;
- else
- image.Dispose(); //画像チェック後は使わないので破棄する
+ ImageSelectedPicture.Image = item.CreateImage();
+ SetImagePage(index, item, MyCommon.UploadFileType.Picture);
}
- SetImagePage(index, fileName, MyCommon.UploadFileType.Picture);
+ else
+ {
+ try
+ {
+ var image = item.CreateImage();
+ if (isSelectedPage)
+ ImageSelectedPicture.Image = image;
+ else
+ image.Dispose(); //画像チェック後は使わないので破棄する
+ SetImagePage(index, item, MyCommon.UploadFileType.Picture);
+ }
+ catch (InvalidImageException)
+ {
+ SetImagePage(index, item, MyCommon.UploadFileType.MultiMedia);
+ }
+ }
+
+ valid = true; //正常終了
}
- catch (InvalidImageException)
+ catch (FileNotFoundException)
{
- SetImagePage(index, fileName, MyCommon.UploadFileType.MultiMedia);
+ if (!noMsgBox) MessageBox.Show("File not found.");
+ }
+ catch (Exception)
+ {
+ if (!noMsgBox) MessageBox.Show("The type of this file is not image.");
}
}
- catch (FileNotFoundException)
- {
- ClearImagePage(index);
- if (!suppressMsgBox) MessageBox.Show("File not found.");
- }
- catch (Exception)
+ finally
{
- ClearImagePage(index);
- if (!suppressMsgBox) MessageBox.Show("The type of this file is not image.");
+ if (!valid)
+ {
+ ClearImagePage(index);
+ DisposeMediaItem(item);
+ }
}
}
else
{
ImagePageCombo.Enabled = false;
+ var valid = false;
try
{
- FileInfo fi = new FileInfo(ImagefilePathText.Text.Trim());
- string ext = fi.Extension;
- var imageService = this.pictureService[serviceName];
- if (!imageService.CheckFileExtension(ext) ||
- !imageService.CheckFileSize(ext, fi.Length))
+ var item = ((SelectedMedia)ImagePageCombo.Items[0]).Item;
+ if (item != null)
{
- ClearImageSelectedPicture();
- ClearSelectedImagePage();
+ var ext = item.Extension;
+ var imageService = this.pictureService[serviceName];
+ if (imageService.CheckFileExtension(ext) &&
+ imageService.CheckFileSize(ext, item.Size))
+ {
+ valid = true;
+ }
}
}
- catch (Exception)
+ catch
+ {
+ }
+ finally
{
- ClearImageSelectedPicture();
- ClearSelectedImagePage();
+ if (!valid)
+ {
+ ClearImageSelectedPicture();
+ ClearSelectedImagePage();
+ }
}
}
}
using (ControlTransaction.Update(ImagePageCombo))
{
ImagePageCombo.Enabled = false;
- ImagePageCombo.Items.Clear();
- if (media != null)
- {
- ImagePageCombo.Items.Add(media);
- ImagefilePathText.Text = media.Path;
- }
- else
+
+ foreach (SelectedMedia oldMedia in ImagePageCombo.Items)
{
- ImagePageCombo.Items.Add(new SelectedMedia("1"));
- ImagefilePathText.Text = "";
+ if (oldMedia == null || oldMedia == media) continue;
+ DisposeMediaItem(oldMedia.Item);
}
+ ImagePageCombo.Items.Clear();
+
+ if (media == null)
+ media = new SelectedMedia("1");
+
+ ImagePageCombo.Items.Add(media);
+ ImagefilePathText.Text = media.Path;
+
ImagePageCombo.SelectedIndex = 0;
}
}
}
}
- private void SetSelectedImagePage(string path, MyCommon.UploadFileType type)
+ private void SetSelectedImagePage(IMediaItem item, MyCommon.UploadFileType type)
{
- SetImagePage(-1, path, type);
+ SetImagePage(-1, item, type);
}
- private void SetImagePage(int index, string path, MyCommon.UploadFileType type)
+ private void SetImagePage(int index, IMediaItem item, MyCommon.UploadFileType type)
{
var selectedIndex = ImagePageCombo.SelectedIndex;
if (index < 0) index = selectedIndex;
- var item = (SelectedMedia)ImagePageCombo.Items[index];
- item.Path = path;
- item.Type = type;
+ var media = (SelectedMedia)ImagePageCombo.Items[index];
+ if (media.Item != item)
+ {
+ DisposeMediaItem(media.Item);
+ media.Item = item;
+ }
+ media.Type = type;
AddNewImagePage(index);
}
var selectedIndex = ImagePageCombo.SelectedIndex;
if (index < 0) index = selectedIndex;
- var item = (SelectedMedia)ImagePageCombo.Items[index];
- item.Path = "";
- item.Type = MyCommon.UploadFileType.Invalid;
+ var media = (SelectedMedia)ImagePageCombo.Items[index];
+ DisposeMediaItem(media.Item);
+ media.Item = null;
+ media.Type = MyCommon.UploadFileType.Invalid;
if (index == selectedIndex) ImagefilePathText.Text = "";
}
private void ValidateSelectedImagePage()
{
var idx = ImagePageCombo.SelectedIndex;
- var item = (SelectedMedia)ImagePageCombo.Items[idx];
+ var media = (SelectedMedia)ImagePageCombo.Items[idx];
ImageServiceCombo.Enabled = (idx == 0); // idx == 0 以外では投稿先サービスを選べないようにする
- ImagefilePathText.Text = item.Path;
- ImageFromSelectedFile(true);
+ ImagefilePathText.Text = media.Path;
+ ImageFromSelectedFile(media.Item, true);
}
private void ImagePageCombo_SelectedIndexChanged(object sender, EventArgs e)
<Compile Include="FilterDialog.Designer.cs">
<DependentUpon>FilterDialog.cs</DependentUpon>
</Compile>
+ <Compile Include="MediaItem.cs" />
<Compile Include="WaitingDialog.cs">
<SubType>Form</SubType>
</Compile>
public long? inReplyToId = null;
public string inReplyToName = null;
public string imageService = ""; //画像投稿サービス名
- public string[] imagePath = null;
+ public IMediaItem[] mediaItems = null;
public PostingStatus()
{
}
if (ImageSelector.Visible)
{
//画像投稿
- if (!ImageSelector.TryGetSelectedMedia(out status.imageService, out status.imagePath))
+ if (!ImageSelector.TryGetSelectedMedia(out status.imageService, out status.mediaItems))
return;
}
{
await Task.Run(async () =>
{
- if (status.imagePath == null || status.imagePath.Length == 0 || string.IsNullOrEmpty(status.imagePath[0]))
+ if (status.mediaItems == null || status.mediaItems.Length == 0)
{
var err = this.tw.PostStatus(status.status, status.inReplyToId);
if (!string.IsNullOrEmpty(err))
else
{
var service = ImageSelector.GetService(status.imageService);
- await service.PostStatusAsync(status.status, status.inReplyToId, status.imagePath)
+ await service.PostStatusAsync(status.status, status.inReplyToId, status.mediaItems)
.ConfigureAwait(false);
}
});
p.Report(errMsg);
this._myStatusError = true;
}
+ finally
+ {
+ // 使い終わった MediaItem は破棄する
+ if (status.mediaItems != null)
+ {
+ foreach (var disposableItem in status.mediaItems.OfType<IDisposable>())
+ {
+ disposableItem.Dispose();
+ }
+ }
+ }
if (ct.IsCancellationRequested)
return;
// Webページを開く動作
OpenURLMenuItem_Click(null, null);
return true;
- case Keys.V:
- if( Focused == FocusedControl.StatusText ) {
- ProcClipboardFromStatusTextWhenCtrlPlusV();
- return true;
- }
- break;
}
//フォーカスList
if (Focused == FocusedControl.ListTab)
case Keys.A:
StatusText.SelectAll();
return true;
+ case Keys.V:
+ ProcClipboardFromStatusTextWhenCtrlPlusV();
+ return true;
case Keys.Up:
case Keys.Down:
if (!string.IsNullOrWhiteSpace(StatusText.Text))
/// <summary>
/// StatusTextでCtrl+Vが押下された時の処理
/// </summary>
- private void ProcClipboardFromStatusTextWhenCtrlPlusV() {
- if( Clipboard.ContainsText() ) {
+ private void ProcClipboardFromStatusTextWhenCtrlPlusV()
+ {
+ if (Clipboard.ContainsText())
+ {
// clipboardにテキストがある場合は貼り付け処理
- this.StatusText.Paste( Clipboard.GetText() );
- } else if( Clipboard.ContainsImage() ) {
+ this.StatusText.Paste(Clipboard.GetText());
+ }
+ else if (Clipboard.ContainsImage())
+ {
// 画像があるので投稿処理を行う
// clipboardから画像を取得
- var image = Clipboard.GetImage();
- // 一時的に保存するためのパスを取得し、一旦保存を行う(png)
- var path = string.Format( "{0}.png", Path.GetTempFileName() );
- using( var fs = new FileStream( path, FileMode.Create ) ) {
- image.Save( fs, System.Drawing.Imaging.ImageFormat.Png );
- }
- // 保存したパスをImageSelectorに投げる
- this.ImageSelector.BeginSelection( new string[] { path } );
+ using (var image = Clipboard.GetImage())
+ {
+ this.ImageSelector.BeginSelection(image);
+ }
}
}
#endregion
return "";
}
- public string PostStatusWithMedia(string postStr, long? reply_to, FileInfo mediaFile)
+ public string PostStatusWithMedia(string postStr, long? reply_to, IMediaItem item)
{
if (MyCommon._endingFlag) return "";
var content = "";
try
{
- res = twCon.UpdateStatusWithMedia(postStr, reply_to, mediaFile, ref content);
+ res = twCon.UpdateStatusWithMedia(postStr, reply_to, item, ref content);
}
catch(Exception ex)
{
return "";
}
- public string PostStatusWithMultipleMedia(string postStr, long? reply_to, List<FileInfo> mediaFiles)
+ public string PostStatusWithMultipleMedia(string postStr, long? reply_to, IMediaItem[] mediaItems)
{
if (MyCommon._endingFlag) return "";
var mediaIds = new List<long>();
- foreach (var mediaFile in mediaFiles)
+ foreach (var item in mediaItems)
{
long? mediaId = null;
- var err = UploadMedia(mediaFile, ref mediaId);
+ var err = UploadMedia(item, ref mediaId);
if (!mediaId.HasValue || !string.IsNullOrEmpty(err)) return err;
mediaIds.Add(mediaId.Value);
}
return PostStatus(postStr, reply_to, mediaIds);
}
- public string UploadMedia(FileInfo mediaFile, ref long? mediaId)
+ public string UploadMedia(IMediaItem item, ref long? mediaId)
{
if (MyCommon._endingFlag) return "";
var content = "";
try
{
- res = twCon.UploadMedia(mediaFile, ref content);
+ res = twCon.UploadMedia(item, ref content);
}
catch (Exception ex)
{