音ネタ

Plagger向けのFilter::FetchEnclosure::Mplayerを書いた*1.これでenclosureをmplayerでwavファイルにダンプできる.ていうか,このプラグインだけだと何の役にも立たない.せめて,Filter::Convert::Lame*2のようなものが必要だ.

これは,enclosureで指定されたファイルがmplayerで再生できれば,その音声をwavにダンプできる.もとがmp3とかm4aなファイルならそんなことする必要はまったくないわけだが,動画やストリーミングでさえFetchできるのがこのプラグインの強みなわけ.

なんかアレゲプラグインな匂いがぷんぷんしますが気のせいでしょうか.

性懲りもなくソースコード貼付ける.本日もう眠いのでコレで勘弁.

package Plagger::Plugin::Filter::FetchEnclosure::Mplayer;
use strict;
use base qw(Plagger::Plugin::Filter::FetchEnclosure);

use POE;
use POE::Session;
use POE::Wheel::Run;

sub register {
    my($self, $context) = @_;
    $context->register_hook(
        $self,
        'update.entry.fixup' => \&enqueue,
        'update.fixup'       => \&fetch,
    );
}

sub enqueue {
    my($self, $context, $args) = @_;
    my $body = $args->{entry}->body;
    $context->log(debug => "body = $body");

    for my $enclosure ($args->{entry}->enclosures) {
        # TODO: do all of this in the base class ::Command
        my $feed_dir = File::Spec->catfile($self->conf->{dir}, $args->{feed}->id_safe);
        unless (-e $feed_dir && -d _) {
            $context->log(info => "mkdir $feed_dir");
            mkdir $feed_dir, 0777;
        }

        my $path = File::Spec->catfile($feed_dir, $enclosure->filename);

        if ($enclosure->length && -e $path && -s _ == $enclosure->length) {
            # TODO: if-none-match
            $context->log(debug => $enclosure->url . "is already stored in $path");
            next;
        }

        $context->log(info => "fetch " . $enclosure->url . " to " . $path);

        POE::Session->create(
            inline_states => {
                _start => sub {
                    $_[HEAP]->{wheel} = POE::Wheel::Run->new(
                        Program => [
                            'mplayer',
                            $enclosure->url,
                            '-vc', 'dummy',
                            '-vo', 'null',
                            '-ao', "pcm:file=$path",
                        ],
                        StdoutEvent => 'stdout',
                        ErrorEvent => 'wheel_close',
                        CloseEvent => 'wheel_close',
                    );
                },
                stdout => sub {
                    if ($_[ARG0] =~ /Starting playback.../) {
                        my $length = -s $path;
                        $enclosure->local_path($path);
                        $enclosure->type('audio/x-wav');
                        $context->log(info => "Dumping to $path is done [$length]");
                    }

                    $context->log(debug => "$_[ARG0]");
                },
                wheel_close => sub {
                    delete $_[HEAP]->{wheel};
                },
            },
        );
    }
}

sub fetch {
    Plagger->context->log(info => "Start dumping stream as wav files using mplayer.");
    POE::Kernel->run;
    Plagger->context->log(info => "Dumping finished.");
}

1;

__END__

=head1 NAME

Plagger::Plugin::Filter::FetchEnclosure::Mplayer - Fetch enclosures using mplayer

=head1 SYNOPSIS

  - module: Filter::FetchEnclosure::Mplayer
    config:
      dir: /path/to/download

=head1 DESCRIPTION

This plugin dumps audio/video stream to a wav file.

=head1 AUTHOR

Yohei Fushii

=head1 SEE ALSO

L<Plagger>

=cut

*1:ちょっとFilter::FetchEnclosure::Wgetを変えただけやけどなー

*2:これは明日書く