質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

4283閲覧

UnityのLet's Tweet in Unityを用いた画像ツイート

mosin_nozomi

総合スコア29

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2016/12/19 14:32

編集2016/12/19 15:01

Unityの無料Asset、Let's Twitter in Unityを用いTwitterクライアントを製作しています。

このアセットには画像ツイートメソッドは含まれていないため、文字のみのツイートをポストするメソッドを真似て画像をアップロードするメソッドを作りたいのですが、エラーが返ってきてしまいなかなかうまくいきません。

以下が真似て作ったメソッドになります。

https://syncer.jp/twitter-api-matome#sec-6

このページを参考にheaderとWWWFormを作ったのですが、
BadRequest:Code:38,media parameter is missing
のエラーが返ってきてしまいます。

また、boundaryについてよくわかっておらず、AddFieldでboundaryを追加してもBadRequestが返ってきてしまいました。

C#

1 2public static IEnumerator UploadPic(string picture, string consumerKey, string consumerSecret, AccessTokenResponse response, UploadPicCallback callback) 3{ 4 5 Dictionary<string, string> parameters = new Dictionary<string, string>(); 6 7 // Add data to the form to post. 8 WWWForm form = new WWWForm(); 9 form.AddField("Content-Disposition", "form-data"); 10 form.AddField("name", "media_data"); 11 form.AddField(picture, ""); 12 13 14 15 // HTTP header 16 17 Dictionary<string, string> headers = new Dictionary<string, string>(); 18 headers["Authorization"] = GetHeaderWithAccessToken("POST", UploadPicURL, consumerKey, consumerSecret, response, parameters); 19 headers["Content-Type"] = "multipart/form-data; boundary="; 20 21 22 WWW web = new WWW(UploadPicURL, form.data, headers); 23 24 yield return web; 25 26 if (!string.IsNullOrEmpty(web.error)) 27 { 28 Debug.Log(string.Format("UploadPic - failed. {0}\n{1}", web.error, web.text)); 29 callback(false, web.error); 30 } 31 else 32 { 33 string error = Regex.Match(web.text, @"<error>([^&]+)</error>").Groups[1].Value; 34 35 if (!string.IsNullOrEmpty(error)) 36 { 37 Debug.Log(string.Format("UploadPic - failed. {0}", error)); 38 callback(false, web.error); 39 } 40 else 41 { 42 callback(true, web.text); 43 } 44 } 45 46 } 47

以上がメソッドになります。

引数のpictureはアップロードする画像をBase64に変換したStringになります。
Consumer_keyとConsumer_Secretはツイッターのアプリケーションのキーで正しいものが入っています。
responseはユーザの認証情報でこれも正しいです。
callbackはコールバック関数でログの表示のみを行います。

調べがついているのは
WWWForm form = new WWWFormに必要なデータで上記の参考URLのリクエストボディにあたる部分
Dictionaryのheaderは署名とヘッダーにあたる部分で、参考URLの文字列のみのツイートのヘッダーと比較を行いながら作成したため、これは正しいと踏んでいるのですが、解説しているサイト等がないため確証はありません。

headersとformにどの要素を入れれば良いかご教授願えないでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

なんか、2段階にPOSTしないといけないようですね。1回目のポストでmedia_idを取得して、2回目のポストでツイート時にmedia_idsを添付する形となります。
一応、動作したコードです。このメソッドをTwitter.csに追加して、

c#

1StartCoroutine(Twitter.API.PostTweetWithMedia(m_Tweet, "画像ファイル絶対パス", CONSUMER_KEY, CONSUMER_SECRET, m_AccessTokenResponse, new Twitter.PostTweetCallback(this.OnPostTweet)));

のように呼び出してみてください。

c#

1// 1回目のレスポンスJSONをオブジェクトに変換するためのクラス 2class strctImage 3{ 4 public string image_type; 5 public long w; 6 public long h; 7} 8class mediaResponse 9{ 10 public long media_id; 11 public string media_id_string; 12 public long size; 13 public long expires_after_secs; 14 public strctImage image; 15} 16 17// Twitter.csに追加するメソッド 18public static IEnumerator PostTweetWithMedia(string text, string imagePath, string consumerKey, string consumerSecret, AccessTokenResponse response, PostTweetCallback callback) 19{ 20 if (string.IsNullOrEmpty(text) || text.Length > 140) 21 { 22 Debug.Log(string.Format("PostTweet - text[{0}] is empty or too long.", text)); 23 24 callback(false); 25 } 26 else 27 { 28 FileStream fileStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read); 29 BinaryReader bin = new BinaryReader(fileStream); 30 byte[] bytes = bin.ReadBytes((int)bin.BaseStream.Length); 31 var bs64 = Convert.ToBase64String(bytes); 32 bin.Close(); 33 34 Dictionary<string, string> mediaParameters = new Dictionary<string, string>(); 35 mediaParameters.Add("media_data", bs64); 36 WWWForm mediaForm = new WWWForm(); 37 mediaForm.AddField("media_data", bs64); 38 var mediaHeaders = new Dictionary<string, string>(); 39 mediaHeaders.Add("Authorization", GetHeaderWithAccessToken("POST", UploadMediaURL, consumerKey, consumerSecret, response, mediaParameters)); 40 WWW mediaWeb = new WWW(UploadMediaURL, mediaForm.data, mediaHeaders); 41 42 yield return mediaWeb; 43 44 string media_id_string = ""; 45 if (!string.IsNullOrEmpty(mediaWeb.error)) 46 { 47 Debug.Log(string.Format("PostMedia - failed. {0}\n{1}", mediaWeb.error, mediaWeb.text)); 48 callback(false); 49 yield break; 50 } 51 else 52 { 53 string error = Regex.Match(mediaWeb.text, @"<error>([^&]+)</error>").Groups[1].Value; 54 55 if (!string.IsNullOrEmpty(error)) 56 { 57 Debug.Log(string.Format("PostTweet - failed. {0}", error)); 58 callback(false); 59 yield break; 60 } 61 else 62 { 63 var res = JsonUtility.FromJson<mediaResponse>(mediaWeb.text); 64 media_id_string = res.media_id_string; 65 } 66 } 67 68 Dictionary<string, string> parameters = new Dictionary<string, string>(); 69 parameters.Add("status", text); 70 parameters.Add("media_ids", media_id_string); 71 WWWForm form = new WWWForm(); 72 form.AddField("status", text); 73 form.AddField("media_ids", media_id_string); 74 75 // HTTP header 76 var headers = new Dictionary<string, string>(); 77 headers.Add("Authorization", GetHeaderWithAccessToken("POST", PostTweetURL, consumerKey, consumerSecret, response, parameters)); 78 79 WWW web = new WWW(PostTweetURL, form.data, headers); 80 yield return web; 81 82 if (!string.IsNullOrEmpty(web.error)) 83 { 84 Debug.Log(string.Format("PostTweet - failed. {0}\n{1}", web.error, web.text)); 85 callback(false); 86 } 87 else 88 { 89 string error = Regex.Match(web.text, @"<error>([^&]+)</error>").Groups[1].Value; 90 91 if (!string.IsNullOrEmpty(error)) 92 { 93 Debug.Log(string.Format("PostTweet - failed. {0}", error)); 94 callback(false); 95 } 96 else 97 { 98 callback(true); 99 } 100 } 101 } 102}

投稿2016/12/19 18:24

turbgraphics200

総合スコア4267

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mosin_nozomi

2016/12/19 18:51

ありがとうございます、画像をConvert.ToBase64Stringした後、mediaParametersにAddし、mediaHeadersにaddするときのGetHeaderWithAccessTokenでUriFormatException:Uri is longer than the maximum {0} characters. が出てしまうのですが、UrlEncodeのメソッドはどこか変更されていたりしますか? 幾度もお手数かけて申し訳ありません。
mosin_nozomi

2016/12/19 19:25

テスト用の画像を用意してプロジェクトの実行をしていたのですが、その画像がjpgであったためエラーが出ていたようです。pngのテスト画像を用意したところ無事アップロードできました・・・。 本当にありがとうございました。画像の拡張子でエラーが出るか出ないかが変わるのですね・・・
guest

0

addFieldの使い方としては、

C#

1form.AddField("media_data", picture);

が、正しいかと。
あと、boundaryは、ライブラリ内部で展開してくれると思うので自分で実装する必要はないのではと思います。

投稿2016/12/19 15:42

turbgraphics200

総合スコア4267

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mosin_nozomi

2016/12/19 15:46

ご回答ありがとうございます。 form.AddField("media_data", picture); も試してみたのですが、やはりBadRequestが返ってきてしまいます。 また、headesの headers["Content-Type"] = "multipart/form-data; boundary="; のboundary=の削除も試してみたのですが、結果変わらずでした・・・ リクエストする要素がそもそも足りていないのでしょうか・・・
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問