焼きサンマ綺麗に食べるブログ

焼きサンマ食べたい

自分の発言をダウンロードしたくて

Twitterでの自分の発言をダウンロードしたくてコードを書いた。Archiveのダウンロードは無理っぽかったので、user_timelineをとってきてcronで回す方法に変更。

汎用性を持たせようと思ったのでコードが長くなった。いつもはDBIx::Class使っているけど、Loaderの設定とか面倒になったのでDBIを直にたたいてみたら終わるまで時間がかかってしまった。

以下コードのこと

最初書き忘れてしまったが、設定にはYAMLファイルを使います。第一引数にyamlファイルを指定してください。

username: ********
password: ********
db_file : hogehoge.sqlite3 (絶対パス推奨)
table:
  message: messages

あと、テーブルの仕様は以下のものでデータベースにはSQLiteを使っています。

CREATE TABLE messages (
id BIGINT PRIMARY KEY,
text TEXT,
created_at DATETIME );

一応このSQL文はMySQLでも通るはずです。未確認ですが。

以下コード

#!/usr/bin/env perl

use strict;
use warnings;
use Carp;
use utf8;

use encoding 'utf8';

use YAML::Syck;
use Net::Twitter;
use DateTime::Format::RSS;
use DateTime::Format::MySQL;
use SQL::Abstract;
use DBI;

use Readonly;
Readonly our %DEFAULT => (MESSAGE_TABLE => 'messages');

our $config = init_config( @ARGV );

{
    my $message_table = $config->{table}->{message};
    my $dbh = DBI->connect("dbi:SQLite:dbname=$config->{db_file}", '', '', { RaiseError => 1 });
    $dbh->{unicode} = 1;
    
    my $max_id = $dbh->selectrow_array("SELECT max(id) FROM $message_table");
    my $since = undef;
    if (defined $max_id ) {
        $since = $dbh->selectrow_array("SELECT created_at FROM $message_table WHERE id = $max_id") ;
    }
    
    my $twit = Net::Twitter->new(username => $config->{username},
                                 password => $config->{password});
    my $timeline = $twit->user_timeline( { id=> $config->{username}, count => 20, since => $since } );
    
    insert_timeline($dbh, $timeline) if (defined $timeline);
    
    $dbh->disconnect;
}

sub init_config {
    my ($config_filename, $db_file) = @_;
    unless (-e $config_filename) { die "Can not open $config_filename"; }
    
    my $config_file = LoadFile($config_filename);
    my $config = {};
    $config->{username} = $config_file->{username} || die 'Not input username';
    $config->{password} = $config_file->{password} || die 'Not input password';
    $config->{db_file} = $db_file || $config_file->{db_file} || die 'Not input DB File';
    unless (-e $config->{db_file} ) { die "Can not open $config->{db_file}"; }
    
    $config->{table} = {};
    if (defined $config_file->{table}) {
        $config->{table}->{message} = $config_file->{table}->{message} || $DEFAULT{MESSAGE_TABLE};
    }
    else {
        $config->{table}->{message} = $DEFAULT{MESSAGE_TABLE};
    }
    return $config;
}

sub insert_timeline {
    my $dbh = shift;
    my $timeline = shift;

    my $message_table = $config->{table}->{message};
    my $table_item = { id => 0, text => q//, created_at => q// };
    
    my $sql = SQL::Abstract->new;
    my ($stmt, @bind) = $sql->insert($message_table, $table_item);
    my $sth = $dbh->prepare($stmt);
    
    for my $item (@{$timeline}) {
        my $date = DateTime::Format::RSS->parse_datetime( $item->{created_at} );
        my $date_str = DateTime::Format::MySQL->format_datetime( $date );
        $table_item->{id} = $item->{id};
        $table_item->{text} = $item->{text};
        $table_item->{created_at} = $date_str;
        
        @bind = $sql->values( $table_item );
        $sth->execute(@bind);
    }
    $sth->finish;
}

1;
__END__