VB.netでニコニコ静画に有る画像の拡張子を特定する方法

お久しぶりです。
今回はニコニコ静画に使えるネタを紹介します。

静画のAPI(一部)
殆どPIRA Blog参考にしました(http://pita.s374.xrea.com/blog/archives/94

※ココに書いてある[画像番号]とはim0000のimを取った0000の事を言う

原型サイズ http://seiga.nicovideo.jp/image/source?id=[画像番号]
表示用のサイズ http://lohas.nicoseiga.jp/img/[画像番号]l
http://lohas.nicoseiga.jp/thumb/[画像番号]i
サムネイル http://lohas.nicoseiga.jp/img/[画像番号]s
http://lohas.nicoseiga.jp/thumb/[画像番号]q アス比そのまま
http://lohas.nicoseiga.jp/thumb/[画像番号] アス比変わる

ニコニコから取れる画像の形式はjpg,png,gifの三種類
だが拡張子が付いてない

どの画像がどの拡張子かを判別する方法は2つ
①保存するときレスポンスヘッダのContent-Typeを見て判断する (昔この方法だった)
②画像のバイナリー文字列の先頭の文字で判断する (今回はこの方法)

こちらのサイトを参考しました
PNG, GIF, JPEG のバイナリーデータなどについて | ヨモツネット
http://www.yomotsu.net/wp/?p=504

ファイル先頭の文字列
バイナリー文字列 デコード後
PNG 89 50 4E 47 臼NG
GIF(89a) 47 49 46 38 39 61 GIF89a
GIF(87a) 47 49 46 38 37 61 GIF87a
JPEG FF D8 FF .リ.

こうなっているので簡単に判別ができる
ね?簡単でしょ?

以下ソース

        Dim url As String = "http://seiga.nicovideo.jp/image/source?id=[画像番号]"

        Dim wc As New System.Net.WebClient
        wc.Headers.Add("Cookie", "user_session=ユーザーセッション")

        Dim imageByte As Byte() = wc.DownloadData(url)
        Dim str As String = Nothing

        For index = 0 To 5
            Dim hoge As String = Convert.ToString(imageByte(index), 16) '16進数に変換
            str = str & " " & hoge
        Next
        str = str.ToUpper() 'すべて大文字にする
        Console.WriteLine("→" & str)

        If str.StartsWith(" 89 50 4E 47") = True Then
            Console.WriteLine("PNG")
        End If


        If str.StartsWith(" 47 49 46 38 39 61") = True Then
            Console.WriteLine("GIF(89a)")
        End If


        If str.StartsWith(" 47 49 46 38 37 61") = True Then
            Console.WriteLine("GIF(87a)")
        End If


        If str.StartsWith(" FF D8 FF") = True Then
            Console.WriteLine("JPEG")
        End If

VB.netでパケットキャプチャーを作ってみる

VB.netでパケットキャプチャーを作ってみる

[C#] System.Net.Sockets.Socketを使ってパケットモニタ (3)
こちらのサイトを参考にしました

目的
 ・開いたサイトのアドレスとかもリアルタイムで分かるのでコメントビューアに使いたかった
 ・通信内容が直で分かるので、ニコ生のゲットプレーヤーステータスが暗号化されてても接続できるようにする
です。

これが書いたソースです。

    Private Sub Test()
        Dim ip As String = "192.168.11.2"

        Dim socket As New Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP)

        socket.Bind(New IPEndPoint(IPAddress.Parse(ip), 0))
        socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AcceptConnection, True)
        socket.IOControl(IOControlCode.ReceiveAll, New Byte() {1, 0, 0, 0}, New Byte() {0, 0, 0, 0})

        Dim buffer As Byte() = New Byte(4096) {}
        Dim k As Integer

        Do
            socket.Receive(buffer)

            Dim message As String = Encoding.UTF8.GetString(buffer)
            'Console.WriteLine(message) '←何故かココでプログラムが止まってしまう。原因教えて下さい


            '送信元IP
            Dim source As String = String.Format("{0}.{1}.{2}.{3}", buffer(12), buffer(13), buffer(14), buffer(15))
            '送信先IP
            Dim destination As String = String.Format("{0}.{1}.{2}.{3}", buffer(16), buffer(17), buffer(18), buffer(19))


            If message.Contains("<chat") = True AndAlso source.Contains(ip) = False Then

                'For Each item As String In buffer
                '    Console.WriteLine(item)
                'Next

                Dim dstPort10 As String = Convert.ToString(buffer(22), 16) & Convert.ToString(buffer(23), 16)
                Dim srcPort10 As String = Convert.ToString(buffer(20), 16) & Convert.ToString(buffer(21), 16)
                Dim dstPort As Integer = Convert.ToInt32(dstPort10, 16)
                Dim srcPort As Integer = Convert.ToInt32(srcPort10, 16)


                Dim match = System.Text.RegularExpressions.Regex.Match(message, "thread=""(?<thread>[0-9]+)""")
                Dim thread As Integer = CInt(match.Groups("thread").Value)


                Console.WriteLine()
                Console.WriteLine(k)
                Console.WriteLine("送信元{0}  -  送信先{1}", source, destination)
                Console.WriteLine("ポート{0}  -  {1}", srcPort, dstPort)
                Console.WriteLine("スレッド{0}", thread)
                k = k + 1
            End If


        Loop
    End Sub

はいこれが、パケットキャプチャーのソースです。
以下説明

自分のIP

        Dim ip As String = "192.168.11.2"

messageの中にはパケットのバイナリ?をUTF-8でエンコードした物が一応入ってます。

Dim message As String = Encoding.UTF8.GetString(buffer)
'Console.WriteLine(message) '←何故かココでプログラムが止まってしまう。原因教えて下さい

bufferの中にパケットの16進数(バイナリ?)を10進数に直した1バイトが入ってます。
(写真1)

12,13,14,15 送信元
16,17,18,19 送信先アドレス
が.区切り?で入ってるのでIPの形に直して入れます。
(写真2)

            '送信元IP
            Dim source As String = String.Format("{0}.{1}.{2}.{3}", buffer(12), buffer(13), buffer(14), buffer(15))
            '送信先IP
            Dim destination As String = String.Format("{0}.{1}.{2}.{3}", buffer(16), buffer(17), buffer(18), buffer(19))

messageの中にコメントで使われる形式の”
っとなっているので、threadの値を正規表現で取ります。

                Dim match = System.Text.RegularExpressions.Regex.Match(message, "thread=""(?<thread>[0-9]+)""")
                Dim thread As Integer = CInt(match.Groups("thread").Value)

以上です。ありがとうございました。

VB.netで正規表現を使って文字列を見つける方法2

前回は正規表現で文字列を一つだけ取りましたね?

今回は全部取ってみたいと思います。

前回の続きで書いていきます。

まず、ボタン2を置きます。(無い場合はテキストボックスをフォームに置きます。)
前回読んだ人はスルーしてください。
テキストボックスには↓ココから

<li><a href="html/index.html">トップページ</a></li>
<li><a href="html/test.html">実験用テストページ</a></li>
<li><a href="hoge/index.html">テストのトップページ</a></li>
<li><a href="homu/homu.html">ほむほむ</a></li>

↑ココまで
を入れときます。

ボタン2のソースはこんな感じ

        '. $ ^ { [ ( | ) * + ?  を含む場合は、文字の前にをつける 例: (1)→((?<value>[0-9]*)
    
        '<li><a href="html/index.html">トップページ</a></li>
        Dim pattern As String = "<li><a href=""(?<url>.*)"">(?<text>.*)</a></li>"
        Dim m As Match = Regex.Match(TextBox1.Text, pattern, RegexOptions.IgnoreCase Or RegexOptions.Compiled)

        Do While m.Success

            Console.WriteLine("URL:{0}  -  タイトル:{1}", m.Groups("url").Value, _
                                                      m.Groups("text").Value)

            m = m.NextMatch()
        Loop

1
実行すると…

URL:html/index.html – タイトル:トップページ
URL:html/test.html – タイトル:実験用テストページ
URL:hoge/index.html – タイトル:テストのトップページ
URL:homu/homu.html – タイトル:ほむほむ

全部出てくれましたね!
こんな感じで、難しい事書かなくてもできます。

ね?簡単でしょ?

VB.netで正規表現を使って文字列を見つける方法1

今回は正規表現を使って文字を抜き出したいと思います。
次回は正規表現を使って複数の文字を抜き出したいと思います。

まず、ボタンとテキストボックスをフォームに置きます。
テキストボックスには↓ココから

<li><a href="html/index.html">トップページ</a></li>
<li><a href="html/test.html">実験用テストページ</a></li>
<li><a href="hoge/index.html">テストのトップページ</a></li>
<li><a href="homu/homu.html">ほむほむ</a></li>

↑ココまで
を入れときます。

ボタン1のソースはこんな感じ

        '. $ ^ { [ ( | ) * + ?  を含む場合は、文字の前にをつける 例: (1)→((?<value>[0-9]*)
    
        '<li><a href="html/index.html">トップページ</a></li>
        Dim matchText = Regex.Match(TextBox1.Text, _
                                    "<li><a href=""(?<url>.*)"">(?<text>.*)</a></li>")



        Console.WriteLine(matchText.Groups("url").Value)
        Console.WriteLine(matchText.Groups("text").Value)
        '↑↓どちらでもおk
        'Console.WriteLine(matchText.Groups(1).Value)
        'Console.WriteLine(matchText.Groups(2).Value)

実行すると…

html/index.html
トップページ

って出ますね、足りないですね!
このソースだと1つしか出せないのです。

次は、正規表現を使って複数の物を抽出してみましょう!

どうでしたか?意外と簡単でしょ?
正規表現の書き方などは他のサイトを参考にしてください。

VB.netでユニコードエスケープ(u~)を読めるようにしてみる

よくJSONなどで使われてる
「u5143u6c17u3067u3059u304buff1fuff01」
こんな奴。

ニコ動のAPIでエラーで帰ってる奴にこれが使われてたので、頑張って調べた結果…

分からなかった!(´・ω・`)

なので、5zjさんに教えてもらいましたw
コード

'u3042(あ)からuを抜いた文字列を入れる
Dim hoge As String = "3042"
Dim intData As Integer = Convert.ToInt32(hoge, 16)
Dim mozi As String = ChrW(intData)

終わり。

次は長い文字列から直してみる
作り方は簡単!文字列をuで区切ればいいだけ!
で、こうなった

        Dim mes As String = ""
        Dim txt As String = "u5143u6c17u3067u3059u304buff1fuff01"
        Dim stArrayData As String() = Split(txt, "u")

        For Each stData As String In stArrayData
            If stData.Length = 4 Then
                Dim intData As Integer = Convert.ToInt32(stData, 16)
                Dim mozi As String = ChrW(intData)
                'Console.WriteLine(mozi)
                mes = mes & mozi
            End If
        Next
        Console.WriteLine(mes)

実行すると、「元気ですか?!」って出てきてくるはずです。

出てきたら、終わりです。ありがとうございました。

余談で、

Dim hoge As String() = txt.Split(CChar("u"))

Dim hoge As String() = Split(txt, "u")

で結果が違った…気づくのに結構時間が掛かった…orz

【VB.net】CookieGetterSharpの使い方

①どっかからHalCookieGetterSharpを持ってきます。

②今のライブラリを追加します。
『プロジェクト』→『参照の追加』→参照タブからさっき持ってきたライブラリを追加します。

③クラスの外に

  Imports Hal.CookieGetterSharp

っと書きます

④次にクッキーを取ってくるコードを書きます

       '使うブラウザに応じて"GoogleChrome3"の部分を書き換えます。
       Dim cg = CookieGetter.CreateInstance(BrowserType.GoogleChrome3)
        If cg.Status.IsAvailable = False Then
            MessageBox.Show("ブラウザが確認できませんでした。")
            Exit Sub
        End If

        '"http://live.nicovideo.jp/"で使われるクッキーの"user_session"の値を取得します。
        Dim collection = cg.GetCookieCollection(New Uri("http://live.nicovideo.jp/"))
        Dim userSession = collection("user_session")

        Console.WriteLine(userSession.Value)

⑤VS2010以下の人は終わりです。
 後は煮るなり焼いたりゴニョゴニョします。

 VS2010以上の人は引き続き続きます

⑥.NET Framework 4だと動かないので、.NET Framework 3.5に落とします
 『プロジェクト』→『(何とか)のプロパティ』→『詳細コンパイル オプション』
  →『対象のフレームワーク(すべての構成)』→『.NET Framework 3.5』にします。

終わりです。

以上使い方でした。

ニコニコ生放送のコメント取ってみようぜ!3

Cookieを渡して getplayerstatus を取る方法

        Dim wc As New WebClient
        wc.Headers.Add("Cookie", "user_session=" & UserSessionValue)
        Dim enc As Encoding = Encoding.UTF8

    Dim liveID As String = "lv36190498"
        Dim data As Byte() = wc.DownloadData("http://live.nicovideo.jp/api/getplayerstatus?v=" & liveID)
        Dim res As String = enc.GetString(data)

        '0幅文字が含まれてるので消す(消さないと動かない)
        res = res.Replace("", "")

        Dim status = XDocument.Parse(res)
        threadId = status...<ms>...<thread>.Value
        messageServerPort = status...<ms>...<port>.Value
        messageServerAddress = status...<ms>...<addr>.Value

UserSessionValueの中に自分のユーザーセッションを記入してください、
自分は、Hal.CookieGetterSharpを使用しました。
CookieGetterSharpの使い方はいつか書きたいなーっと思ってます。

次は、コメントサーバーの仕様について書いて行きたいと思います。
自分の勝手な憶測なので、間違ってたらごめんなさい…

ニコニコ生放送のコメント取ってみようぜ!2

作るのに参考にしたサイト
とある技術の備忘録 – C#でニコ生からコメント取得
http://d.hatena.ne.jp/r7kamura/20091123/1258948977

NicoPITA Blog.
http://nicopita.info/NicoPITA/

今回は、VB.NET で作成していきます。

Imports System.Net.Sockets
Imports System.Text

Module Module1

    Sub Main()

        'http://watch.live.nicovideo.jp/api/getplayerstatus?v=lv何とか
        'msの値
        '取ってくるのはまた別に書くよ!
        Dim thread As Integer = 1062986843
        Dim addr As String = "msg102.live.nicovideo.jp"
        Dim port As Integer = 2813

        Dim more As String = ""
        'res_from で過去ログ取得 -10にすると、-10コメント前を取ってくる
        Dim req = String.Format("<thread thread=""{0}"" version=""20061206"" res_from=""-10"" /> ", thread)
        Dim tcp As New TcpClient(addr, Integer.Parse(port.ToString))
        Dim ns As NetworkStream = tcp.GetStream()
        Dim sendBytes As Byte() = Encoding.UTF8.GetBytes(req)
        sendBytes(sendBytes.Length - 1) = 0

        ns.Write(sendBytes, 0, sendBytes.Length)


        Dim resSize As Integer

        Do
            Dim resBytes As Byte() = New Byte(2048) {}

            resSize = ns.Read(resBytes, 0, resBytes.Length)
            If resSize = 0 Then
                Exit Do
            End If

            Dim message As String = Encoding.UTF8.GetString(resBytes)
            'Console.WriteLine(message)

            message = more & message
            more = ""
            Dim elements As String() = message.Split(New String() {vbNullChar}, StringSplitOptions.RemoveEmptyEntries)

            '<chat thread="1062986843" no="1" vpos="6300" date="1293718792" mail="184" user_id="mwR5e8FptFf6-O3gZtQ3ceHAgPU" premium="3" anonymity="1">テスト!</chat>

            For Each receiveData As String In elements

                '帰ってきたXMLに"<chat"から"</chat>"まで全部あったらで分ける
                '文字が多いいと、分割して帰ってくるから、
                If receiveData.StartsWith("<chat") AndAlso receiveData.EndsWith("</chat>") Then
                    OnReceiveChat(receiveData)
                Else
                    'チャットが分割で来たときの処理。
                    If receiveData.StartsWith("<thread resultcode=") = False Then
                        If receiveData.StartsWith("<view_counter") = True Then
                            'ここは、ニコニコ実況ようだから、スルーでおk
                        ElseIf receiveData.Contains("</chat>") = False Then
                            more = receiveData
                        End If
                    End If

                End If

            Next

        Loop While ns.CanRead
    End Sub

    Public Sub OnReceiveChat(ByVal receiveData As String)
        Dim commentNo As String
        Dim commentVpos As String
        Dim commentDate As String
        Dim commentMaill As String
        Dim commentUserID As String
        Dim commentPremium As String
        Dim commentAnonymity As String
        Dim commentText As String
        Dim commentThread As Integer
        Dim commentLoom As String = ""

        Dim userName As String = Nothing




        Dim comment = XElement.Parse(receiveData)
        commentNo = comment.@no
        commentDate = comment.@date
        commentVpos = comment.@vpos
        commentMaill = comment.@mail
        commentUserID = comment.@user_id
        commentPremium = comment.@premium

        '時々帰って来ない時がある。
        If commentPremium = Nothing Then
            commentPremium = "0"
        End If

        commentAnonymity = comment.@anonymity
        commentThread = CInt(comment.@thread)
        commentText = comment.Value



        'ユーザーレベル種分け
        If commentPremium = "0" Then
            commentPremium = "一般"
        ElseIf commentPremium = "1" Then
            commentPremium = "プレミアム"
        ElseIf commentPremium = "3" Then
            commentPremium = "放送主"
        ElseIf commentPremium = "7" Then
            commentPremium = "BSP"
        End If

        '0=一般
        '1=プレミアム
        '2=放送終了後に送られてくる、/disconnect のレベル
        '3=放送主
        '7=BSP

        '公式生見ると25とかある時がある。何故かはわからん

        Console.WriteLine("{0} : {1}", commentNo, commentText)
        'Console.Write(vbCrLf & CommentNo & " " & CommentVpos & " " & CommentDate & " " & CommentMaill & " " & CommentUserID & " " & CommentPremium & " " & CommentAnonymity & " " & CommentText)
 
    End Sub

End Module

お疲れ様でした 一応取得部分は完成です。
次は、getplayerstatusから値を取るコードを書きたいと思います。