--- /dev/null
+// OpenTween - Client of Twitter
+// Copyright (c) 2017 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.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using System.Web;
+using Xunit;
+
+namespace OpenTween.Api
+{
+ public class BitlyApiTest
+ {
+ [Fact]
+ public async Task ShortenAsync_OAuth2Test()
+ {
+ using (var mockHandler = new HttpMessageHandlerMock())
+ using (var http = new HttpClient(mockHandler))
+ {
+ var bitly = new BitlyApi(http);
+
+ mockHandler.Enqueue(x =>
+ {
+ Assert.Equal(HttpMethod.Get, x.Method);
+ Assert.Equal("https://api-ssl.bitly.com/v3/shorten",
+ x.RequestUri.GetLeftPart(UriPartial.Path));
+
+ var query = HttpUtility.ParseQueryString(x.RequestUri.Query);
+
+ Assert.Equal("http://www.example.com/", query["longUrl"]);
+ Assert.Equal("bit.ly", query["domain"]);
+ Assert.Equal("hogehoge", query["access_token"]);
+
+ return new HttpResponseMessage(HttpStatusCode.OK)
+ {
+ Content = new StringContent("http://bit.ly/foo"),
+ };
+ });
+
+ bitly.EndUserAccessToken = "hogehoge";
+
+ var result = await bitly.ShortenAsync(new Uri("http://www.example.com/"), "bit.ly")
+ .ConfigureAwait(false);
+ Assert.Equal("http://bit.ly/foo", result.OriginalString);
+
+ Assert.Equal(0, mockHandler.QueueCount);
+ }
+ }
+
+ [Fact]
+ public async Task ShortenAsync_LegacyApiKeyTest()
+ {
+ using (var mockHandler = new HttpMessageHandlerMock())
+ using (var http = new HttpClient(mockHandler))
+ {
+ var bitly = new BitlyApi(http);
+
+ mockHandler.Enqueue(x =>
+ {
+ Assert.Equal(HttpMethod.Get, x.Method);
+ Assert.Equal("https://api-ssl.bitly.com/v3/shorten",
+ x.RequestUri.GetLeftPart(UriPartial.Path));
+
+ var query = HttpUtility.ParseQueryString(x.RequestUri.Query);
+
+ Assert.Equal("http://www.example.com/", query["longUrl"]);
+ Assert.Equal("bit.ly", query["domain"]);
+ Assert.Equal("username", query["login"]);
+ Assert.Equal("hogehoge", query["apiKey"]);
+
+ return new HttpResponseMessage(HttpStatusCode.OK)
+ {
+ Content = new StringContent("http://bit.ly/foo"),
+ };
+ });
+
+ bitly.EndUserLoginName = "username";
+ bitly.EndUserApiKey = "hogehoge";
+
+ var result = await bitly.ShortenAsync(new Uri("http://www.example.com/"), "bit.ly")
+ .ConfigureAwait(false);
+ Assert.Equal("http://bit.ly/foo", result.OriginalString);
+
+ Assert.Equal(0, mockHandler.QueueCount);
+ }
+ }
+
+ [Fact]
+ public async Task GetAccessTokenAsync_Test()
+ {
+ using (var mockHandler = new HttpMessageHandlerMock())
+ using (var http = new HttpClient(mockHandler))
+ {
+ var bitly = new BitlyApi(http);
+
+ mockHandler.Enqueue(async x =>
+ {
+ Assert.Equal(HttpMethod.Post, x.Method);
+ Assert.Equal("https://api-ssl.bitly.com/oauth/access_token",
+ x.RequestUri.GetLeftPart(UriPartial.Path));
+
+ Assert.Equal("Basic", x.Headers.Authorization.Scheme);
+ Assert.Equal(ApplicationSettings.BitlyClientId + ":" + ApplicationSettings.BitlyClientSecret,
+ Encoding.UTF8.GetString(Convert.FromBase64String(x.Headers.Authorization.Parameter)));
+
+ var body = await x.Content.ReadAsStringAsync()
+ .ConfigureAwait(false);
+ var query = HttpUtility.ParseQueryString(body);
+
+ Assert.Equal("password", query["grant_type"]);
+ Assert.Equal("hogehoge", query["username"]);
+ Assert.Equal("tetete", query["password"]);
+
+ return new HttpResponseMessage(HttpStatusCode.OK)
+ {
+ Content = new StringContent("{\"access_token\": \"abcdefg\"}"),
+ };
+ });
+
+ var result = await bitly.GetAccessTokenAsync("hogehoge", "tetete")
+ .ConfigureAwait(false);
+ Assert.Equal("abcdefg", result);
+
+ Assert.Equal(0, mockHandler.QueueCount);
+ }
+ }
+
+ [Fact]
+ public async Task GetAccessTokenAsync_ErrorResponseTest()
+ {
+ using (var mockHandler = new HttpMessageHandlerMock())
+ using (var http = new HttpClient(mockHandler))
+ {
+ var bitly = new BitlyApi(http);
+
+ mockHandler.Enqueue(x =>
+ {
+ return new HttpResponseMessage(HttpStatusCode.OK)
+ {
+ Content = new StringContent("{\"status_code\": \"500\", \"status_txt\": \"MISSING_ARG_USERNAME\"}"),
+ };
+ });
+
+ await Assert.ThrowsAsync<WebApiException>(() => bitly.GetAccessTokenAsync("hogehoge", "tetete"))
+ .ConfigureAwait(false);
+
+ Assert.Equal(0, mockHandler.QueueCount);
+ }
+ }
+ }
+}
<ItemGroup>
<Compile Include="AnyOrderComparer.cs" />
<Compile Include="Api\ApiLimitTest.cs" />
+ <Compile Include="Api\BitlyApiTest.cs" />
<Compile Include="Api\MicrosoftTranslatorApiTest.cs" />
<Compile Include="Api\TwitterApiStatusTest.cs" />
<Compile Include="Api\TwitterApiTest.cs" />
--- /dev/null
+// OpenTween - Client of Twitter
+// Copyright (c) 2017 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.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Runtime.Serialization.Json;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using System.Xml;
+using System.Xml.Linq;
+using OpenTween.Connection;
+
+namespace OpenTween.Api
+{
+ public class BitlyApi
+ {
+ public static readonly Uri ApiBase = new Uri("https://api-ssl.bitly.com/");
+
+ public string EndUserAccessToken { get; set; }
+
+ public string EndUserLoginName { get; set; }
+ public string EndUserApiKey { get; set; }
+
+ private HttpClient http => this.localHttpClient ?? Networking.Http;
+ private readonly HttpClient localHttpClient;
+
+ public BitlyApi()
+ : this(null)
+ {
+ }
+
+ public BitlyApi(HttpClient http)
+ {
+ this.localHttpClient = http;
+ }
+
+ public async Task<Uri> ShortenAsync(Uri srcUri, string domain = null)
+ {
+ var query = new Dictionary<string, string>
+ {
+ ["format"] = "txt",
+ ["longUrl"] = srcUri.OriginalString,
+ };
+
+ if (!string.IsNullOrEmpty(domain))
+ query["domain"] = domain;
+
+ var uri = new Uri("/v3/shorten", UriKind.Relative);
+ var responseText = await this.GetAsync(uri, query).ConfigureAwait(false);
+
+ if (!Regex.IsMatch(responseText, @"^https?://"))
+ throw new WebApiException("Failed to create URL.", responseText);
+
+ return new Uri(responseText.TrimEnd());
+ }
+
+ public async Task<string> GetAsync(Uri endpoint, IEnumerable<KeyValuePair<string, string>> param)
+ {
+ var paramWithToken = param.Concat(this.CreateAccessTokenParams());
+
+ var requestUri = new Uri(new Uri(ApiBase, endpoint), "?" + MyCommon.BuildQueryString(paramWithToken));
+
+ using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri))
+ using (var response = await this.http.SendAsync(request).ConfigureAwait(false))
+ {
+ return await response.Content.ReadAsStringAsync()
+ .ConfigureAwait(false);
+ }
+ }
+
+ public async Task<string> GetAccessTokenAsync(string username, string password)
+ {
+ var param = new Dictionary<string, string>
+ {
+ ["grant_type"] = "password",
+ ["username"] = username,
+ ["password"] = password,
+ };
+
+ var endpoint = new Uri(ApiBase, "/oauth/access_token");
+
+ using (var request = new HttpRequestMessage(HttpMethod.Post, endpoint))
+ using (var postContent = new FormUrlEncodedContent(param))
+ {
+ var authzParam = ApplicationSettings.BitlyClientId + ":" + ApplicationSettings.BitlyClientSecret;
+ request.Headers.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes(authzParam)));
+
+ request.Content = postContent;
+
+ using (var response = await this.http.SendAsync(request).ConfigureAwait(false))
+ {
+ var responseBytes = await response.Content.ReadAsByteArrayAsync()
+ .ConfigureAwait(false);
+
+ return this.ParseOAuthCredential(responseBytes);
+ }
+ }
+ }
+
+ private string ParseOAuthCredential(byte[] responseBytes)
+ {
+ using (var jsonReader = JsonReaderWriterFactory.CreateJsonReader(responseBytes, XmlDictionaryReaderQuotas.Max))
+ {
+ var xElm = XElement.Load(jsonReader);
+
+ var statusCode = xElm.Element("status_code")?.Value ?? "200";
+ if (statusCode != "200")
+ {
+ var statusText = xElm.Element("status_txt")?.Value;
+ throw new WebApiException(statusText ?? $"status_code = {statusCode}");
+ }
+
+ var accessToken = xElm.Element("access_token")?.Value;
+ if (accessToken == null)
+ throw new WebApiException("Property `access_token` required");
+
+ return accessToken;
+ }
+ }
+
+ private IEnumerable<KeyValuePair<string, string>> CreateAccessTokenParams()
+ {
+ if (string.IsNullOrEmpty(this.EndUserAccessToken))
+ {
+ return new[]
+ {
+ new KeyValuePair<string, string>("login", this.EndUserLoginName),
+ new KeyValuePair<string, string>("apiKey", this.EndUserApiKey),
+ };
+ }
+
+ return new[]
+ {
+ new KeyValuePair<string, string>("access_token", this.EndUserAccessToken),
+ };
+ }
+ }
+}
this.Save.Name = "Save";
this.ToolTip1.SetToolTip(this.Save, resources.GetString("Save.ToolTip"));
this.Save.UseVisualStyleBackColor = true;
- this.Save.Click += new System.EventHandler(this.Save_Click);
//
// Cancel
//
this.Cancel.Name = "Cancel";
this.ToolTip1.SetToolTip(this.Cancel, resources.GetString("Cancel.ToolTip"));
this.Cancel.UseVisualStyleBackColor = true;
- this.Cancel.Click += new System.EventHandler(this.Cancel_Click);
//
// ColorDialog1
//
internal Twitter tw;
internal TwitterApi twitterApi;
- private bool _ValidationError = false;
-
public AppendSettingDialog()
{
this.InitializeComponent();
}
}
- private void Save_Click(object sender, EventArgs e)
- {
- if (MyCommon.IsNetworkAvailable() &&
- (this.ShortUrlPanel.ComboBoxAutoShortUrlFirst.SelectedIndex == (int)MyCommon.UrlConverter.Bitly || this.ShortUrlPanel.ComboBoxAutoShortUrlFirst.SelectedIndex == (int)MyCommon.UrlConverter.Jmp))
- {
- // bit.ly 短縮機能実装のプライバシー問題の暫定対応
- // bit.ly 使用時はログインIDとAPIキーの指定を必須とする
- // 参照: http://sourceforge.jp/projects/opentween/lists/archive/dev/2012-January/000020.html
- if (string.IsNullOrEmpty(this.ShortUrlPanel.TextBitlyId.Text) || string.IsNullOrEmpty(this.ShortUrlPanel.TextBitlyPw.Text))
- {
- MessageBox.Show("bit.ly のログイン名とAPIキーの指定は必須項目です。", Application.ProductName);
- _ValidationError = true;
- TreeViewSetting.SelectedNode = TreeViewSetting.Nodes["ConnectionNode"].Nodes["ShortUrlNode"]; // 動作タブを選択
- TreeViewSetting.Select();
- this.ShortUrlPanel.TextBitlyId.Focus();
- return;
- }
-
- if (!BitlyValidation(this.ShortUrlPanel.TextBitlyId.Text, this.ShortUrlPanel.TextBitlyPw.Text).Result)
- {
- MessageBox.Show(Properties.Resources.SettingSave_ClickText1);
- _ValidationError = true;
- TreeViewSetting.SelectedNode = TreeViewSetting.Nodes["ConnectionNode"].Nodes["ShortUrlNode"]; // 動作タブを選択
- TreeViewSetting.Select();
- this.ShortUrlPanel.TextBitlyId.Focus();
- return;
- }
- else
- {
- _ValidationError = false;
- }
- }
- else
- {
- _ValidationError = false;
- }
- }
-
private void Setting_FormClosing(object sender, FormClosingEventArgs e)
{
if (MyCommon._endingFlag) return;
e.Cancel = true;
}
}
- if (_ValidationError)
- {
- e.Cancel = true;
- }
if (e.Cancel == false && TreeViewSetting.SelectedNode != null)
{
var curPanel = (SettingPanelBase)TreeViewSetting.SelectedNode.Tag;
this.GetPeriodPanel.LabelUserStreamActive.Visible = tw.UserStreamActive;
}
- private async Task<bool> BitlyValidation(string id, string apikey)
- {
- if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(apikey))
- {
- return false;
- }
-
- try
- {
- var requestUri = new Uri("http://api.bit.ly/v3/validate");
- var param = new Dictionary<string, string>
- {
- ["login"] = ApplicationSettings.BitlyLoginId,
- ["apiKey"] = ApplicationSettings.BitlyApiKey,
- ["x_login"] = id,
- ["x_apiKey"] = apikey,
- ["format"] = "txt",
- };
-
- using (var postContent = new FormUrlEncodedContent(param))
- using (var response = await Networking.Http.PostAsync(requestUri, postContent).ConfigureAwait(false))
- {
- var responseText = await response.Content.ReadAsStringAsync()
- .ConfigureAwait(false);
-
- return responseText.TrimEnd() == "1";
- }
- }
- catch (OperationCanceledException) { }
- catch (HttpRequestException) { }
-
- return false;
- }
-
- private void Cancel_Click(object sender, EventArgs e)
- {
- _ValidationError = false;
- }
-
private void OpenUrl(string url)
{
string myPath = url;
//=====================================================================
// bit.ly
- // https://bitly.com/a/account から取得できます。
+ // https://bitly.com/a/oauth_apps から取得できます。
/// <summary>
- /// bit.ly ログイン名
+ /// bit.ly Client ID
/// </summary>
- public const string BitlyLoginId = "opentween";
+ public const string BitlyClientId = "ddab8ec50f4459c315cbde9d923cf490923b6d2e";
/// <summary>
- /// bit.ly APIキー
+ /// bit.ly Client Secret
/// </summary>
- public const string BitlyApiKey = "R_76319a25e2420b8d2c42e812fe177d8b";
+ public const string BitlyClientSecret = "485c9d03dd264f8eeb4fc65d38e2762c4420cee7";
//=====================================================================
// TINAMI
--- /dev/null
+namespace OpenTween
+{
+ partial class LoginDialog
+ {
+ /// <summary>
+ /// Required designer variable.
+ /// </summary>
+ private System.ComponentModel.IContainer components = null;
+
+ /// <summary>
+ /// Clean up any resources being used.
+ /// </summary>
+ /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ /// <summary>
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ /// </summary>
+ private void InitializeComponent()
+ {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(LoginDialog));
+ this.label1 = new System.Windows.Forms.Label();
+ this.textboxLoginName = new System.Windows.Forms.TextBox();
+ this.label2 = new System.Windows.Forms.Label();
+ this.textboxPassword = new System.Windows.Forms.TextBox();
+ this.buttonLogin = new System.Windows.Forms.Button();
+ this.buttonCancel = new System.Windows.Forms.Button();
+ this.SuspendLayout();
+ //
+ // label1
+ //
+ resources.ApplyResources(this.label1, "label1");
+ this.label1.Name = "label1";
+ //
+ // textboxLoginName
+ //
+ resources.ApplyResources(this.textboxLoginName, "textboxLoginName");
+ this.textboxLoginName.Name = "textboxLoginName";
+ //
+ // label2
+ //
+ resources.ApplyResources(this.label2, "label2");
+ this.label2.Name = "label2";
+ //
+ // textboxPassword
+ //
+ resources.ApplyResources(this.textboxPassword, "textboxPassword");
+ this.textboxPassword.Name = "textboxPassword";
+ this.textboxPassword.UseSystemPasswordChar = true;
+ //
+ // buttonLogin
+ //
+ resources.ApplyResources(this.buttonLogin, "buttonLogin");
+ this.buttonLogin.Name = "buttonLogin";
+ this.buttonLogin.UseVisualStyleBackColor = true;
+ this.buttonLogin.Click += new System.EventHandler(this.buttonLogin_Click);
+ //
+ // buttonCancel
+ //
+ resources.ApplyResources(this.buttonCancel, "buttonCancel");
+ this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ this.buttonCancel.Name = "buttonCancel";
+ this.buttonCancel.UseVisualStyleBackColor = true;
+ //
+ // LoginDialog
+ //
+ this.AcceptButton = this.buttonLogin;
+ resources.ApplyResources(this, "$this");
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.CancelButton = this.buttonCancel;
+ this.Controls.Add(this.buttonCancel);
+ this.Controls.Add(this.buttonLogin);
+ this.Controls.Add(this.textboxPassword);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.textboxLoginName);
+ this.Controls.Add(this.label1);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "LoginDialog";
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.TextBox textboxLoginName;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.TextBox textboxPassword;
+ private System.Windows.Forms.Button buttonLogin;
+ private System.Windows.Forms.Button buttonCancel;
+ }
+}
\ No newline at end of file
--- /dev/null
+// OpenTween - Client of Twitter
+// Copyright (c) 2017 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.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace OpenTween
+{
+ public partial class LoginDialog : OTBaseForm
+ {
+ public string LoginName => this.textboxLoginName.Text;
+ public string Password => this.textboxPassword.Text;
+
+ public Func<Task<bool>> LoginCallback { get; set; } = null;
+ public bool LoginSuccessed { get; set; } = false;
+
+ public LoginDialog()
+ => this.InitializeComponent();
+
+ private async void buttonLogin_Click(object sender, EventArgs e)
+ {
+ if (this.LoginCallback == null)
+ return;
+
+ try
+ {
+ using (ControlTransaction.Disabled(this))
+ {
+ // AcceptButton によって自動でフォームが閉じられるのを抑制する
+ this.AcceptButton = null;
+
+ this.LoginSuccessed = await this.LoginCallback();
+ if (this.LoginSuccessed)
+ this.DialogResult = DialogResult.OK;
+ }
+ }
+ finally
+ {
+ this.AcceptButton = this.buttonLogin;
+ }
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+ <data name="label1.Size" type="System.Drawing.Size, System.Drawing">
+ <value>56, 12</value>
+ </data>
+ <data name="label1.Text" xml:space="preserve">
+ <value>&Username</value>
+ </data>
+ <data name="label2.Size" type="System.Drawing.Size, System.Drawing">
+ <value>54, 12</value>
+ </data>
+ <data name="label2.Text" xml:space="preserve">
+ <value>&Password</value>
+ </data>
+ <data name="buttonLogin.Text" xml:space="preserve">
+ <value>&Login</value>
+ </data>
+ <data name="buttonCancel.Text" xml:space="preserve">
+ <value>&Cancel</value>
+ </data>
+</root>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+ <data name="label1.AutoSize" type="System.Boolean, mscorlib">
+ <value>True</value>
+ </data>
+ <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+ <data name="label1.Location" type="System.Drawing.Point, System.Drawing">
+ <value>12, 15</value>
+ </data>
+ <data name="label1.Size" type="System.Drawing.Size, System.Drawing">
+ <value>73, 12</value>
+ </data>
+ <data name="label1.TabIndex" type="System.Int32, mscorlib">
+ <value>0</value>
+ </data>
+ <data name="label1.Text" xml:space="preserve">
+ <value>ユーザー名(&U)</value>
+ </data>
+ <data name=">>label1.Name" xml:space="preserve">
+ <value>label1</value>
+ </data>
+ <data name=">>label1.Type" xml:space="preserve">
+ <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </data>
+ <data name=">>label1.Parent" xml:space="preserve">
+ <value>$this</value>
+ </data>
+ <data name=">>label1.ZOrder" xml:space="preserve">
+ <value>5</value>
+ </data>
+ <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+ <data name="textboxLoginName.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
+ <value>Top, Left, Right</value>
+ </data>
+ <data name="textboxLoginName.Location" type="System.Drawing.Point, System.Drawing">
+ <value>94, 12</value>
+ </data>
+ <data name="textboxLoginName.Size" type="System.Drawing.Size, System.Drawing">
+ <value>193, 19</value>
+ </data>
+ <data name="textboxLoginName.TabIndex" type="System.Int32, mscorlib">
+ <value>1</value>
+ </data>
+ <data name=">>textboxLoginName.Name" xml:space="preserve">
+ <value>textboxLoginName</value>
+ </data>
+ <data name=">>textboxLoginName.Type" xml:space="preserve">
+ <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </data>
+ <data name=">>textboxLoginName.Parent" xml:space="preserve">
+ <value>$this</value>
+ </data>
+ <data name=">>textboxLoginName.ZOrder" xml:space="preserve">
+ <value>4</value>
+ </data>
+ <data name="label2.AutoSize" type="System.Boolean, mscorlib">
+ <value>True</value>
+ </data>
+ <data name="label2.Location" type="System.Drawing.Point, System.Drawing">
+ <value>12, 40</value>
+ </data>
+ <data name="label2.Size" type="System.Drawing.Size, System.Drawing">
+ <value>67, 12</value>
+ </data>
+ <data name="label2.TabIndex" type="System.Int32, mscorlib">
+ <value>2</value>
+ </data>
+ <data name="label2.Text" xml:space="preserve">
+ <value>パスワード(&P)</value>
+ </data>
+ <data name=">>label2.Name" xml:space="preserve">
+ <value>label2</value>
+ </data>
+ <data name=">>label2.Type" xml:space="preserve">
+ <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </data>
+ <data name=">>label2.Parent" xml:space="preserve">
+ <value>$this</value>
+ </data>
+ <data name=">>label2.ZOrder" xml:space="preserve">
+ <value>3</value>
+ </data>
+ <data name="textboxPassword.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
+ <value>Top, Left, Right</value>
+ </data>
+ <data name="textboxPassword.Location" type="System.Drawing.Point, System.Drawing">
+ <value>94, 37</value>
+ </data>
+ <data name="textboxPassword.Size" type="System.Drawing.Size, System.Drawing">
+ <value>193, 19</value>
+ </data>
+ <data name="textboxPassword.TabIndex" type="System.Int32, mscorlib">
+ <value>3</value>
+ </data>
+ <data name=">>textboxPassword.Name" xml:space="preserve">
+ <value>textboxPassword</value>
+ </data>
+ <data name=">>textboxPassword.Type" xml:space="preserve">
+ <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </data>
+ <data name=">>textboxPassword.Parent" xml:space="preserve">
+ <value>$this</value>
+ </data>
+ <data name=">>textboxPassword.ZOrder" xml:space="preserve">
+ <value>2</value>
+ </data>
+ <data name="buttonLogin.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
+ <value>Bottom, Right</value>
+ </data>
+ <data name="buttonLogin.AutoSize" type="System.Boolean, mscorlib">
+ <value>True</value>
+ </data>
+ <data name="buttonLogin.Location" type="System.Drawing.Point, System.Drawing">
+ <value>146, 64</value>
+ </data>
+ <data name="buttonLogin.Size" type="System.Drawing.Size, System.Drawing">
+ <value>75, 25</value>
+ </data>
+ <data name="buttonLogin.TabIndex" type="System.Int32, mscorlib">
+ <value>4</value>
+ </data>
+ <data name="buttonLogin.Text" xml:space="preserve">
+ <value>ログイン(&L)</value>
+ </data>
+ <data name=">>buttonLogin.Name" xml:space="preserve">
+ <value>buttonLogin</value>
+ </data>
+ <data name=">>buttonLogin.Type" xml:space="preserve">
+ <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </data>
+ <data name=">>buttonLogin.Parent" xml:space="preserve">
+ <value>$this</value>
+ </data>
+ <data name=">>buttonLogin.ZOrder" xml:space="preserve">
+ <value>1</value>
+ </data>
+ <data name="buttonCancel.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
+ <value>Bottom, Right</value>
+ </data>
+ <data name="buttonCancel.AutoSize" type="System.Boolean, mscorlib">
+ <value>True</value>
+ </data>
+ <data name="buttonCancel.Location" type="System.Drawing.Point, System.Drawing">
+ <value>227, 64</value>
+ </data>
+ <data name="buttonCancel.Size" type="System.Drawing.Size, System.Drawing">
+ <value>78, 25</value>
+ </data>
+ <data name="buttonCancel.TabIndex" type="System.Int32, mscorlib">
+ <value>5</value>
+ </data>
+ <data name="buttonCancel.Text" xml:space="preserve">
+ <value>キャンセル(&C)</value>
+ </data>
+ <data name=">>buttonCancel.Name" xml:space="preserve">
+ <value>buttonCancel</value>
+ </data>
+ <data name=">>buttonCancel.Type" xml:space="preserve">
+ <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </data>
+ <data name=">>buttonCancel.Parent" xml:space="preserve">
+ <value>$this</value>
+ </data>
+ <data name=">>buttonCancel.ZOrder" xml:space="preserve">
+ <value>0</value>
+ </data>
+ <metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+ <value>True</value>
+ </metadata>
+ <data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
+ <value>6, 12</value>
+ </data>
+ <data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
+ <value>317, 101</value>
+ </data>
+ <data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
+ <value>CenterParent</value>
+ </data>
+ <data name="$this.Text" xml:space="preserve">
+ <value>LoginDialog</value>
+ </data>
+ <data name=">>$this.Name" xml:space="preserve">
+ <value>LoginDialog</value>
+ </data>
+ <data name=">>$this.Type" xml:space="preserve">
+ <value>OpenTween.OTBaseForm, OpenTween, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null</value>
+ </data>
+</root>
\ No newline at end of file
<DependentUpon>ApiInfoDialog.cs</DependentUpon>
</Compile>
<Compile Include="Api\ApiLimit.cs" />
+ <Compile Include="Api\BitlyApi.cs" />
<Compile Include="Api\DataModel\GeoJson.cs" />
<Compile Include="Api\DataModel\TwitterConfiguration.cs" />
<Compile Include="Api\DataModel\TwitterEntity.cs" />
<DependentUpon>FilterDialog.cs</DependentUpon>
</Compile>
<Compile Include="IndexedSortedSet.cs" />
+ <Compile Include="LoginDialog.cs">
+ <SubType>Form</SubType>
+ </Compile>
+ <Compile Include="LoginDialog.Designer.cs">
+ <DependentUpon>LoginDialog.cs</DependentUpon>
+ </Compile>
<Compile Include="MediaItem.cs" />
<Compile Include="Models\ComparerMode.cs" />
<Compile Include="Models\DirectMessagesTabModel.cs" />
<DependentUpon>AppendSettingDialog.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
+ <EmbeddedResource Include="LoginDialog.en.resx">
+ <DependentUpon>LoginDialog.cs</DependentUpon>
+ </EmbeddedResource>
+ <EmbeddedResource Include="LoginDialog.resx">
+ <DependentUpon>LoginDialog.cs</DependentUpon>
+ </EmbeddedResource>
<EmbeddedResource Include="MediaSelector.en.resx">
<DependentUpon>MediaSelector.cs</DependentUpon>
</EmbeddedResource>
}
/// <summary>
+ /// 認証に失敗しました ({0}) に類似しているローカライズされた文字列を検索します。
+ /// </summary>
+ internal static string BitlyAuthorize_ErrorText {
+ get {
+ return ResourceManager.GetString("BitlyAuthorize_ErrorText", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// ブラウザの起動に失敗しました。エラーコード: {0} に類似しているローカライズされた文字列を検索します。
/// </summary>
internal static string BrowserStartFailed {
}
/// <summary>
- /// IDとAPIキーの組み合わせが違います。IDと同時に設定するのはパスワードではなくAPIキーです。ご確認ください。 に類似しているローカライズされた文字列を検索します。
- /// </summary>
- internal static string SettingSave_ClickText1 {
- get {
- return ResourceManager.GetString("SettingSave_ClickText1", resourceCulture);
- }
- }
-
- /// <summary>
/// フォロー状況取得中・・・ に類似しているローカライズされた文字列を検索します。
/// </summary>
internal static string ShowFriendshipText1 {
}
/// <summary>
+ /// Bitlyを使用するには設定画面で認証情報を入力する必要があります に類似しているローカライズされた文字列を検索します。
+ /// </summary>
+ internal static string UrlConvert_BitlyAuthRequired {
+ get {
+ return ResourceManager.GetString("UrlConvert_BitlyAuthRequired", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// 適用 に類似しているローカライズされた文字列を検索します。
/// </summary>
internal static string UserInfoButtonEdit_ClickText1 {
<data name="SaveLogMenuItem_ClickText5" xml:space="preserve">
<value>Save events?{0} [Yes] :Save events in this tab{0} [No] :Save all events{0}[Cancel]:Cancel{0}(Save as Tab separated text(TSV))</value>
</data>
- <data name="SettingSave_ClickText1" xml:space="preserve">
- <value>Failed to authorization. Please confirm api key.</value>
- </data>
<data name="TranslateDefaultLanguage" xml:space="preserve">
<value>en</value>
</data>
* If you run as administrator, operations to post images with D&D will be restricted.
* After running, the setting files of {0} will be able to modify only from administrator.</value>
</data>
+ <data name="BitlyAuthorize_ErrorText" xml:space="preserve">
+ <value>Failed to authorize. ({0})</value>
+ </data>
+ <data name="UrlConvert_BitlyAuthRequired" xml:space="preserve">
+ <value>To use Bitly, you must perform the Bitly authentication in settings dialog.</value>
+ </data>
</root>
\ No newline at end of file
<data name="ChangeIconToolStripMenuItem_ClickText5" xml:space="preserve">
<value>アイコンを変更しました。 次回発言より反映されます。</value>
</data>
- <data name="SettingSave_ClickText1" xml:space="preserve">
- <value>IDとAPIキーの組み合わせが違います。IDと同時に設定するのはパスワードではなくAPIキーです。ご確認ください。</value>
- </data>
<data name="UserInfoButtonEdit_ClickText1" xml:space="preserve">
<value>適用</value>
</data>
* 管理者権限で実行するとD&Dで画像を投稿する操作が制限されます。
* {0}の設定ファイルが一般ユーザー権限で編集できなくなります。</value>
</data>
+ <data name="BitlyAuthorize_ErrorText" xml:space="preserve">
+ <value>認証に失敗しました ({0})</value>
+ </data>
+ <data name="UrlConvert_BitlyAuthRequired" xml:space="preserve">
+ <value>Bitlyを使用するには設定画面で認証情報を入力する必要があります</value>
+ </data>
</root>
\ No newline at end of file
更新履歴
==== Ver 1.3.8-dev(2017/xx/xx)
- * FIX: bit.ly の正しいAPIキーを入力しても検証時にエラーが表示される不具合を修正
+ * NEW: bit.ly の認証方式が変更されました
+ - 短縮URLに bit.ly を使用する場合は、設定画面の「短縮URL」から bit.ly の「認可」ボタンを押して認証情報を入力して下さい
==== Ver 1.3.7(2017/03/20)
* NEW: PNG画像のアップロード時にJPEGへの変換による劣化を回避する機能を追加しました (pic.twitter.com のみ)
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ShortUrlPanel));
this.ShortenTcoCheck = new System.Windows.Forms.CheckBox();
this.CheckTinyURL = new System.Windows.Forms.CheckBox();
- this.TextBitlyPw = new System.Windows.Forms.TextBox();
+ this.TextBitlyAccessToken = new System.Windows.Forms.TextBox();
this.CheckAutoConvertUrl = new System.Windows.Forms.CheckBox();
this.Label71 = new System.Windows.Forms.Label();
this.ComboBoxAutoShortUrlFirst = new System.Windows.Forms.ComboBox();
- this.Label76 = new System.Windows.Forms.Label();
this.Label77 = new System.Windows.Forms.Label();
- this.TextBitlyId = new System.Windows.Forms.TextBox();
+ this.ButtonBitlyAuthorize = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// ShortenTcoCheck
this.CheckTinyURL.Name = "CheckTinyURL";
this.CheckTinyURL.UseVisualStyleBackColor = true;
//
- // TextBitlyPw
+ // TextBitlyAccessToken
//
- resources.ApplyResources(this.TextBitlyPw, "TextBitlyPw");
- this.TextBitlyPw.Name = "TextBitlyPw";
+ resources.ApplyResources(this.TextBitlyAccessToken, "TextBitlyAccessToken");
+ this.TextBitlyAccessToken.Name = "TextBitlyAccessToken";
//
// CheckAutoConvertUrl
//
this.ComboBoxAutoShortUrlFirst.Name = "ComboBoxAutoShortUrlFirst";
this.ComboBoxAutoShortUrlFirst.SelectedIndexChanged += new System.EventHandler(this.ComboBoxAutoShortUrlFirst_SelectedIndexChanged);
//
- // Label76
- //
- resources.ApplyResources(this.Label76, "Label76");
- this.Label76.Name = "Label76";
- //
// Label77
//
resources.ApplyResources(this.Label77, "Label77");
this.Label77.Name = "Label77";
//
- // TextBitlyId
+ // ButtonBitlyAuthorize
//
- resources.ApplyResources(this.TextBitlyId, "TextBitlyId");
- this.TextBitlyId.Name = "TextBitlyId";
+ resources.ApplyResources(this.ButtonBitlyAuthorize, "ButtonBitlyAuthorize");
+ this.ButtonBitlyAuthorize.Name = "ButtonBitlyAuthorize";
+ this.ButtonBitlyAuthorize.UseVisualStyleBackColor = true;
+ this.ButtonBitlyAuthorize.Click += new System.EventHandler(this.ButtonBitlyAuthorize_Click);
//
// ShortUrlPanel
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.Controls.Add(this.ShortenTcoCheck);
this.Controls.Add(this.CheckTinyURL);
- this.Controls.Add(this.TextBitlyPw);
+ this.Controls.Add(this.TextBitlyAccessToken);
this.Controls.Add(this.CheckAutoConvertUrl);
this.Controls.Add(this.Label71);
this.Controls.Add(this.ComboBoxAutoShortUrlFirst);
- this.Controls.Add(this.Label76);
+ this.Controls.Add(this.ButtonBitlyAuthorize);
this.Controls.Add(this.Label77);
- this.Controls.Add(this.TextBitlyId);
this.Name = "ShortUrlPanel";
this.ResumeLayout(false);
this.PerformLayout();
internal System.Windows.Forms.CheckBox ShortenTcoCheck;
internal System.Windows.Forms.CheckBox CheckTinyURL;
- internal System.Windows.Forms.TextBox TextBitlyPw;
internal System.Windows.Forms.CheckBox CheckAutoConvertUrl;
internal System.Windows.Forms.Label Label71;
internal System.Windows.Forms.ComboBox ComboBoxAutoShortUrlFirst;
- internal System.Windows.Forms.Label Label76;
internal System.Windows.Forms.Label Label77;
- internal System.Windows.Forms.TextBox TextBitlyId;
+ private System.Windows.Forms.Button ButtonBitlyAuthorize;
+ private System.Windows.Forms.TextBox TextBitlyAccessToken;
}
}
using System.Linq;
using System.Text;
using System.Windows.Forms;
+using OpenTween.Api;
+using System.Threading.Tasks;
namespace OpenTween.Setting.Panel
{
this.ShortenTcoCheck.Enabled = this.CheckAutoConvertUrl.Checked;
this.ComboBoxAutoShortUrlFirst.SelectedIndex = (int)settingCommon.AutoShortUrlFirst;
- this.TextBitlyId.Text = settingCommon.BilyUser;
- this.TextBitlyPw.Text = settingCommon.BitlyPwd;
- this.TextBitlyId.Modified = false;
- this.TextBitlyPw.Modified = false;
+ this.TextBitlyAccessToken.Text = settingCommon.BitlyAccessToken;
+ this.TextBitlyAccessToken.Modified = false;
}
public void SaveConfig(SettingCommon settingCommon)
settingCommon.UrlConvertAuto = this.CheckAutoConvertUrl.Checked;
//settingCommon.ShortenTco = this.ShortenTcoCheck.Checked;
settingCommon.AutoShortUrlFirst = (MyCommon.UrlConverter)this.ComboBoxAutoShortUrlFirst.SelectedIndex;
- settingCommon.BilyUser = this.TextBitlyId.Text;
- settingCommon.BitlyPwd = this.TextBitlyPw.Text;
+ settingCommon.BitlyAccessToken = this.TextBitlyAccessToken.Text;
}
private void ComboBoxAutoShortUrlFirst_SelectedIndexChanged(object sender, EventArgs e)
if (ComboBoxAutoShortUrlFirst.SelectedIndex == (int)MyCommon.UrlConverter.Bitly ||
ComboBoxAutoShortUrlFirst.SelectedIndex == (int)MyCommon.UrlConverter.Jmp)
{
- Label76.Enabled = true;
Label77.Enabled = true;
- TextBitlyId.Enabled = true;
- TextBitlyPw.Enabled = true;
+ TextBitlyAccessToken.Enabled = true;
+ ButtonBitlyAuthorize.Enabled = true;
}
else
{
- Label76.Enabled = false;
Label77.Enabled = false;
- TextBitlyId.Enabled = false;
- TextBitlyPw.Enabled = false;
+ TextBitlyAccessToken.Enabled = false;
+ ButtonBitlyAuthorize.Enabled = false;
}
}
{
ShortenTcoCheck.Enabled = CheckAutoConvertUrl.Checked;
}
+
+ private void ButtonBitlyAuthorize_Click(object sender, EventArgs e)
+ {
+ using (var dialog = new LoginDialog())
+ {
+ const string DialogText = "Bitly Login";
+ dialog.Text = DialogText;
+
+ string accessToken = null;
+ dialog.LoginCallback = async () =>
+ {
+ try
+ {
+ var bitly = new BitlyApi();
+ accessToken = await bitly.GetAccessTokenAsync(dialog.LoginName, dialog.Password);
+ return true;
+ }
+ catch (WebApiException ex)
+ {
+ var text = string.Format(Properties.Resources.BitlyAuthorize_ErrorText, ex.Message);
+ MessageBox.Show(dialog, text, DialogText, MessageBoxButtons.OK, MessageBoxIcon.Error);
+ return false;
+ }
+ };
+
+ if (dialog.ShowDialog(this.ParentForm) == DialogResult.OK)
+ {
+ this.TextBitlyAccessToken.Text = accessToken;
+ }
+ }
+ }
}
}
<data name="Label71.Text" xml:space="preserve">
<value>Primary URLshorten service</value>
</data>
+ <data name="Label77.Size" type="System.Drawing.Size, System.Drawing">
+ <value>108, 12</value>
+ </data>
+ <data name="Label77.Text" xml:space="preserve">
+ <value>Bit.ly Access Token</value>
+ </data>
+ <data name="ButtonBitlyAuthorize.Text" xml:space="preserve">
+ <value>Authorize</value>
+ </data>
</root>
\ No newline at end of file
<value>95, 16</value>
</data>
<data name="ShortenTcoCheck.TabIndex" type="System.Int32, mscorlib">
- <value>18</value>
+ <value>2</value>
</data>
<data name="ShortenTcoCheck.Text" xml:space="preserve">
<value>t.coで短縮する</value>
<value>122, 16</value>
</data>
<data name="CheckTinyURL.TabIndex" type="System.Int32, mscorlib">
- <value>10</value>
+ <value>0</value>
</data>
<data name="CheckTinyURL.Text" xml:space="preserve">
<value>短縮URLを解決する</value>
<data name=">>CheckTinyURL.ZOrder" xml:space="preserve">
<value>1</value>
</data>
- <data name="TextBitlyPw.Location" type="System.Drawing.Point, System.Drawing">
- <value>419, 127</value>
+ <data name="TextBitlyAccessToken.Location" type="System.Drawing.Point, System.Drawing">
+ <value>249, 131</value>
</data>
- <data name="TextBitlyPw.Size" type="System.Drawing.Size, System.Drawing">
- <value>70, 19</value>
+ <data name="TextBitlyAccessToken.Size" type="System.Drawing.Size, System.Drawing">
+ <value>173, 19</value>
</data>
- <data name="TextBitlyPw.TabIndex" type="System.Int32, mscorlib">
- <value>17</value>
+ <data name="TextBitlyAccessToken.TabIndex" type="System.Int32, mscorlib">
+ <value>6</value>
</data>
- <data name=">>TextBitlyPw.Name" xml:space="preserve">
- <value>TextBitlyPw</value>
+ <data name=">>TextBitlyAccessToken.Name" xml:space="preserve">
+ <value>TextBitlyAccessToken</value>
</data>
- <data name=">>TextBitlyPw.Type" xml:space="preserve">
+ <data name=">>TextBitlyAccessToken.Type" xml:space="preserve">
<value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
- <data name=">>TextBitlyPw.Parent" xml:space="preserve">
+ <data name=">>TextBitlyAccessToken.Parent" xml:space="preserve">
<value>$this</value>
</data>
- <data name=">>TextBitlyPw.ZOrder" xml:space="preserve">
+ <data name=">>TextBitlyAccessToken.ZOrder" xml:space="preserve">
<value>2</value>
</data>
<data name="CheckAutoConvertUrl.AutoSize" type="System.Boolean, mscorlib">
<value>242, 16</value>
</data>
<data name="CheckAutoConvertUrl.TabIndex" type="System.Int32, mscorlib">
- <value>11</value>
+ <value>1</value>
</data>
<data name="CheckAutoConvertUrl.Text" xml:space="preserve">
<value>入力欄のURLを投稿する際に自動で短縮する</value>
<value>154, 12</value>
</data>
<data name="Label71.TabIndex" type="System.Int32, mscorlib">
- <value>12</value>
+ <value>3</value>
</data>
<data name="Label71.Text" xml:space="preserve">
<value>URL自動短縮で優先的に使用</value>
<value>246, 20</value>
</data>
<data name="ComboBoxAutoShortUrlFirst.TabIndex" type="System.Int32, mscorlib">
- <value>13</value>
+ <value>4</value>
</data>
<data name=">>ComboBoxAutoShortUrlFirst.Name" xml:space="preserve">
<value>ComboBoxAutoShortUrlFirst</value>
<data name=">>ComboBoxAutoShortUrlFirst.ZOrder" xml:space="preserve">
<value>5</value>
</data>
- <data name="Label76.AutoSize" type="System.Boolean, mscorlib">
- <value>True</value>
- </data>
- <data name="Label76.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
- <value>NoControl</value>
- </data>
- <data name="Label76.Location" type="System.Drawing.Point, System.Drawing">
- <value>246, 130</value>
- </data>
- <data name="Label76.Size" type="System.Drawing.Size, System.Drawing">
- <value>16, 12</value>
- </data>
- <data name="Label76.TabIndex" type="System.Int32, mscorlib">
- <value>14</value>
- </data>
- <data name="Label76.Text" xml:space="preserve">
- <value>ID</value>
- </data>
- <data name=">>Label76.Name" xml:space="preserve">
- <value>Label76</value>
- </data>
- <data name=">>Label76.Type" xml:space="preserve">
- <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
- </data>
- <data name=">>Label76.Parent" xml:space="preserve">
- <value>$this</value>
- </data>
- <data name=">>Label76.ZOrder" xml:space="preserve">
- <value>6</value>
- </data>
<data name="Label77.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<value>NoControl</value>
</data>
<data name="Label77.Location" type="System.Drawing.Point, System.Drawing">
- <value>364, 130</value>
+ <value>23, 134</value>
</data>
<data name="Label77.Size" type="System.Drawing.Size, System.Drawing">
- <value>42, 12</value>
+ <value>106, 12</value>
</data>
<data name="Label77.TabIndex" type="System.Int32, mscorlib">
- <value>16</value>
+ <value>5</value>
</data>
<data name="Label77.Text" xml:space="preserve">
- <value>APIKey</value>
+ <value>Bit.ly アクセストークン</value>
</data>
<data name=">>Label77.Name" xml:space="preserve">
<value>Label77</value>
<data name=">>Label77.ZOrder" xml:space="preserve">
<value>7</value>
</data>
- <data name="TextBitlyId.Location" type="System.Drawing.Point, System.Drawing">
- <value>273, 127</value>
+ <data name="ButtonBitlyAuthorize.Location" type="System.Drawing.Point, System.Drawing">
+ <value>429, 129</value>
+ </data>
+ <data name="ButtonBitlyAuthorize.Size" type="System.Drawing.Size, System.Drawing">
+ <value>67, 23</value>
</data>
- <data name="TextBitlyId.Size" type="System.Drawing.Size, System.Drawing">
- <value>71, 19</value>
+ <data name="ButtonBitlyAuthorize.TabIndex" type="System.Int32, mscorlib">
+ <value>7</value>
</data>
- <data name="TextBitlyId.TabIndex" type="System.Int32, mscorlib">
- <value>15</value>
+ <data name="ButtonBitlyAuthorize.Text" xml:space="preserve">
+ <value>認可</value>
</data>
- <data name=">>TextBitlyId.Name" xml:space="preserve">
- <value>TextBitlyId</value>
+ <data name=">>ButtonBitlyAuthorize.Name" xml:space="preserve">
+ <value>ButtonBitlyAuthorize</value>
</data>
- <data name=">>TextBitlyId.Type" xml:space="preserve">
- <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ <data name=">>ButtonBitlyAuthorize.Type" xml:space="preserve">
+ <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
- <data name=">>TextBitlyId.Parent" xml:space="preserve">
+ <data name=">>ButtonBitlyAuthorize.Parent" xml:space="preserve">
<value>$this</value>
</data>
- <data name=">>TextBitlyId.ZOrder" xml:space="preserve">
- <value>8</value>
+ <data name=">>ButtonBitlyAuthorize.ZOrder" xml:space="preserve">
+ <value>6</value>
</data>
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
public bool GetFav = true;
public string BilyUser = "";
public string BitlyPwd = "";
+
+ /// <summary>Bitly API アクセストークン</summary>
+ public string BitlyAccessToken { get; set; } = "";
+
public bool ShowGrid = false;
public bool UseAtIdSupplement = true;
public bool UseHashSupplement = true;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
+using OpenTween.Api;
using OpenTween.Connection;
namespace OpenTween
/// </summary>
public int PurgeCount { get; set; }
+ public string BitlyAccessToken { get; set; }
public string BitlyId { get; set; }
public string BitlyKey { get; set; }
if ("http://bit.ly/xxxx".Length > srcUri.OriginalString.Length)
return srcUri;
- // bit.ly 短縮機能実装のプライバシー問題の暫定対応
- // ログインIDとAPIキーが指定されていない場合は短縮せずにPOSTする
- // 参照: http://sourceforge.jp/projects/opentween/lists/archive/dev/2012-January/000020.html
- if (string.IsNullOrEmpty(this.BitlyId) || string.IsNullOrEmpty(this.BitlyKey))
+ // OAuth2 アクセストークンまたは API キー (旧方式) のいずれも設定されていなければ短縮しない
+ if (string.IsNullOrEmpty(this.BitlyAccessToken) && (string.IsNullOrEmpty(this.BitlyId) || string.IsNullOrEmpty(this.BitlyKey)))
return srcUri;
- var query = new Dictionary<string, string>
+ var bitly = new BitlyApi
{
- ["login"] = this.BitlyId,
- ["apiKey"] = this.BitlyKey,
- ["format"] = "txt",
- ["domain"] = domain,
- ["longUrl"] = srcUri.OriginalString,
+ EndUserAccessToken = this.BitlyAccessToken,
+ EndUserLoginName = this.BitlyId,
+ EndUserApiKey = this.BitlyKey,
};
- var uri = new Uri("https://api-ssl.bitly.com/v3/shorten?" + MyCommon.BuildQueryString(query));
- using (var response = await this.http.GetAsync(uri).ConfigureAwait(false))
- {
- response.EnsureSuccessStatusCode();
-
- var result = await response.Content.ReadAsStringAsync()
- .ConfigureAwait(false);
-
- if (!Regex.IsMatch(result, @"^https?://"))
- throw new WebApiException("Failed to create URL.", result);
-
- return new Uri(result.TrimEnd());
- }
+ return await bitly.ShortenAsync(srcUri, domain)
+ .ConfigureAwait(false);
}
private async Task<Uri> ShortenByUxnuAsync(Uri srcUri)
tw.AllAtReply = SettingManager.Common.AllAtReply;
AllrepliesToolStripMenuItem.Checked = tw.AllAtReply;
ShortUrl.Instance.DisableExpanding = !SettingManager.Common.TinyUrlResolve;
+ ShortUrl.Instance.BitlyAccessToken = SettingManager.Common.BitlyAccessToken;
ShortUrl.Instance.BitlyId = SettingManager.Common.BilyUser;
ShortUrl.Instance.BitlyKey = SettingManager.Common.BitlyPwd;
tw.RestrictFavCheck = SettingManager.Common.RestrictFavCheck;
tw.ReadOwnPost = SettingManager.Common.ReadOwnPost;
ShortUrl.Instance.DisableExpanding = !SettingManager.Common.TinyUrlResolve;
+ ShortUrl.Instance.BitlyAccessToken = SettingManager.Common.BitlyAccessToken;
ShortUrl.Instance.BitlyId = SettingManager.Common.BilyUser;
ShortUrl.Instance.BitlyKey = SettingManager.Common.BitlyPwd;
TwitterApiConnection.RestApiHost = SettingManager.Common.TwitterApiHost;
private async Task<bool> UrlConvertAsync(MyCommon.UrlConverter Converter_Type)
{
+ if (Converter_Type == MyCommon.UrlConverter.Bitly || Converter_Type == MyCommon.UrlConverter.Jmp)
+ {
+ // OAuth2 アクセストークンまたは API キー (旧方式) のいずれも設定されていなければ短縮しない
+ if (string.IsNullOrEmpty(SettingManager.Common.BitlyAccessToken) &&
+ (string.IsNullOrEmpty(SettingManager.Common.BilyUser) || string.IsNullOrEmpty(SettingManager.Common.BitlyPwd)))
+ {
+ MessageBox.Show(this, Properties.Resources.UrlConvert_BitlyAuthRequired, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ return false;
+ }
+ }
+
//t.coで投稿時自動短縮する場合は、外部サービスでの短縮禁止
//if (SettingDialog.UrlConvertAuto && SettingDialog.ShortenTco) return;