SQLの窓

2013年07月26日


まぎらわしい『AdSenseの終了』を知らせる『日本語ページ』

、と巷で評判になってましたが、Google 側がさすがにまずいと思ったらしく、表現が変わっていました。
( つい数時間前まで『AdSenseの終了』)

『Google サイトでの AdSense 掲載終了について』

英語ページに変更すると、いまだに『Sunsetting AdSense』となっていますが、そちらでは『 AdSense on any of your Google Sites』なんで間違う人もいないと思います。実際、Google.com で検索すると、焦点は『Googleサイトでもう収入は得られないのか?』というものでした。でも、日本じゃ騒然とするのも仕方無いですね。

だいたい、Google のドキュメントは、英語ページと日本語ページで違う事も多く、ある英単語に対して時期が違うと違う日本語の単語になっていたりする事もあります。ただ、たいていにおいて、『ん?』となる程度で問題になった事はあまりないでしょうが、今回はさすがに対応したみたいですね(笑)



そう言えば、最後の1文は前は無かったはずです。

『Google サイト以外でお使いの AdSense への影響はなく、通常通りご利用いただけます。』



posted by lightbox at 2013-07-26 16:15 | 記録 | このブログの読者になる | 更新情報をチェックする

2013年07月24日


Trigger Rally(WebGL+Three.js) のコースを無視してひたすら悪路を走りまくる



Bandicam で録画しました。
( 動画も便利ですが、静止画もさらに便利ですね )

WebGL+Three.js なので、Google Chrome で実行しています。Trigger Rally は、Three.js をエンジンとして CoffeeScript で書かれています。

結論から言うと、ヒマつぶしに持ってこいです。

上下矢印キー : 前進・後退
左右矢印キー : ハンドル
スペースキー : ハンドブレーキ
C キー : カメラビューの変更
R キー : リスタート

以上の操作で、ただひたすらにどこまても悪路を走り続ける事ができます。本来は、コースを作ってタイムトライアルをするのですが、コースをカスタマイズしたりデモコース以外を走ったりするには PayPal で 5ドル程度を支払うと可能になります。( イマイチ詳細が良く解りません )

この時、車の種類が2台増えるのですが・・・・あまり面白く無いのでフリーで遊べばいいと思います。( 検証の為に 5ドル払いました )

羽の生えた車を使って大空をグライダー飛行したり、天空のダートコースを走ったりできるのですが・・・たぶんすぐ飽きちゃうと思います。







posted by lightbox at 2013-07-24 22:06 | 記録 | このブログの読者になる | 更新情報をチェックする

Google Chrome を強制終了すると、後で『開いていたページを復元』できますが、ログイン状態も復元してしまいます。



しごく当たり前の事ですが、自宅以外のコンピュータでどこかのサービースへログインしたままシャットダウンまたはログオフしてしまうと、次に Google Chrome を実行した人がそのサービスへのログイン状態のまま作業ができてしまいます。



posted by lightbox at 2013-07-24 09:10 | Google Chrome | このブログの読者になる | 更新情報をチェックする

2013年07月18日


VS2010(C#) Form : Google API でログインして Google ドライブにアップロード

ダウンロードする zip は、VS2010 用のテンプレートです

SkyDrive へ移動



ダイアログを表示して、ログインした後ダイアログを閉じて、フォームより画像をアップロードします( 他の種類のファイルをアップロードするには、コードを変更して MIME と拡張子の関係を設定して下さい )

ダイアログ( Form2 ) から Form1 のコントロールを参照できるように、該当するコントロールの modifiers を Public に変更しています。

Client ID と Client secret と Redirect URIs が必要です( APIs Console )

Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;

namespace Google_Drive_Upload4
{
    public partial class Form1 : Form
    {
        // *******************************************
        // 以下の3つの static な文字列を設定して下さい
        // *******************************************
        public static string client_id = "";
        public static string client_secret = "";
        // ▼ 登録しているものを設定しないとエラーになります
        public static string redirect_uri = "";

        // ログインで取得する値
        public string access_token = null;
        public string token_type = null;

        // ログインダイアログ
        public Form2 login = null;

        // ここで使用する為に static にしています
        public VS2010_GoogleDrive vgd = new VS2010_GoogleDrive(
                    client_id,
                    client_secret,
                    redirect_uri
        );

        public Form1()
        {
            InitializeComponent();
        }

        // ***************************************************************
        // 投稿
        // ***************************************************************
        private void button1_Click(object sender, EventArgs e)
        {
            // ダイアログを開く準備
            this.openFileDialog1.Filter = "JPEG|*.jpg*;*.jpg";
            this.openFileDialog1.FilterIndex = 0;
            this.openFileDialog1.FileName = "";
            // ダイアログを開く
            DialogResult dr = this.openFileDialog1.ShowDialog();
            if (dr == System.Windows.Forms.DialogResult.OK)
            {
                // 実際は、拡張子によって、MIME を変更する
                vgd.Upload(openFileDialog1.FileName, "image/jpeg", token_type, access_token);
                vgd.GoogleUploadResult += (object _sender, VS2010_GoogleDrive.GoogleUploadArgs _e) =>
                {
                    this.textBox1.Text = _e.Message;
                };
            }
        }

        // ***************************************************************
        // ログインダイアログを開く
        // ***************************************************************
        private void button2_Click(object sender, EventArgs e)
        {
            login = new Form2();
            login.ShowDialog(this);
        }
    }
}

Form2.cs

WebBrowser のみを配置したダイアログです
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Net;
using Newtonsoft.Json.Linq;

namespace Google_Drive_Upload4
{
    public partial class Form2 : Form
    {
        // 親フォーム参照用の変数
        private Form1 owner = null;
        private WebClient webClient = null;

        // アクセストークン取得用の URL
        private string _auth2_url = "https://accounts.google.com/o/oauth2/token";

        public Form2()
        {
            InitializeComponent();
        }

        // ***************************************************************
        // 初期処理
        // ***************************************************************
        private void Form2_Load(object sender, EventArgs e)
        {
            // 初期処理として、親フォーム参照用の変数をセット
            owner = this.Owner as Form1;
            // ログイン用のページを表示
            this.webBrowser1.Navigate(new Uri(owner.vgd.LoginUrl));
        }

        // ***************************************************************
        // code を取得
        // ***************************************************************
        private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            string url = e.Url.ToString();
            if (url.IndexOf("code=") != -1)
            {
                Debug.WriteLine(url);

                // URL に含まれる code を取得する
                int cur = url.IndexOf("=");
                string _code = url.Substring(cur + 1);

                webClient = new WebClient();

                webClient.UploadStringCompleted += new UploadStringCompletedEventHandler(get_token);
                // POST 用
                webClient.Headers["Content-Type"] = "application/x-www-form-urlencoded";

                string param = "";
                param = "code=" + _code;
                param += "&grant_type=authorization_code";
                param += "&redirect_uri=" + Form1.redirect_uri;
                param += "&client_id=" + Form1.client_id;
                param += "&client_secret=" + Form1.client_secret;
                // 呼び出し
                webClient.UploadStringAsync(new Uri(_auth2_url), "POST", param);

            }

        }

        // ***************************************************************
        // 有効なアクセストークンを取得
        // ***************************************************************
        private void get_token(object sender, UploadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                Debug.WriteLine("get_token:" + e.Error.Message);
            }
            else
            {
                string json_string = e.Result;
                Debug.WriteLine(json_string);

                // Json.NET の処理
                JObject data = JObject.Parse(json_string);
                owner.access_token = data["access_token"].ToString();
                owner.token_type = data["token_type"].ToString();

                // 全ての処理が終わったのでメインページへ戻る
                // ( コントロールの modifiers を public にしているので参照可能 )
                owner.button1.Enabled = true;
                owner.textBox1.Enabled = true;

                webClient.Dispose();

                // ダイアログを閉じる
                this.Close();
            }
        }

    }
}


VS2010_GoogleDrive.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Threading;

namespace Google_Drive_Upload4
{
    public class VS2010_GoogleDrive
    {
        private string _client_id;
        private string _client_secret;
        private string _redirect_uri;
        private SynchronizationContext sc = null;

        // ログイン用の URL
        private string loginUrlBase = "https://accounts.google.com/o/oauth2/auth";
        private string responseType = "code";
        // https://developers.google.com/drive/training/drive-apps/auth/scopes?hl=ja
        // https://developers.google.com/drive/v2/reference/files/insert
        private string scope = "https://www.googleapis.com/auth/drive.file+https://www.googleapis.com/auth/drive+https://www.googleapis.com/auth/drive.appdata";

        // アップロード用の URL
        private string upload_url = "https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart";
        //        private string upload_url = "http://localhost/test.php";

        // イベント引き渡し用クラス
        private class MyParam
        {
            public WebRequest web_request;
            public string boundary;
            public string file_path;
            public string content_type;
        }

        public VS2010_GoogleDrive(
            string client_id,
            string client_secret,
            string redirect_uri
            )
        {
            _client_id = client_id;
            _client_secret = client_secret;
            _redirect_uri = redirect_uri;
        }

        // ***************************************************
        // GoogleログインURLを取得する
        // https://developers.google.com/accounts/docs/OAuth2Login
        // ***************************************************
        public string LoginUrl
        {
            get
            {
                string url = loginUrlBase + "?";

                url += "client_id=" + _client_id;
                url += "&response_type=" + responseType;
                url += "&scope=" + scope;
                url += "&redirect_uri=" + _redirect_uri;

                return url;
            }
        }

        // ***************************************************
        // アップロード
        // ***************************************************
        public void Upload(string path, string contentType, string tokenType, string token)
        {
            // UI スレッドに戻る為のコンテキスト
            sc = SynchronizationContext.Current;

            HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(upload_url);
            // 経過処理を可能にする為に、キャッシュをしない設定
            webRequest.AllowWriteStreamBuffering = false;
            webRequest.SendChunked = true;

            webRequest.Method = "POST";

            // 地道なアップロード処理の開始
            string strBoundary = DateTime.Now.Ticks.ToString("x");
            webRequest.ContentType = "multipart/form-data; boundary=" + strBoundary;
            webRequest.Headers.Add("Authorization", tokenType + " " + token);

            AsyncCallback writeCallBack = new AsyncCallback(WriteCallBack);
            MyParam myParam = new MyParam()
            {
                web_request = webRequest,
                boundary = strBoundary,
                file_path = path,
                content_type = contentType
            };

            // 要求開始
            IAsyncResult iar1 = webRequest.BeginGetRequestStream(writeCallBack, myParam);

        }

        // ***************************************************
        // 書き込み
        // ***************************************************
        private void WriteCallBack(IAsyncResult ar)
        {
            HttpWebRequest webRequest = (HttpWebRequest)(ar.AsyncState as MyParam).web_request;
            string strBoundary = (ar.AsyncState as MyParam).boundary;
            // ファイルのパス
            string file_path = (ar.AsyncState as MyParam).file_path;
            // アップロード用のファイル名
            string file_name = Path.GetFileName(file_path);
            string content_type = (ar.AsyncState as MyParam).content_type;

            Stream binWriter = webRequest.EndGetRequestStream(ar);

            //--foo_bar_baz
            //Content-Type: application/json; charset=UTF-8

            //{
            //  "title": "My File"
            //}
            //--foo_bar_baz
            //Content-Type: image/jpeg

            //JPEG data
            //--foo_bar_baz--

            Encoding encoding = Encoding.ASCII;
            Byte[] content = encoding.GetBytes("--" + strBoundary + "\r\n");
            binWriter.Write(content, 0, content.Length);

            content = encoding.GetBytes("Content-Type: application/json; charset=UTF-8\r\n\r\n");
            binWriter.Write(content, 0, content.Length);

            // JSON フォーマットによるファイルの指定
            content = encoding.GetBytes("{\r\n");
            binWriter.Write(content, 0, content.Length);
            // ファイル名は UTF-8 で
            content = Encoding.GetEncoding("UTF-8").GetBytes("  \"title\": \"" + file_name + "\"\r\n");
            binWriter.Write(content, 0, content.Length);
            content = encoding.GetBytes("}\r\n");
            binWriter.Write(content, 0, content.Length);

            content = encoding.GetBytes("--" + strBoundary + "\r\n");
            binWriter.Write(content, 0, content.Length);

            content = encoding.GetBytes("Content-Type: " + content_type + "\r\n\r\n");
            binWriter.Write(content, 0, content.Length);

            // ファイルのバイナリデータ
            FileStream fs = new FileStream(file_path, FileMode.Open);
            int buffer_len = 409600;
            long length = 0;
            int read_size = 0;
            byte[] file_data = new byte[buffer_len];
            while ((read_size = fs.Read(file_data, 0, buffer_len)) > 0)
            {
                length += read_size;
                Debug.WriteLine("writing...." + length);
                binWriter.Write(file_data, 0, read_size);
                if (read_size < buffer_len)
                {
                    break;
                }
            }
            fs.Close();
            Debug.WriteLine("終了");

            content = encoding.GetBytes("\r\n--" + strBoundary + "--\r\n");
            binWriter.Write(content, 0, content.Length);

            binWriter.Close();

            AsyncCallback readCallBack = new AsyncCallback(this.ReadCallBack);
            IAsyncResult iar2 = webRequest.BeginGetResponse(readCallBack, webRequest);

        }

        // ***************************************************
        // 読み込み
        // ***************************************************
        private void ReadCallBack(IAsyncResult ar)
        {
            HttpWebRequest webRequest = (HttpWebRequest)ar.AsyncState;
            HttpWebResponse response = (HttpWebResponse)webRequest.EndGetResponse(ar);

            Encoding enc = System.Text.Encoding.GetEncoding("UTF-8");
            StreamReader streamReader = new StreamReader(response.GetResponseStream(), enc);

            string str = streamReader.ReadToEnd();
            streamReader.Close();

            Debug.WriteLine(str);

            // 内部のイベントの呼び出し( 最終的なイベントを UI スレッドで実行させる )
            sc.Post((object state) => { OnGoogleUploadResult(new GoogleUploadArgs(str)); }, null);

        }

        // ***************************************************
        // カスタムイベント用引数
        // ***************************************************
        public class GoogleUploadArgs : EventArgs
        {
            // 引数の保存エリア
            private string message;
            // コンストラクタ
            public GoogleUploadArgs(string s)
            {
                message = s;
            }

            // 引数取り出し用のプロパティ
            public string Message
            {
                get { return message; }
            }
        }

        // ***************************************************
        // カスタムイベントハンドラの定義 ( EventHandler<T> )
        // ***************************************************
        public event EventHandler<GoogleUploadArgs> GoogleUploadResult;

        // ***************************************************
        // 外部へイベントを発行する為の内部メソッドの定義( virtual )
        // ***************************************************
        protected virtual void OnGoogleUploadResult(GoogleUploadArgs e)
        {
            EventHandler<GoogleUploadArgs> handler = GoogleUploadResult;

            // イベントが外部で実装されている場合、そのイベントを呼び出す
            if (handler != null)
            {
                handler(this, e);
            }
        }
    }
}

コメントの、"http://localhost/test.php" は、生の投稿データを確認する為に使用しています( トレース )

関連する記事

VS2010(C#) Form : POST statuses/update_with_media で画像を伴った Twitter 投稿


posted by lightbox at 2013-07-18 22:20 | VS(C#) | このブログの読者になる | 更新情報をチェックする

VS2010(C#) Form : POST statuses/update_with_media で画像を伴った Twitter 投稿

VS 2010 用のテンプレートです。

SkyDrive へ移動


Twitter API : POST statuses/update_with_media

❶ API 1.1 での URL は、https://api.twitter.com/1.1/statuses/update_with_media.json です。
❷ 認証用のデータは、oauth_* のみ使って、status は使用しません
❸ 日本語投稿部分は、URLエンコードでは無く、UTF-8 で出力します
❹ UI スレッドへのアクセスは、SynchronizationContext を使用しています
❺ カスタムイベントで、投稿結果の JSON を取得します( UI スレッド )

生データをチェックしたい場合、AN HTTPD では、トレースを出力するようにして、http://localhost/test.php を投稿先とし、test.php には OK とのみ書いておきます。

Progress が必要な場合は、wr.AllowWriteStreamBuffering = false; と wr.SendChunked = true; を実行して、ファイルを書き込むループ内で処理するか、そこから外部へのイベントを作成すれば良いと思います。

ここでは、409600 というバッファのサイズにあまり意味はありませんが、どの程度のサイズのファイルのアップロードの Progress をテストするかによって、考慮する必要が出て来ると思います。しかし、実装段階での効率の良いサイズとしては、大きすぎず、小さすぎず程度でいいと思います。

Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using LBOX_Tool;
using System.Net;

namespace Twitter_Post_with_Media_test1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.FileName = "";
            ofd.Filter = "JPEG|*.jpg;*.jpeg";
            ofd.FilterIndex = 0;

            if (ofd.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            VS2010_Twitter twitter =
                new VS2010_Twitter(
                    "Consumer key",
                    "Consumer secret",
                    "Access token",
                    "Access token secret"
                );

            twitter.TwitterImageUploadResult += (object _sender, VS2010_Twitter.TwitterImageUploadArgs _e) =>
            {
                this.textBox2.Text = _e.Message;
            };

            twitter.Tweet(this.textBox1.Text, ofd.FileName);

        }
    }
}



VS2010_Twitter.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Net;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace LBOX_Tool
{
    class VS2010_Twitter
    {
        private string _consumer_key;
        private string _consumer_secret;
        private string _token;
        private string _secret;
        private SynchronizationContext sc = null;

        // API 1.1 における最新の URL
        private string _tweet_api = "https://api.twitter.com/1.1/statuses/update_with_media.json";

        // イベント引き渡し用クラス
        private class MyParam
        {
            public WebRequest wr;
            public string image_path;
            public string strBoundary;
            public string text;
        }

        public VS2010_Twitter(
            string consumer_key,
            string consumer_secret,
            string token,
            string secret
            )
        {
            _consumer_key = consumer_key;
            _consumer_secret = consumer_secret;
            _token = token;
            _secret = secret;
        }

        public void Tweet(string text, string path)
        {
            // UI スレッドに戻る為のコンテキスト
            sc = SynchronizationContext.Current;

            // ソートされるリスト
            SortedList<string, string> sl = new SortedList<string, string>();
            sl.Add("oauth_consumer_key", _consumer_key);
            sl.Add("oauth_nonce", Nonce());
            sl.Add("oauth_signature_method", "HMAC-SHA1");
            sl.Add("oauth_timestamp", TimeStamp());
            sl.Add("oauth_token", _token);
            sl.Add("oauth_version", "1.0");
            // 画像投稿では、以上で認証用のデータを作成する( status は使用できない )

            // http ヘッダ用シグネチャ作成
            string work = "";
            foreach (KeyValuePair<string, string> kvp in sl)
            {
                if (work != "")
                {
                    work += "&";
                }
                work += kvp.Key + "=" + kvp.Value;
            }

            string work2 = "";
            // メソッド
            work2 += "POST" + "&";
            // API URL
            work2 += Uri.EscapeDataString(_tweet_api) + "&";
            // Oauth + データ
            work2 += Uri.EscapeDataString(work);

            // OAuth tool チェック用
            Debug.WriteLine(work2);

            string oauth_signature = Signature(work2);

            // ヘッダ情報を作成
            work = "";
            foreach (KeyValuePair<string, string> kvp in sl)
            {
                // oauth_* のみを使用する
                if (work != "")
                {
                    if (kvp.Key.Substring(0, 6) == "oauth_")
                    {
                        work += ", ";
                    }
                }
                if (kvp.Key.Substring(0, 6) == "oauth_")
                {
                    work += kvp.Key + "=" + Dd(kvp.Value);
                }
            }
            // シグネチャを追加( ヘッダーはソートの必要は無い )
            work += ", oauth_signature=" + Dd(Uri.EscapeDataString(oauth_signature));

            // OAuth tool チェック用
            Debug.WriteLine(work);

            // 投稿準備(1)
            string strBoundary = DateTime.Now.Ticks.ToString("x");
            HttpWebRequest wr = (HttpWebRequest)HttpWebRequest.Create(_tweet_api);
            // 生データをチェックしたい場合
            // HttpWebRequest wr = (HttpWebRequest)HttpWebRequest.Create("http://localhost/test.php");
            // Progress が必要な場合
            //wr.AllowWriteStreamBuffering = false;
            //wr.SendChunked = true;

            // HttpWebRequest の基本部分の設定
            wr.Method = "POST";
            wr.ContentType = "multipart/form-data; boundary=---" + strBoundary;
            wr.Headers["Authorization"] = "OAuth " + work;

            // ストリームへの書き込みイベント
            AsyncCallback writeCallBack = new AsyncCallback(WriteCallBack);
            MyParam myParam = new MyParam() { wr = wr, image_path = path, strBoundary = strBoundary, text = text };
            // 呼び出し
            IAsyncResult iar1 = wr.BeginGetRequestStream(writeCallBack, myParam);

        }

        // 書き込み
        public void WriteCallBack(IAsyncResult ar)
        {
            HttpWebRequest req = (HttpWebRequest)(ar.AsyncState as MyParam).wr;
            string path = (ar.AsyncState as MyParam).image_path;
            string strBoundary = (ar.AsyncState as MyParam).strBoundary;
            string text = (ar.AsyncState as MyParam).text;

            // 書き込み用のストリーム
            Stream sw = req.EndGetRequestStream(ar);

            // ▼ 以下、Twitter のドキュメントサンプル
            //--cce6735153bf14e47e999e68bb183e70a1fa7fc89722fc1efdf03a917340
            //Content-Disposition: form-data; name="status"
            //
            //Hello 2012-09-07 15:51:41.375247 -0700 PDT!
            //--cce6735153bf14e47e999e68bb183e70a1fa7fc89722fc1efdf03a917340
            //Content-Type: application/octet-stream
            //Content-Disposition: form-data; name="media[]"; filename="media.png"
            //...
            //--cce6735153bf14e47e999e68bb183e70a1fa7fc89722fc1efdf03a917340--

            // 書き込み処理
            Encoding encoding = Encoding.ASCII;
            // セクション(1) / 日本語投稿本文
            Byte[] content = encoding.GetBytes("-----" + strBoundary + "\r\n");
            sw.Write(content, 0, content.Length);

            content = encoding.GetBytes("Content-Disposition: form-data; name=\"status\"\r\n\r\n");
            sw.Write(content, 0, content.Length);

            content = Encoding.GetEncoding("UTF-8").GetBytes(text + "\r\n");
            sw.Write(content, 0, content.Length);

            // セクション(2) / 生バイナリ画像部分
            content = encoding.GetBytes("-----" + strBoundary + "\r\n");
            sw.Write(content, 0, content.Length);

            content = encoding.GetBytes("Content-Type: application/octet-stream\r\n");
            sw.Write(content, 0, content.Length);

            content = encoding.GetBytes("Content-Disposition: form-data; name=\"media[]\"; filename=\"media.jpg\"\r\n\r\n");
            sw.Write(content, 0, content.Length);

            // ファイルのバイナリデータ( バッファサイズの大きさにあまり意味はありません )
            FileStream fs = new FileStream(path, FileMode.Open);
            int buffer_len = 409600;
            long length = 0;
            int read_size = 0;
            byte[] file_data = new byte[buffer_len];
            while ((read_size = fs.Read(file_data, 0, buffer_len)) > 0)
            {
                length += read_size;
                Debug.WriteLine("writing...." + length);
                sw.Write(file_data, 0, read_size);
                if (read_size < buffer_len)
                {
                    break;
                }
            }
            fs.Close();
            fs.Dispose();

            // multipart の終了
            content = encoding.GetBytes("\r\n-----" + strBoundary + "--\r\n");
            sw.Write(content, 0, content.Length);

            sw.Close();
            sw.Dispose();

            // 最終的なレスポンスの取得
            AsyncCallback readCallBack = new AsyncCallback(this.ReadCallBack);
            IAsyncResult iar2 = req.BeginGetResponse(readCallBack, req);

        }

        // 読み込み
        public void ReadCallBack(IAsyncResult ar)
        {
            string result = "";

            HttpWebRequest req = (HttpWebRequest)ar.AsyncState;
            HttpWebResponse response = null;
            // ここで時々接続が切られたりします 
            try
            {
                response = (HttpWebResponse)req.EndGetResponse(ar);

                Encoding enc = System.Text.Encoding.GetEncoding("UTF-8");
                StreamReader sr = new StreamReader(response.GetResponseStream(), enc);

                result = sr.ReadToEnd();
                Debug.WriteLine(result);
                sr.Close();
                sr.Dispose();
            }
            catch (Exception ex)
            {
                result = ex.Message;
                Debug.WriteLine(result);
            }

            // 内部のイベントの呼び出し( 最終的なイベントを UI スレッドで実行させる )
            sc.Post((object state) => { OnTwitterImageUploadResult(new TwitterImageUploadArgs(result)); }, null);

        }

        // ***************************************************
        // カスタムイベント用引数
        // ***************************************************
        public class TwitterImageUploadArgs : EventArgs
        {
            // 引数の保存エリア
            private string message;
            // コンストラクタ
            public TwitterImageUploadArgs(string s)
            {
                message = s;
            }

            // 引数取り出し用のプロパティ
            public string Message
            {
                get { return message; }
            }
        }

        // ***************************************************
        // カスタムイベントハンドラの定義 ( EventHandler<T> )
        // ***************************************************
        public event EventHandler<TwitterImageUploadArgs> TwitterImageUploadResult;

        // ***************************************************
        // 外部へイベントを発行する為の内部メソッドの定義( virtual )
        // ***************************************************
        protected virtual void OnTwitterImageUploadResult(TwitterImageUploadArgs e)
        {
            EventHandler<TwitterImageUploadArgs> handler = TwitterImageUploadResult;

            // イベントが外部で実装されている場合、そのイベントを呼び出す
            if (handler != null)
            {
                handler(this, e);
            }
        }

        // ダブルクォートで挟む
        private string Dd(string base_string)
        {
            return "\"" + base_string + "\"";
        }

        private string Nonce()
        {
            Random rand = new Random();
            int nonce = rand.Next(1000000000);
            return nonce.ToString();
        }

        // タイムスタンプ
        private string TimeStamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }

        // シグネチャ
        private string Signature(string target)
        {
            string work = _consumer_secret + "&" + _secret;
            byte[] bin = Encoding.UTF8.GetBytes(target);

            HMACSHA1 hmacsha1 = new HMACSHA1();
            hmacsha1.Key = Encoding.UTF8.GetBytes(work);
            byte[] hash = hmacsha1.ComputeHash(bin);

            return Convert.ToBase64String(hash);
        }

    }

}

関連する記事Twitter API 1.1 : POST statuses/update_with_media / 画像付き投稿 -- の注意事項Windows Phone から Facebook に画像アップロード


posted by lightbox at 2013-07-18 04:37 | VS(C#) | このブログの読者になる | 更新情報をチェックする

2013年07月14日


Formアプリ(C#) でFacebookにログインして60日間のアクセストークンを取得して投稿



JSON の処理は行っていませんが、Json.NET がおすすめです

投稿ボタンとテキストエリアは、コントロールの modifiers を public にしているので Form2 より参照可能です。

Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;

namespace Facebook_POST
{
    public partial class Form1 : Form
    {
        public static string app_id = "App ID";
        public static string app_secret = "App Secret";
        public string url_api = "https://www.facebook.com/dialog/oauth/?redirect_uri=http://www.facebook.com/connect/login_success.html&response_type=token&client_id="+app_id+"&scope=user_about_me,user_photos,read_stream,publish_stream";
        public string access_token = null;
        public Form2 login = null;

        public Form1()
        {
            InitializeComponent();
        }

        // ***************************************************************
        // 投稿
        // ***************************************************************
        private void button1_Click(object sender, EventArgs e)
        {
            VS2010_Facebook facebook =
                new VS2010_Facebook(
                    app_id,
                    app_secret,
                    access_token
                );

            // ただ投稿するだけなら twitter.Tweet(this.textBox1.Text);
            facebook.Post(this.textBox1.Text, (object _sender, UploadStringCompletedEventArgs _e) =>
            {
                if (_e.Error == null)
                {
                    // JSON
                    String stringResult = _e.Result;
                    MessageBox.Show(_e.Result);
                }
                else
                {
                    MessageBox.Show("通信エラーが発生しました。\r\n" + _e.Error.Message);
                }

            });

        }

        // ***************************************************************
        // ログインダイアログを開く
        // ***************************************************************
        private void button2_Click(object sender, EventArgs e)
        {
            login = new Form2();
            login.ShowDialog(this);
        }
    }
}



ログインは、WebBrowser コントロールで行います。上の画像では、フォームを親コンテナとしてドッキングしています。実際には、ログイン済みなのかまたは、アクセストークンを保存して使う等の実装が必要ですが、ここでは必ずログインし、ログインが成功する事を前提として、Form1 から投稿を行うようになっています。

Form2.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Net;

namespace Facebook_POST
{
    public partial class Form2 : Form
    {
        // 親フォーム参照用の変数
        private Form1 owner = null;

        public Form2()
        {
            InitializeComponent();
        }

        // ***************************************************************
        // 初期処理
        // ***************************************************************
        private void Form2_Load(object sender, EventArgs e)
        {
            // 初期処理として、親フォーム参照用の変数をセット
            owner = this.Owner as Form1;
            // ログイン用のページを表示
            this.webBrowser1.Navigate(new Uri(owner.url_api));
        }

        // ***************************************************************
        // 2時間有効なアクセストークンを取得
        // ***************************************************************
        private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            string url = e.Url.ToString();
            if (url.IndexOf("access_token") != -1)
            {
                Debug.WriteLine(url);
                string target_line = url.Substring(url.IndexOf("access_token"));
                string[] separators = new string[1];
                separators[0] = "&";
                string[] part_string = target_line.Split(separators, System.StringSplitOptions.RemoveEmptyEntries);

                Dictionary<string, string> dic = new Dictionary<string, string>();
                separators[0] = "=";
                string[] part_values = null;
                part_values = part_string[0].Split(separators, System.StringSplitOptions.RemoveEmptyEntries);
                dic.Add(part_values[0], part_values[1]);
                part_values = part_string[1].Split(separators, System.StringSplitOptions.RemoveEmptyEntries);
                dic.Add(part_values[0], part_values[1]);

                // 60日間有効なアクセストークンを取得する為の処理
                WebClient webClient = new WebClient();

                webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(get_Token60);
                // 60日間有効なアクセストークンを取得する API
                url = String.Format("https://graph.facebook.com/oauth/access_token?client_id={0}&client_secret={1}&grant_type=fb_exchange_token&fb_exchange_token={2}",
                    Form1.app_id,
                    Form1.app_secret,
                    dic["access_token"]);

                // 呼び出し
                webClient.DownloadStringAsync(new Uri(url));
            }

        }

        // ***************************************************************
        // 60日間有効なアクセストークンを取得
        // ***************************************************************
        private void get_Token60(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                    Debug.WriteLine(e.Error.Message);
            }
            else
            {
                string new_token_line = e.Result;
                Debug.WriteLine(new_token_line);

                string[] separators = new string[1];
                separators[0] = "&";
                string[] part_string = new_token_line.Split(separators, System.StringSplitOptions.RemoveEmptyEntries);

                Dictionary<string, string> dic = new Dictionary<string, string>();
                separators[0] = "=";
                string[] part_values = null;
                part_values = part_string[0].Split(separators, System.StringSplitOptions.RemoveEmptyEntries);
                dic.Add(part_values[0], part_values[1]);
                part_values = part_string[1].Split(separators, System.StringSplitOptions.RemoveEmptyEntries);
                dic.Add(part_values[0], part_values[1]);

                Debug.WriteLine(dic["access_token"]);

                owner.access_token = dic["access_token"];

                WebClient webClient = new WebClient();

                webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(get_UserInfo);
                string url = String.Format("https://graph.facebook.com/me?access_token={0}",
                    dic["access_token"]);

                webClient.DownloadStringAsync(new Uri(url));
            }
        }

        // ***************************************************************
        // ユーザ情報を取得
        // ( 投稿するだけなら必要ありません )
        // ***************************************************************
        private void get_UserInfo(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                    Debug.WriteLine(e.Error.Message);
            }
            else
            {
                Debug.WriteLine(e.Result);

                // 全ての処理が終わったのでメインページへ戻る
                // ( コントロールの modifiers を public にしているので参照可能 )
                owner.button1.Enabled = true;
                owner.textBox1.Enabled = true;

                // ダイアログを閉じる
                this.Close();
            }
        }

    }
}


VS2010_Facebook.cs

このクラスは実際には、POST しているだけです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;

namespace Facebook_POST
{
    class VS2010_Facebook
    {
        private string _app_key;
        private string _app_secret;
        private string _token;

        private string _tweet_api = "https://graph.facebook.com/me/feed";

        public VS2010_Facebook(
            string app_key,
            string app_secret,
            string token
            ) {
                _app_key = app_key;
                _app_secret = app_secret;
                _token = token;
        }

        public void Post(string text,UploadStringCompletedEventHandler newEvent=null)
        {

            WebClient wc = new WebClient();

            if (newEvent != null)
            {
                wc.UploadStringCompleted += newEvent;
            }

            wc.Headers["Content-Type"] = "application/x-www-form-urlencoded";

            // 投稿
            wc.UploadStringAsync(new Uri(_tweet_api), 
                "POST", 
                "message=" + Uri.EscapeDataString(text) + "&access_token=" + _token ); 

        }
    }
}





posted by lightbox at 2013-07-14 00:12 | VS(C#) | このブログの読者になる | 更新情報をチェックする

2013年07月12日


Live SDK v5.4 : VS2012(C#) + Form アプリ / ファイルアップロード

SkyDrive へ移動( VS2012 用テンプレート )




VS2010 では動作しませんでした。

SkyDrive でアプリを作成して、クライアント ID を取得して使用します。
Form1.cs
using Microsoft.Live;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
	public partial class Form1 : Form
	{
		public LiveAuthClient auth;
		public LiveConnectClient lcc = null;
		private CancellationTokenSource ctsUpload = new CancellationTokenSource();

		public Form1()
		{
			InitializeComponent();
		}

		// ログイン結果より、セッションを作成
		private async void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
		{
			// リダイレクトされた URL の処理
			string url = e.Url.ToString();
			string[] param = url.Split(new string[] { "=", "&" }, StringSplitOptions.None);
			Debug.WriteLine(param);

			// ( テスト的な方法 )
			// リダイレクトされた結果の中で、必要な情報が含まれる処理を対象とする
			if (param[2] == "lc")
			{
				Debug.WriteLine(auth.Session);
				var target = await auth.ExchangeAuthCodeAsync(param[1]);
				Debug.WriteLine(auth.Session);
				// セッションの作成
				lcc = new LiveConnectClient(target);

				// テスト的な情報表示
				Debug.WriteLine(lcc.Session);
				var Result = await lcc.GetAsync("me/skydrive/files");
				Debug.WriteLine(Result.RawResult);

				// アップロード用の参照ボタンを有効にする
				this.button2.Enabled = true;

			}
		}

		// ログイン処理をブラウザ内で行う
		private void button1_Click(object sender, EventArgs e)
		{
			auth = new LiveAuthClient("クライアント ID");
//			auth.IntializeAsync();
			string url = auth.GetLoginUrl(new string[] { "wl.signin", "wl.basic", "wl.skydrive_update" });
			Debug.WriteLine(url);
			// WebBrowser でログイン画面を表示
			this.webBrowser1.Navigate(url);
		}

		// ファイルを参照してアップロード
		private async void button2_Click(object sender, EventArgs e)
		{
			this.openFileDialog1.Filter = "すべて|*.*";
			this.openFileDialog1.FilterIndex = 0;
			DialogResult dr = this.openFileDialog1.ShowDialog();
			if (dr == System.Windows.Forms.DialogResult.OK)
			{
				// 中止ボタンを有効にする
				this.button3.Enabled = true;
				// 選択されたファイルのパス
				string FileName = Path.GetFileName(openFileDialog1.FileName);
				Debug.WriteLine(openFileDialog1.FileName + "をアップロードします");

				// トークンにキャンセル直後の処理を登録
				ctsUpload.Token.Register(() =>
				{
					Debug.WriteLine("キャンセルされました");
				});

				// 経過処理用プライベートクラス
				ProgressUpload pu = new ProgressUpload();
				// アップロードが正常終了した時の戻り値
				LiveOperationResult Result = null;

				// キャンセルすると、WebException が発生
				try
				{
					Result = await lcc.UploadAsync(
						"me/skydrive",
						FileName,
						File.OpenRead(openFileDialog1.FileName),
						OverwriteOption.Overwrite,
						ctsUpload.Token,
						pu
					);
				}
				catch (Exception ex)
				{
					Debug.WriteLine(ex.Message);
				}

				// トークンより、キャンセルを判断
				if (ctsUpload.Token.IsCancellationRequested)
				{
					MessageBox.Show("アップロードはキャンセルされました");
				}
				else
				{
					// 正常終了
					Debug.WriteLine(Result.RawResult);
					MessageBox.Show("アップロードしました");
				}
			}
		}

		// 経過処理用のクラス
		private class ProgressUpload : IProgress<LiveOperationProgress> {
			public void Report(LiveOperationProgress value) {
				Debug.WriteLine(value.ProgressPercentage);
			}
		}

		// キャンセル
		private void button3_Click(object sender, EventArgs e)
		{
			ctsUpload.Cancel();
		}
	}
}

関連する記事

わりと簡単に作れるので、SkyDrive の運用はアプリケーションを作ると便利になると思います。Windows ストアの場合はもっと統合されているのですが、現状では落ちるので使えません。
Windows8 ストアアプリは、年額4900円を払って登録しないと専用の API は使用できません。
Live SDK v5.4 : VS2010 + Windows Phone / 画像アップロード
posted by lightbox at 2013-07-12 19:55 | VS(C#) | このブログの読者になる | 更新情報をチェックする

Live SDK v5.4 : VS2010 + Windows Phone / 画像アップロード

VS2010 で動いたのは、Windows Phone だけでした。Form アプリで動作させるには、VS2012 が必要なようです。( VS2010 で、一部、情報の参照は動いたのですが、アップロードやダウンロードという一番必要なものが落ちました。dll が足らないとか言われます。しかし、VS2012 では同じものが動作しています )

Microsoft のドキュメントは、どれもこれも微妙にウソでした。

my:SignInButton の追加は、コントロールの Toolbox の『Windows Phone コントロール』で右クリックして『アイテムの選択』で、Program Files 内の "Microsoft SDKs\Live\v5.4\Windows Phone 7.1\References\Microsoft.Live.Controls.dll" を読み込んで使います。

というか、そもそも、Windows8 ストアで動かすとログイン完了で落ちます
( Win8 ストアでは、Login する為の単独メソッドがあり、パスワードを間違うとちゃんと反応しますが、ログインがうまく行くと落ちます )
Windows8 ストアアプリは、年額4900円を払って登録しないと専用の API は使用できません。
コード内で使うクラスは、Microsoft.Live.dll を参照します。 Micrsoft のドキュメントでは、同様のものが Windows ストアにもあるような記述がされているのですが、Live SDK v5.4 ではみあたりません。 MainPage.xaml
<phone:PhoneApplicationPage 
    x:Class="PhoneApp2.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True"
    xmlns:my="clr-namespace:Microsoft.Live.Controls;assembly=Microsoft.Live.Controls">

    <!--LayoutRoot は、すべてのページ コンテンツが配置されるルート グリッドです-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel は、アプリケーション名とページ タイトルを格納します-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock
                x:Name="ApplicationTitle"
                Text="Live SDK v5.4"
                Style="{StaticResource PhoneTextNormalStyle}" />
            <TextBlock
                x:Name="PageTitle"
                Text="画像アップロード"
                Margin="9,-7,0,0"
                Style="{StaticResource PhoneTextTitle1Style}"
                FontSize="40"
                TextWrapping="Wrap" />
        </StackPanel>

        <!--ContentPanel - 追加コンテンツをここに入力します-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <my:SignInButton
                Content="Button"
                Height="101"
                HorizontalAlignment="Left"
                Margin="16,20,0,0"
                Name="signInButton1"
                VerticalAlignment="Top"
                Width="420"
                ClientId="自分のアプリのクライアントID"
                SessionChanged="signInButton1_SessionChanged"
                Scopes="wl.signin wl.basic wl.skydrive_update" />
            <TextBlock
                Height="301"
                HorizontalAlignment="Left"
                Margin="19,127,0,0"
                Name="infoTextBlock"
                VerticalAlignment="Top"
                Width="417"
                FontSize="22"
                TextWrapping="Wrap" />
            <Button
                Content="画像アップロード"
                Height="96"
                HorizontalAlignment="Left"
                Margin="19,434,0,0"
                Name="button1"
                VerticalAlignment="Top"
                Width="417"
                Click="button1_Click"
                IsEnabled="False" />
        </Grid>
    </Grid>
 
    <!--ApplicationBar の使用法を示すサンプル コード-->
    <!--<phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
            <shell:ApplicationBar.MenuItems>
                <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
            </shell:ApplicationBar.MenuItems>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>-->

</phone:PhoneApplicationPage>

MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Live;
using Microsoft.Phone.Tasks;
using System.Diagnostics;

namespace PhoneApp2
{
    public partial class MainPage : PhoneApplicationPage
    {

        private LiveConnectClient client;
        private LiveConnectSession session;

        // コンストラクター
        public MainPage()
        {
            InitializeComponent();
        }

        // ****************************************************
        // サインイン・ボタン
        // ****************************************************
        private void signInButton1_SessionChanged(object sender, 
            Microsoft.Live.Controls.LiveConnectSessionChangedEventArgs e)
        {
            if (e.Status == LiveConnectSessionStatus.Connected)
            {
                session = e.Session;
                client = new LiveConnectClient(session);
                infoTextBlock.Text = "サインイン";
                this.button1.IsEnabled = true;
            }
            else
            {
                infoTextBlock.Text = "未接続";
                client = null;
            }
        }

        // ****************************************************
        // 画像アップロードボタン
        // ****************************************************
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            // 画像参照オブジェクト
            var picker = new PhotoChooserTask();
            // 画像参照オブジェクトに選択完了のイベントを登録
            picker.Completed +=
                new EventHandler<PhotoResult>(Image_Selected);
            // 参照開始
            picker.Show();
        }

        // ****************************************************
        // 選択完了のイベント
        // ****************************************************
        private void Image_Selected(object sender, PhotoResult e)
        {
            if (e.Error != null)
            {
                this.infoTextBlock.Text = "画像選択エラー: " + e.Error.ToString();
            }
            else
            {
                // Windows Phone 内部のパスよりファイル名を取得
                //string[] filePathSegments = e.OriginalFileName.Split('\\');
                //string fileName = filePathSegments[filePathSegments.Length - 1];
                // SkyDrive を処理するオブジェクトにイベントを登録
                client.UploadCompleted
                    += new EventHandler<LiveOperationCompletedEventArgs>(Live_UploadCompleted);
                // ****************************************************
                // アップロード開始
                // ****************************************************
                client.UploadAsync("me/skydrive", 
                    "PhotoChooserTask.jpg", 
                    e.ChosenPhoto, 
                    OverwriteOption.Overwrite);
            }
        }

        // ****************************************************
        // アップロード完了
        // ****************************************************
        private void Live_UploadCompleted(object sender, LiveOperationCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                IDictionary<string, object> file = (IDictionary<string, object>)e.Result;
                this.infoTextBlock.Text = "File uploaded. Link: " + file["source"];

                foreach (var key in file.Keys)
                {
                    Debug.WriteLine(string.Format("KEY : {0} => VALUE : {1}", key, file[key]));
                }
                
            }
            else
            {
                this.infoTextBlock.Text =
                    "Error uploading file: " + e.Error.ToString();
            }
        }

    }
}


Windows Phone エミュレータでは、『Pause』キーで、キーボードから英数字が入力可能になります。しかし、US キーボード配置なので、@ は、SHIFT+(2 " ふ) で、_ は、SHIFT+(- = ほ) です。
( CTRL+ でも動作するようです )









アプリは、SkyDrive のページの一番下にある『開発者向け情報(英語)』より登録して、『モバイル クライアント アプリ』を『はい』に設定しておきます。VS2012 で、Form アプリからアクセスする場合もこの設定が必要です。



※ Android でテストした時のアプリをそのまま使っています




posted by lightbox at 2013-07-12 19:00 | Windows Phone | このブログの読者になる | 更新情報をチェックする

Google Chrome 拡張の『instant translate』という翻訳機能の翻訳ウインドウを大きくする

バグもある上に、元々の大きさが小さすぎて長い文章の翻訳結果がとても読みにくいので CSS を変更して大きくしました。

instant translate



▼ 対象ファイル
C:\Users\ユーザ名\AppData\Local\Google\Chrome\User Data\Default\Extensions\ihmgiclibbndffejedjimfjmfoabpcke\1.8.1_0\resources\styles\ui_components\tooltip\helpSelected.css
/* Local ID ? mndocdiojkckhpnhpeminpalidafeink */
/* Web Store ID ? ihmgiclibbndffejedjimfjmfoabpcke */

.TnITTtw-help-selected-wrap {
  border: 1px solid #C7C6C2;
  box-shadow: 0 0 10px rgba(43, 43, 43, 0.325);
  border-radius: 4px;
  width: 431px
}

  .TnITTtw-help-inside-layout {
    height: 433px;
    background: #F5F5F5;
    border-radius: 3px
  }

    .TnITTtw-left-particle {
      border-top-left-radius: 4px;
      border-bottom-left-radius: 4px;
      box-shadow: inset 0 1px 0 white;
      color: #4E4E4E;
      text-shadow: 0 1px 0 white;
      width: 394px;
      display: inline-block;
      border-right: 1px solid #D9D9D9
    }

      .TnITTtw-content-layout {
        text-align: left;
        margin: 10px 15px
      }

        .TnITTtw-variant-bunch-wrap {

        }

          .TnITTtw-variant-bunch-wrap .inside-layout {

          }

            .TnITTtw-main-variant-wrap {

            }

              .TnITTtw-main-variant {
                font-weight: 700;
                font-size: 15px;
                text-shadow: 0 1px 0 rgba(255, 255, 255, 0.775);
                display: inline-block;
                vertical-align: top;
                color: #2B2B2B
              }

            .TnITTtw-variants-by-pos {
              
            }

              .TnITTtw-TnITTtw-variant-row {
                text-shadow: 0 1px 0 rgba(255, 255, 255, 0.775)
              }

                .TnITTtw-v-pos {
                  font-weight: 700;
                  margin-top: 10px;
                  font-size: 12px;
                  color: #545454
                }

                  .TnITTtw-v-pos:first-child {
                    margin-top: 8px
                  }

                .TnITTtw-v-closest-wrap {
                  font-size: 13px;
                  color: #4E4E4E
                }

                  .TnITTtw-v-item {
                    display: inline-block
                  }

        .TnITTtw-listen-disabled {
          opacity: 0.475;
          cursor: default
        }

    .TnITTtw-right-particle {
      background: rgba(255, 255, 255, 0.125);
      border-top-right-radius: 4px;
      border-bottom-right-radius: 4px;
      display: inline-block;
      width: 36px;
      height: 433px;
      vertical-align: top;
      box-shadow: inset 1px 0 3px rgba(43, 43, 43, 0.05), inset 0 1px 0 #F5F5F5
    }

      .TnITTtw-sidebar {

      }

        .TnITTtw-sbutton {
          position: absolute;
          -webkit-user-select: none;
          cursor: pointer
        }

        .TnITTtw-listen-button {
          width: 16px;
          height: 17px;
          background: url(chrome-extension://ihmgiclibbndffejedjimfjmfoabpcke/resources/images/sprites/sprite.png);
          background-position: -54px 153px;
          margin: 10px 0 0 10px
        }

          .TnITTtw-listen-button:active, .TnITTtw-listen-disabled {
            background-position: -54px 136px
          }

/* ========== */
/* Scrollbars */

#TnITTtw-trVisibleLayout {
  position: relative !important;
  overflow: hidden;
  height: 433px;
  width: 100%
}

#TnITTtw-tr-scrollbar {
  position: absolute;
  display: block;
  width: 9px; 
  height: 435px; 
  font-size: 1px
}

#TnITTtw-track { 
  position: absolute;
  left: 385px;
  top: -434px;
  width: 11px;
  height: 429px;
  background: transparent
}

#TnITTtw-dragBar {
  position: absolute; 
  left: 1px;
  top: 1px;
  width: 5px; 
  height: 10px;
  background: rgba(43, 43, 43, 0.475);
  cursor: pointer;
  border-radius: 3px;
  box-shadow: 0 1px 0 #FFF
}

  #TnITTtw-dragBar:hover, #TnITTtw-dragBar:active {
    background: rgba(43, 43, 43, 0.775)
  } 

#TnITTtw-scrollbar, #TnITTtw-track, #TnITTtw-dragBar {
  -webkit-user-select: none
}

.TnITTtw-arrow {
  display: none;
  width: 12px;
  height: 6px;
  background: url(chrome-extension://ihmgiclibbndffejedjimfjmfoabpcke/resources/images/sprites/sprite.png);
  position: relative
}

.TnITTtw-top-arrow {
  background-position: -108px 148px;
  bottom: -1px
}

.TnITTtw-bottom-arrow {
  background-position: -108px 154px;
  top: -1px
}


posted by lightbox at 2013-07-12 00:10 | Google Chrome | このブログの読者になる | 更新情報をチェックする

2013年07月11日


PHP : Twitter 投稿関数( twitter_update ) / cURL 関数

cURL 関数を使った単純な投稿用です。( windows では、php.ini で extension=php_curl.dll を有効にして下さい )

<?php
header("Content-type: text/html; charset=utf-8");

$result = twitter_update(
		"Consumer key",
		"Consumer secret",
		"Access token",
		"Access token secret",
		"PHPより投稿しています"
);

print "<pre>";
print_r(json_decode($result));
print "</pre>";

// **********************************************************
// AOuth 用の urlencode 関数
// **********************************************************
function urle( $str ) {
	// php 5.3.x 〜 ではこの変換は必要無い
	return str_replace('%7E', '~', rawurlencode($str));
}

function twitter_update( $apikey, $secret, $token, $token_secret, $text ) {
	// **********************************************************
	// API
	// **********************************************************
	$twitter_url = 'https://api.twitter.com/1.1/statuses/update.json';
	
	// **********************************************************
	// 認証データ
	// **********************************************************
	$oauth_consumer_key = $apikey;
	$oauth_consumer_secret = $secret;
	$oauth_token = $token;
	$oauth_secret = $token_secret;
	
	// 毎回変化するランダムな文字列
	$mt = microtime();
	$rand = mt_rand();
	$oauth_nonce = md5($mt . $rand);
	
	$oauth_signature_method = "HMAC-SHA1";
	$oauth_timestamp = time();
	$oauth_version = "1.0";
	
	// *********************************************************
	// シグネチャ用ベース文字列作成
	/*
	  httpMethod + "&" +
	  url_encode(  base_uri ) + "&" +
	  sorted_query_params.each  { | k, v |
	      url_encode ( k ) + "%3D" +
	      url_encode ( v )
	  }.join("%26")
	*/
	// *********************************************************
	$base_string = "POST";
	$base_string .= "&" . urle($twitter_url);
	$base_string .= "&";
	
	$base_string .= urle("oauth_consumer_key")."%3D".urle($oauth_consumer_key)."%26";
	$base_string .= urle("oauth_nonce")."%3D".urle($oauth_nonce)."%26";
	$base_string .= urle("oauth_signature_method")."%3D".urle($oauth_signature_method)."%26";
	$base_string .= urle("oauth_timestamp")."%3D".urle($oauth_timestamp)."%26";
	$base_string .= urle("oauth_token")."%3D".urle($oauth_token)."%26";
	$base_string .= urle("oauth_version")."%3D".urle($oauth_version);
	
	$base_string .= "%26status" . "%3D" . urle(urle($text));
	
	// *********************************************************
	// シグネチャ作成
	/*
	url_encode( consumer_secret ) + "&" +
	url_encode( oauth_token_secret || nil )
	*/
	// *********************************************************
	$oauth_signature = 
	base64_encode( hash_hmac(
		"sha1",
		$base_string,
		$oauth_consumer_secret . "&" . $oauth_secret,
		true
	));
	
	// *********************************************************
	// curl 処理
	// *********************************************************
	$curl = curl_init();
	curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30);
	curl_setopt($curl, CURLOPT_HEADER, false);
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($curl, CURLOPT_BINARYTRANSFER, true);
	curl_setopt($curl, CURLOPT_URL, $twitter_url);
	curl_setopt($curl, CURLOPT_POST, 1);
	curl_setopt($curl, CURLOPT_POSTFIELDS, "status=" . urle($text));
	
	// *********************************************************
	// http ヘッダ作成
	// *********************************************************
	$header = array();
	$header[] = 'Expect:';
	
	$header[] = "Authorization: OAuth ".
	urle("oauth_consumer_key")."=\"".urle($oauth_consumer_key)."\",".
	urle("oauth_token")."=\"".urle($oauth_token)."\",".
	urle("oauth_nonce")."=\"".urle($oauth_nonce)."\",".
	urle("oauth_timestamp")."=\"".urle($oauth_timestamp)."\",".
	urle("oauth_signature_method")."=\"".urle($oauth_signature_method)."\",".
	urle("oauth_version")."=\"".urle($oauth_version)."\",".
	urle("oauth_signature")."=\"".urle($oauth_signature)."\"";
	
	curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
	
	// *********************************************************
	// https 用 ( https://api.twitter.com 利用時に必要 )
	// *********************************************************
	curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
	curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1);
	
	// *********************************************************
	// 戻された http ヘッダの出力
	// *********************************************************
	$handle = fopen("./header.txt", "w");
	curl_setopt($curl, CURLOPT_WRITEHEADER, $handle);
	
	// *********************************************************
	// 送信
	// *********************************************************
	$result = curl_exec($curl);
	
	// *********************************************************
	// 結果
	// *********************************************************
	$ret = true;
	if($result === false) {
		$ret = false;
	}
	curl_close($curl);

	return $result;

}
?>

関連する記事

Twitter API の自分のアプリのトークンを使って投稿するだけの class VS2010_Twitter

Twitter API の自分のアプリのトークンを使って投稿するだけの class Android_Twitter

Twitter API の自分のアプリのトークンを使って投稿するだけの class VS2012_Twitter

WSH : VBScript と JavaScript で Twitter に投稿する

Twitter アプリの登録方法と、API キーの利用


posted by lightbox at 2013-07-11 21:11 | PHP + Twitter | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します
container 終わり

フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

CSS ドロップシャドウの参考デモ
BUTTONS (CSS でボタン)
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり