C++でしょぼいカレンダーから今日の放送予定作品を取得・表示する

みんなが愛しているBoostを使用。データ取得のコードは、公式ドキュメントにあるものを丸パクリしています(ぉ

github.com

やっていること

・しょぼいカレンダーの「cal_chk.php」にアクセスしてデータ取得
・XMLを解析
・構造体配列にぶち込む
・表示

以下、簡易版ソース。詳しくは上のGitHubからどうぞ。

#define XML_PATH "./cal_chk.php"

#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/foreach.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

using namespace std;
using namespace boost;
using namespace boost::asio::ip;
using namespace boost::property_tree;

struct AnimeList
{
    string title;
    string count;
    string sub_title;
    string st_time;
    string ch_name;
};

int main() {
    try
    {
        boost::asio::io_service io_service;

        tcp::resolver resolver( io_service );
        tcp::resolver::query query( "cal.syoboi.jp", "http" );
        tcp::resolver::iterator endpoint_iterator = resolver.resolve( query );
        tcp::resolver::iterator end;

        tcp::socket socket( io_service );
        boost::system::error_code error = boost::asio::error::host_not_found;
        while ( error && endpoint_iterator != end ) {
            socket.close( );
            socket.connect( *endpoint_iterator++, error );
        }
        if ( error ) {
            throw boost::system::system_error( error );
        }

        boost::asio::streambuf request;
        ostream request_stream( &request );
        request_stream << "GET /cal_chk.php?usr=hogehoge&days=1 HTTP/1.0\r\n";
        request_stream << "Host: cal.syoboi.jp\r\n";
        request_stream << "Accept: */*\r\n";
        request_stream << "Connection: close\r\n\r\n";

        boost::asio::write( socket, request );

        boost::asio::streambuf response;
        boost::asio::read_until( socket, response, "\r\n" );

        istream response_stream( &response );
        string http_version;
        response_stream >> http_version;
        unsigned int status_code;
        response_stream >> status_code;
        string status_message;
        getline( response_stream, status_message );
        if ( !response_stream || http_version.substr( 0, 5 ) != "HTTP/" ) {
            cout << "Invalid response\n";
            return 1;
        }
        if ( status_code != 200 ) {
            cout << "Response returned with status code " << status_code << "\n";
            return 1;
        }

        boost::asio::read_until( socket, response, "\r\n\r\n" );

        string header;
        while ( getline( response_stream, header ) && header != "\r" ) {
            /*cout << header << "\n";*/
        }
        /*cout << "\n";*/

        ofstream ofs( XML_PATH );

        if ( response.size() > 0 ) {
            ofs << &response;
        }

        while ( boost::asio::read( socket, response, boost::asio::transfer_at_least(1), error ) ) {
            ofs << &response;
        }
        if ( error != boost::asio::error::eof ) {
            throw boost::system::system_error( error );
        }
    } catch ( std::exception& e ) {
        cout << "Exception: " << e.what() << "\n";
    }

    AnimeList al[50];
    int num = 0;
    
    ptree pt;
    read_xml( XML_PATH, pt );
    
    const ptree & format = pt.get_child( "syobocal.ProgItems" );
    BOOST_FOREACH ( const ptree::value_type & child, format ) {
        const ptree & attributes = child.second.get_child( "<xmlattr>" );
        
        BOOST_FOREACH ( const ptree::value_type &value, attributes ){
            const char *cmp_title = "Title";
            const char *cmp_count = "Count";
            const char *cmp_sub_title = "SubTitle";
            const char *cmp_st_time = "StTime";
            const char *cmp_ch_name = "ChName";
            
            if ( strcmp( value.first.data( ), cmp_title ) == 0 ) {
                al[num].title = value.second.data( );
            } else if ( strcmp( value.first.data( ), cmp_count ) == 0 ) {
                al[num].count = value.second.data( );
            } else if ( strcmp( value.first.data( ), cmp_sub_title ) == 0 ) {
                al[num].sub_title = value.second.data( );
            } else if ( strcmp( value.first.data( ), cmp_st_time ) == 0 ) {
                string date = value.second.data( );
                date = date.substr( 8, 2 ) + ":" + date.substr( 10, 2 );
                al[num].st_time = date;
            } else if ( strcmp( value.first.data( ), cmp_ch_name ) == 0 ) {
                al[num].ch_name = value.second.data( );
            }
        }
        num++;
    }
    
    for ( int i = 0; i < num; i++ ) {
        cout << al[i].st_time << "\n";
        cout << al[i].title << " 第" << al[i].count << "話" << "『" << al[i].sub_title << "』 " << al[i].ch_name << "\n";
    }
    if ( remove( XML_PATH ) != 0 ) {
        cout << "Error deleting file\n";
    }
}

実行結果

[hoge@piyo ~]$ ./a.out
13:00
こどものおもちゃ 第67話『ニューヨークったらサスペンス』 アニマックス
13:30
ご近所物語 第14話『ピイちゃんパニック』 アニマックス
17:00
アイカツ!-アイドルカツドウ!- 第156話『YOU! GO! KYOTO!!』 BS Japan
17:29
かみさまみならい ヒミツのここたま 第4話『大ピンチ!出るに出られぬおシャキです!!』 BS Japan
18:00
世界でいちばん強くなりたい! 第話『#11~#12』 AT-X
18:25
おしりかじり虫(第4シリーズ) 第4話『大騒ぎ!?ドキドキパニックバザー』 NHK BSプレミアム
18:30
蟲師 第21話『綿胞子』 アニマックス
18:30
美少女戦士セーラームーン 第30話『お爺ちゃん乱心、レイちゃんの危機』 NHK BSプレミアム
19:00
ダイヤのA 第71話『9月の空の下』 キッズステーション
19:00
ガンダムビルドファイターズトライ 第9話『決戦のソロモン』 アニマックス
20:00
あずきちゃん 第82話『ジダマ様へ?名前のないラブレター』 AT-X
21:30
UFO戦士ダイアポロン 第11話『出た!!必殺デストロイの秘密』 AT-X
22:00
血界戦線 第7話『拳客のエデン』 アニマックス
22:30
魁!!男塾 第9話『塾長恐怖の思いつき オマエら明日から丸坊主だァ!!』 キッズステーション
23:00
這いよれ!ニャル子さん 第11話『星から訪れた迷い子』 キッズステーション
23:30
スタミュ 高校星歌劇 第3話『第3幕』 AT-X
00:00
終わりのセラフ(第2クール) 第15話『帝鬼軍のヤボウ』 BS11デジタル
00:30
スタミュ 高校星歌劇 第4話『第4幕』 BS11デジタル
00:00
アニソンCLUB! 第13話『「アニソンCLUB!-R」ゲスト:影山ヒロノブ』 BSフジ
01:00
進撃!巨人中学校 第4話『清掃!巨人中学校』 BS11デジタル
03:00
櫻子さんの足下には死体が埋まっている 第3話『夏に眠る骨』 BS11デジタル

このままだとアレすぎるので、ちゃんと書き直してgithubやらに上げます(予定)*1

あとは、AT-Xの連続放送みたいなのは、どうも話数が空になっているようで、サブタイトル内に「#11~#12」と入ってるみたい。おう、面倒臭い。

*1:2015.10.27:上げますた