ニコ生のコメントを取得 (実験用)

実験用なのでかなり汚いです。
コメントもないので参考にならないかもしれません。


■メインコード

namespace Samples

open RLib.Niconico.Net.Cookies
open RLib.Niconico.Net.NiconicoNet

open System
open System.IO
open System.Net.Sockets
open System.Xml
//open System.Xml.Linq
open System.Text

#nowarn "40"

module NiconicoCommentAsyncTest =
    let commSendData = "<thread thread=\"{0}\" version=\"20061206\" res_from=\"-1\"/>"
    let connect (id:string) (host:string) (port:int) =
        let toByte (text:string) =
            Array.append
                <| Encoding.UTF8.GetBytes(text)
                <| Array.zeroCreate 1
        let sendData =
            toByte <| System.String.Format(commSendData, id)
            |> (fun x -> x,0,x.Length)
        let client = new TcpClient()
        try
            client.Connect(host, port)
            use stream = client.GetStream()
            use out = new StreamWriter(stream, AutoFlush = true)
            use inp = new StreamReader(stream)
            stream.Write sendData
            let rec getComment l =
                match inp.Read() with
                | -1 -> []
                | 0 -> l
                | n -> getComment (l@[n])
            let rec seqComment =
                seq {
                    match (getComment []) with
                    | [] -> yield []
                    | l ->
                        yield l
                        yield! seqComment
                }
            seqComment
            |> Seq.map(List.map(char>>string)>>List.reduce(+))
            |> Seq.iter(printfn "%s")
        with
        | _ -> ()
        client.Close()
    /// (ステータス, 放送中ID, コメントサーバホスト, コメントサーバポート, スレッドID?)
    let getLiveIdAndComunity text =
        let xn s = System.Xml.Linq.XName.Get(s)
        let doc = System.Xml.Linq.XDocument.Parse text
        let root = doc.Element(xn "getplayerstatus")
        let status = (root.Attribute(xn "status").Value = "ok")
        let id = root.Element(xn "stream").Element(xn "id").Value
        let ms = root.Element(xn "ms")
        let address = ms.Element(xn "addr").Value
        let port = ms.Element(xn "port").Value
        let thread = ms.Element(xn "thread").Value
        (status, id, address, port, thread)
    let run() =
        let cookies = getTryCookie FolderType.Chrome
        if cookies.IsSome then
            // コミュニティのステータスを取得
            let xml =
                getStatus
                    <| (fun http ->
                            http.CookieContainer <- cookies.Value
                        )
                    <| "co1397033"
            // ステータスXMLからライブIDとコメントサーバなどを取得
            let (ret,id,host,port,thr) = getLiveIdAndComunity xml
            if ret then
                // ネットワーク接続 (同期)
                connect thr host (Int32.Parse(port))
                ()


■ RLib.Niconico.Net.Cookies

namespace RLib.Niconico.Net

open System
open System.Data
open System.Data.SQLite
open System.IO
open System.Net

(*
IE: 
Chrome: C:\Users\<ユーザ名>\AppData\Local\Google\Chrome\User Data\Default\Cookies
LocalApplicationData
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
*)
module Cookies =
    type FolderType = IE | FF | Chrome | OP | Sa

    let getChromeCookieSql = @"
SELECT creation_utc, host_key, name, value, path, expires_utc, secure, httponly, last_access_utc, has_expires, persistent
FROM cookies
WHERE (host_key LIKE '%nicovideo%')
"
    let getChromeCookie () =
        let a = @"Google\Chrome\User Data\Default\Cookies"
        let path =
            Environment.SpecialFolder.ApplicationData
            |> Environment.GetFolderPath
            |> (fun p -> Path.Combine(p,a))
        let cs =
            @"Data Source={0};Pooling=true;FailIfMissing=false"
            |> (fun s -> String.Format(s,@"D:\Cookies"))
        seq {
            use conn = new SQLiteConnection(cs)
            use cmd = new SQLiteCommand()
            cmd.CommandText <- getChromeCookieSql
            cmd.Connection <- conn
            conn.Open()
            use dr = cmd.ExecuteReader()
            while dr.Read() do
                let c = new Cookie()
                c.Domain <- dr.GetString(1)
                c.Name <- dr.GetString(2)
                c.Value <- dr.GetString(3)
                c.Path <- dr.GetString(4)
//                c.Expires <- new DateTime(dr.GetInt64(5), DateTimeKind.Utc)
//                c.Secure <- dr.GetInt32(6) = 0
//                c.HttpOnly <- dr.GetInt32(7) = 0
                yield c
        }

    let getCookie =
        let cc = new CookieContainer()
        function
        | Chrome  ->
            getChromeCookie()
            |> Seq.iter(fun c -> cc.Add(c))
            cc
        | _ -> failwith "未対応ブラウザです。"
    let getTryCookie ft =
        try
            Some(getCookie ft)
        with
        | _ -> None

namespace RLib.Niconico.Net

open System
open System.IO
open System.Net
open System.Net.Sockets
open System.Text

(*
http://live.nicovideo.jp/watch/lv86092947?ref=community
lv86092947
*)

/// 適当に作ったニコニコAPI呼び出し関数群(F#用)
module NiconicoNet =
    /// ニコニコAPIURLmodule NicoUrls =
        let Login = "https://secure.nicovideo.jp/secure/login?site=niconico"
        let Status = "http://live.nicovideo.jp/api/getplayerstatus?v={0}"
        let SendXml = "<thread thread=\"{0}\" version=\"20061206\" res_from=\"-{1}\"/>\0"

    /// 同期型 HTTP POST 送信
    /// f1: (HttpWebRequest -> unit)
    let sendHttp f1 (url:string) (html:string) =
        // コネクション取得
        let req =  WebRequest.Create(url) :?> HttpWebRequest
        // 設定処理用の関数を呼び出す。
        f1 req
        // データの送信
        if not(String.IsNullOrEmpty(html)) then
            let (data,len) =
                Encoding.ASCII.GetBytes(html)
                |> (fun x -> ((x, 0, x.Length),x.Length))
            req.ContentLength <- int64(len)
            use reqs = req.GetRequestStream()
            reqs.Write data
            reqs.Close()
        // データの受信
        use ress = req.GetResponse().GetResponseStream()
        use sr = new StreamReader(ress)
        let text = sr.ReadToEnd()
        sr.Close()
        ress.Close()
        // 結果を返す。
        text
    /// ニコニコへのログイン
    let nicoLogin f id pass =
        if String.IsNullOrWhiteSpace id then failwith "IDまたはPASSが指定されていません。"
        if String.IsNullOrWhiteSpace pass then failwith "IDまたはPASSが指定されていません。"
        sendHttp (fun a -> a.UserAgent <- "NiconicoFSharp"; f a)
            <| "https://secure.nicovideo.jp/secure/login?site=nicolive_antenna"
            <| (String.Format("mail={0}&password={1}", id, pass))
    /// ニコニコAPI:getplayerstatus を呼び出す。
    let getStatus f id =
        if String.IsNullOrWhiteSpace id then failwith "IDが指定されていません。"
        sendHttp (fun a -> a.UserAgent <- "NiconicoFSharp"; f a)
            <| String.Format(NicoUrls.Status, id)
            <| ""


■参考サイト
ニコニコ生放送・実況のコメントを取得 備忘録
ニコ生アラート(本家)の仕様とは
ニコ生アラート + コメントビューア + 1コメゲット ツールを作る(C#) その2
コメントクライアント PITA Blog.htm


    • -