download streaming file by rtmpdump and , convert to mp4 by ffmpeg
#!/usr/local/bin/perl use strict; use warnings; use utf8; use Encode; use FindBin; use LWP::UserAgent; use XML::Simple; use Data::Dumper; ## NHKゴガク https://www2.nhk.or.jp/gogaku/english/ my $MUSIC_OUT_DIR = $FindBin::Bin; my $MUSIC_LIST_ROOT = 'https://www2.nhk.or.jp/gogaku/st/xml'; my $MUSIC_LIST_CHANNELS = {english=>[ 'enjoy', #エンジョイ・シンプル・イングリッシュ 'basic1', #基礎英語1 'basic2', #基礎英語2 'basic3', #基礎英語3 'kaiwa', #ラジオ英会話 'timetrial', #英会話タイムトライアル 'kouryaku', #攻略!英語リスニング 'business1', #入門ビジネス英語 'business2', #実践ビジネス英語 ], }; # There are some paramaters # in https://www2.nhk.or.jp/gogaku/st/flash/sound/ggk_str_pc3.swf , below. # You can extract from swf file # by Flare ( http://www.nowrap.de/flare.html ). my $MUSIC_FILE_ROOT = 'rtmpe://flvs.nhk.or.jp:1935/ondemand'; my $MUSCI_FILE_SUB_PATH = 'mp4:flv/gogaku-stream/mp4'; my $RTMPDUMP_CMD = '/usr/local/bin/rtmpdump'; my $FFMPEG_CMD = '/usr/bin/ffmpeg'; main(@ARGV); sub main { my (@cmd_args) = @_; for my $lang (sort keys %$MUSIC_LIST_CHANNELS ){ for my $channel (@{$MUSIC_LIST_CHANNELS->{$lang}}){ ## DOWNLOAD CHANNEL INFOS my $channel_infos = get_music_list($lang,$channel); next if(ref($channel_infos) ne 'ARRAY' or scalar(@$channel_infos) ==0 ); my $out_dir = get_output_dir($lang,$channel); for my $channel_info ( @$channel_infos ){ ## DOWNLOAD MUSIC FILE by rtmpdump my $music_file = get_music_file($channel_info, $out_dir); next unless $music_file; sleep(2); ## CORRECT by ffmpeg my $mp4_file = conv_to_mp4($music_file); print Encode::encode('utf8',"DONE $mp4_file"),"\n"; unlink $music_file or die "$music_file$!"; } } } } sub conv_to_mp4 { my($org_file) = @_; my $new_file = "$org_file.mp4"; my $cmd = "$FFMPEG_CMD -loglevel error -y -i $org_file -acodec copy $new_file"; my $fh; unless( open $fh, '-|', $cmd ){ print STDERR Encode::encode('utf8',"fail open $cmd"),"\n"; return; } unless( close($fh) ){ print STDERR Encode::encode('utf8',"fail close $cmd"),"\n"; return; } return $new_file; } sub get_output_dir { my($lang,$channel) = @_; my $out_dir_0 = join('/',$MUSIC_OUT_DIR,$lang); if(not -d $out_dir_0){ mkdir $out_dir_0 or die "fail mkdir $out_dir_0 $!"; } return $out_dir_0; # my $out_dir = join('/',$MUSIC_OUT_DIR,$lang,$channel); # if(not -d $out_dir ){ # mkdir $out_dir or die "fail mkdir $out_dir $!"; # } # return $out_dir; } sub get_music_file { my ($channel_info, $out_dir) = @_; my $url = join('/', $MUSIC_FILE_ROOT, $MUSCI_FILE_SUB_PATH, $channel_info->{file}); my $out_file = join('/', $out_dir, "$channel_info->{title}_$channel_info->{hdate}"); my $cmd = "$RTMPDUMP_CMD --quiet -r $url -o $out_file"; my $fh; unless( open $fh, '-|', $cmd ){ print STDERR Encode::encode('utf8',"fail open $cmd"),"\n"; return; } unless( close($fh) ){ print STDERR Encode::encode('utf8',"fail close $cmd"),"\n"; return; } return $out_file; } sub get_music_list { my ($lang, $channel) = @_; my $url = join('/',$MUSIC_LIST_ROOT,$lang, $channel,'listdataflv.xml'); my $ua = LWP::UserAgent->new; my $res = $ua->get($url); if(not $res->is_success ) { print STDERR $res->status_line , " $url\n"; return []; } my $xml_content = $res->content; $xml_content = Encode::decode('utf8',$xml_content); my $ret = XML::Simple::XMLin($xml_content); return $ret->{music}; }
open amを「 〜.jp」のようなccTLDの場合は3つ以上の「.」が必要
https://github.com/k-tamura/openam-book-jp/blob/master/preparing-for-installation.md に、
テスト目的のためであっても、localhostドメインを使用しないで下さい。 OpenAMの動作は、ドメイン名に基づいて返されるブラウザのクッキーに依存しています。基本的には、少なくとも2つの「.」(ドット)を含むドメイン名を使用していることを確認して下さい。 例) openam.example.com ※正確には、OpenAMインストール時の「Cookie ドメイン」に含める「.」の数は、「〜.com 」のようなgTLDの場合は2つでも構いませんが、「 〜.jp」のようなccTLDの場合は3つ以上が必要です。
しっかり記載されていた。勉強になります。
特に
したがって「.example.com」や「.example.co.jp」は適切であっても、「.example.jp」は不適切ということになります。
には驚いた。
pythonで、任意のdirにライブラリのpathを通す
#!/usr/local/bin/perl use strict; use warnings; use utf8; use FindBin; use File::Spec; use lib File::Spec->catdir($FindBin::Bin, '../lib'); :
perlでは上記のように「use lib , FindBin」を使用していましたが pythonでは、以下のように「import sys,os」や「sys.path.append()」を使うみたい。
「init.py」の配備もポイントみたい
$ cat script/foo.py #!/usr/local/bin/python # coding: utf-8 import sys,os sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../lib') from TestClass import TestClass def main(): test_obj = TestClass(3) print test_obj.width if __name__ == '__main__': main()
$ cat lib/TestClass.py # coding: utf-8 class TestClass(object): def __init__(self, width): #constractor self.width = width
$ tree . ├── lib │ ├── __init__.py │ └── TestClass.py └── script └── foo.py
App::cpanminus と OrePAN で、localにcpan mirrorを作成し、そこからinstall
internetに接続されていない環境に 対象のperl moduleをinstallする必要があったので、OrePANを使ってみみた。
前準備
事前に本番機には、App::cpanminus (cpanmコマンド)、 開発機?には、OrePAN + App::cpanminus (cpanmコマンド)をinstallしておいて下さい。
開発機にcpan-mirror を作成し、本番機へscp
$ cpanm -L local-tmp --save-dists=cpan-mirror Plack::Middleware::ReverseProxy $ cpanm -L local-tmp --save-dists=cpan-mirror Amon2 $ cpanm -L local-tmp --save-dists=cpan-mirror DBI $ cpanm -L local-tmp --save-dists=cpan-mirror DBD::SQLite $ cpanm -L local-tmp --save-dists=cpan-mirror DBD::mysql $ cpanm -L local-tmp --save-dists=cpan-mirror DBIx::Class :
↑こちらのようなコマンドで、search.cpan.org からmodule ダウンロードのみ行います。
その後、↓こちらのコマンドでmodule一覧(index file)を作成し、 cpan-mirrorを本番機へscpします。
$ orepan_index.pl -r ./cpan-mirror $ tar -zcvf cpan-mirror.tar.gz cpan-mirror/ $ scp -i ~/.ssh/id_rsa cpan-mirror.tar.gz ???.???.???.???:tmp/
本番ではscpされたcpan-mirrorからinstall
後は簡単。
# cd /home/endo # cpanm --mirror=file:///home/endo/cpan-mirror --mirror-only Amon2 # cpanm --mirror=file:///home/endo/cpan-mirror --mirror-only DBI :
mysql5.7 をsrcからinstall
以前、↑こちらで mysql5.5をinstallしましたが、5.7では少々異なりましたので
install mysql 5.7
$ wget http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.14.tar.gz $ tar -xvf mysql-5.7.14.tar.gz $ cd mysql-5.7.14 $ cmake . \ -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ -DDEFAULT_CHARSET=utf8 \ -DDEFAULT_COLLATION=utf8_general_ci \ -DENABLED_LOCAL_INFILE=true \ -DWITH_INNOBASE_STORAGE_ENGINE=1 \ -DWITH_EXTRA_CHARSETS=all \ -DWITH_READLINE=ON : CMake Error at cmake/boost.cmake:81 (MESSAGE): You can download it with -DDOWNLOAD_BOOST=1 -DWITH_BOOST=<directory> This CMake script will look for boost in <directory>. If it is not there, it will download and unpack it (in that directory) for you. If you are inside a firewall, you may need to use an http proxy: export http_proxy=http://example.com:80 Call Stack (most recent call first): cmake/boost.cmake:238 (COULD_NOT_FIND_BOOST) CMakeLists.txt:455 (INCLUDE) -- Configuring incomplete, errors occurred!
mysql5.7よりboostが必要になったようです。
そこで、cmakeのoptionに 「-DDOWNLOAD_BOOST=1 -DWITH_BOOST=/home/endo/tmp/」を追加すると boostを勝手にdownloadしてくれます。
cmake . \ -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ -DDEFAULT_CHARSET=utf8 \ -DDEFAULT_COLLATION=utf8_general_ci \ -DENABLED_LOCAL_INFILE=true \ -DWITH_INNOBASE_STORAGE_ENGINE=1 \ -DWITH_EXTRA_CHARSETS=all \ -DWITH_READLINE=ON \ -DDOWNLOAD_BOOST=1 \ -DWITH_BOOST=/home/endo/tmp/ $ make $ make test # make install
edit /etc/my.conf
ポイントは - skip-grant-tables がないと、id/pw=root/null でログインできません - sql-mode="ONLY_FULL_GROUP_BY" となっていると、selectする全colをgroup by で指定する必要があります
# For advice on how to change settings please see # http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html # *** DO NOT EDIT THIS FILE. It's a template which will be copied to the # *** default location during install, and will be replaced if you # *** upgrade to a newer version of MySQL. [mysqld] # Remove leading # and set to the amount of RAM for the most important data # cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%. # innodb_buffer_pool_size = 128M # Remove leading # to turn on a very important data integrity option: logging # changes to the binary log between backups. # log_bin # These are commonly set, remove the # and set as required. # basedir = ..... # datadir = ..... # port = ..... # server_id = ..... # socket = ..... default-storage-engine = INNODB basedir = /usr/local/mysql datadir = /home/mysql/data port = 3306 socket = /tmp/mysql.sock skip-grant-tables #sql-mode="ONLY_FULL_GROUP_BY" sql-mode="" # Remove leading # to set options mainly useful for reporting servers. # The server defaults are faster for transactions and fast SELECTs. # Adjust sizes as needed, experiment to find the optimal values. # join_buffer_size = 128M # sort_buffer_size = 2M # read_rnd_buffer_size = 2M # sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES # max connections max_connections = 64 # table_open_cache = (max_connections * tables used in one transaction) + alpha table_open_cache = 800 # table_definition_cache = (all tables in mysql + max_connections) + alpha table_definition_cache = 400 # open_files_limit = table_open_cache * 1.4 open_files_limit = 1120 # global buffer key_buffer_size = 16M query_cache_type = 0 # innodb_buffer_pool_size = RAM for Mysql * 0.7 innodb_buffer_pool_size = 256M # thread buffer read_buffer_size = 256K read_rnd_buffer_size = 512K join_buffer_size = 256K sort_buffer_size = 512K # InnoDB innodb_file_per_table innodb_autoextend_increment = 64 innodb_log_files_in_group = 2 innodb_log_file_size = 64M innodb_log_buffer_size = 16M innodb_flush_log_at_trx_commit = 1 innodb_flush_neighbors=0 #innodb_flush_method=O_DIRECT innodb_thread_concurrency = 4 innodb_commit_concurrency = 4 # log general_log = 0 general_log_file = /usr/local/var/mysql/general.log slow_query_log = 0 [mysqldump] #max_allowed_packet = 16M quick set-charset single-transaction
install apache2.2 + perl5.18 + mod_perl2.0.9
install perl 5.18
$ wget http://www.cpan.org/src/5.0/perl-5.18.4.tar.gz $ tar -xvf perl-5.18.4.tar.gz $ cd perl-5.18.4 $ ./Configure -Dusethreads -Accflags="-fPIC" -de $ make $ make test $ su # make install
※「-Dusethreads -Accflags="-fPIC"」option are needed by mod_perl.
install apache2.2
$ wget http://ftp.riken.jp/net/apache//httpd/httpd-2.2.31.tar.gz $ tar -xvf httpd-2.2.31.tar.gz $ cd httpd-2.2.31 $ ./configure --prefix=/home/endo/local/apache22 \ --with-mpm=prefork \ --enable-proxy \ --enable-modules=all \ --enable-so $ make $ make install
install mod_perl
$ wget http://www.apache.org/dyn/closer.cgi/perl/mod_perl-2.0.9.tar.gz $ tar -xvf mod_perl-2.0.9.tar.gz $ cd mod_perl-2.0.9 $ /usr/local/bin/perl Makefile.PL \ USE_APXS=1 \ WITH_APXS=/home/endo/local/apache22/bin/apxs \ EVERYTHING=1 $ make $ make test $ su # make install
edit httpd.conf & startup.pl
$ vi /home/endo/local/apache22/conf/httpd.conf : LoadModule perl_module modules/mod_perl.so PerlRequire /home/endo/local/apache22/conf/startup.pl PerlSetEnv XING_CONF /home/endo/dev/xing/etc/config.yaml <Directory "/home/endo/dev/xing/app"> AllowOverride All Order allow,deny Allow from all AuthType BASIC AuthUserFile /home/endo/dev/htpasswd AuthName "COLINUX MEMBERS" require valid-user <Files "*.pl"> Options ExecCGI AddHandler cgi-script .pl SetHandler perl-script PerlHandler ModPerl::Registry PerlSendHeader On </Files> </Directory> Alias /Xing /home/endo/dev/xing/app
$ vi /home/endo/local/apache22/conf/startup.pl : #/usr/local/bin/perl BEGIN { use lib qw(. /home/endo/dev/xing/lib ); } use NMW::Template; $NMW::Template::ENCODING = 'utf8'; @NMW::Template::template_path=('/home/endo/dev/xing/tmpl'); use CGI; $CGI::LIST_CONTEXT_WARN = 0; #use Devel::Cover; #$DEVEL_COVER_OPTIONS='-dir,/home/endo/tmp'; 1;
nginx + nginx-auth-ldap module
step1/3 - install
$ cd /home/endo/tmp $ wget http://nginx.org/download/nginx-1.9.3.tar.gz $ tar -xvf nginx-1.9.3.tar.gz $ wget https://www.openssl.org/source/openssl-1.0.2d.tar.gz $ tar -xvf openssl-1.0.2d.tar.gz $ git clone https://github.com/kvspb/nginx-auth-ldap.git $ cd nginx-1.9.3 $ ./configure --prefix=/home/endo/local/nginx \ --with-http_ssl_module \ --with-openssl=../openssl-1.0.2d \ --add-module=../nginx-auth-ldap $ make $ make install
step2/3 - edit nginx.conf
$ vi /home/endo/local/nginx/conf/nginx_auth_ldap.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; ldap_server ldap_sexy { url ldap://ldap.sexy.co.jp/ou=people,o=sexy-group?uid?sub?(objectClass=*) group_attribute uniqueMember; group_attribute_is_dn on; require valid_user; } server { listen 8080; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { auth_ldap "AUTH_LDAP"; auth_ldap_servers ldap_sexy; root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
step 3/3 - start nginx
$ cd /home/endo/local/nginx $ ./sbin/nginx -c conf/nginx_auth_ldap.conf
VirtualBoxのストレージをvdmk(可変サイズ)→vdi形式(固定サイズ)に変更
vdi形式(固定サイズ)の方が、ディスクI/Oが良い気がするので、次のような手順でやってみた。
STEP1 ファイル → 仮想メディアマネージャ
STEP2 イメージファイルのコピー
※VDI(固定サイズ)、VDMK(可変サイズ)
STEP3 旧ストレージをun-mount、新ストレージをmount
以上!!
word2013にプログラムコードを貼るなら、セクション区切り + 行番号表示 + ページ罫線 + 行間隔調整
で、ソースがそれらしく見えます。
step1 ページレイアウト → セクション区切り + 行番号表示
step2 デザイン → ページ罫線
step3 ホーム → 行間隔調整
フォントの調整はお好みで
mysqlのLOAD DATA LOCAL INFILEによる bulk insert オレオレまとめ
sqlの"--"コメントにも記載していますが、自分としてのポイントは、
- LOCAL INFILEの"LOCAL"で、"Access denied for user..."のようなエラーになりづらい
- "\N"としなくても、NULLIF()でnull値をimportできます
かな?
LOAD DATA LOCAL INFILE '/path/to/import_file.csv' [REPLACE | IGNORE] INTO TABLE import_tbl character set 'utf8' -- 文字コード FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' -- フィールドを囲む文字 ESCAPED BY '\' -- エスケープ文字 LINES TERMINATED BY '\n' IGNORE 0 LINES -- 先頭?行を無視 (field_1,field_2,...) -- import対象のcolumn SET -- 必要に応じ値を変換 update_time = NULLIF(update_time, '0000-00-00 00:00:00'), --日時の場合は注意 field_1 = IF(field_1='A', field_1, null), ;
まぁ、dev.mysql.com/doc に記載の通りなんですけどね。 https://dev.mysql.com/doc/refman/5.6/ja/load-data.html
(再)Amon2 for perl のControllerに対するTest::Moreによるunit test
↑こんな風にplug-inを書いて頑張らなくても Plack::Util::load_psgi や Test::WWW::Mechanize::PSGI で十分実現できるそうです。↓
use strict; use warnings; use utf8; use HTTP::Cookies; use JSON; use Plack::Test; use Plack::Util; use Test::More; use Test::Requires 'Test::WWW::Mechanize::PSGI'; use Data::Dumper; $ENV{"PLACK_ENV"} = 'development'; my $cookie_jar = HTTP::Cookies->new(file => "./cookie.txt", autosave => 1, ignore_discard => 1); $cookie_jar->set_cookie(undef, #version "HTTP_mavi-id", #key 'ushiro', #val "/", #pathu "localhost.local"); #domain my $app = Plack::Util::load_psgi 'script/ean-server'; my $mech = Test::WWW::Mechanize::PSGI->new(app => $app, cookie_jar=>$cookie_jar); subtest 'sub_test_name_1'=> sub { $mech->get_ok("/"); $mech->title_like(qr/トップ/s); $mech->content_like(qr/ean/s); }; subtest 'sub_test_name_2'=> sub { $mech->get_ok("/report/group/settings"); my $res_data = JSON::from_json( $mech->content ); print STDERR Dumper($res_data); }; done_testing;
Amon2 for perl のControllerに対するTest::Moreによるunit test
以下の get_dummy_context() 内に記載しているようにAmon2クラスに対して、plug-inを書くとOK
use strict; use utf8; use t::Util; use CGI; use Date::Calc; use JSON; use Plack::Session; use Plack::Test; use Plack::Util; use Test::More; use Data::Dumper; Ean->bootstrap; use_ok('Ean::Controller::MemberEdit'); use_ok('Ean::ObjModel::Member'); my $SMART_ID = 'mae'; my $CGI; my $SESSION; my $REQUEST; subtest 'confirm' => sub { my $class = 'Ean::Controller::MemberEdit'; my $c = get_dummy_context(); $c->session->set( navi_id => $SMART_ID ); $c->req->param( 'navi_email_send', 1 ); $c->req->param( 'ean_email1', 'ndds-test@example.com' ); $c->req->param( 'ean_email1_conf', 'ndds-test@example.com' ); $c->req->param( 'ean_email1_send', 1 ); my $ret_data = $class->confirm($c); #JSONで返す型(int)もcheck like($ret_data, qr/"ean_email2_send":1/o); like($ret_data, qr/"show_bems_area_1":1/o); like($ret_data, qr/"show_bems_area_2":1/o); like($ret_data, qr/"navi_email_send":1/o); like($ret_data, qr/"ean_email1":"ndds-test\@example.com"/o); like($ret_data, qr/"ean_email1_conf":"ndds-test\@example.com"/o); like($ret_data, qr/"ean_email1_send":1/o); like($ret_data, qr/"ean_email2":"ndds-test2\@example.com"/o); like($ret_data, qr/"ean_email2_conf":"ndds-test2\@example.com"/o); }; sub date_str { my ($day_diff) = @_; my @date = Date::Calc::Add_Delta_Days(Date::Calc::Today, $day_diff||0); return sprintf("%04d-%02d-%02d", @date); } sub now_str { my ($day_diff) = @_; my @datetime = Date::Calc::Add_Delta_YMDHMS(Date::Calc::Today_and_Now, 0,0,$day_diff||0, 0,0,0); return sprintf("%04d-%02d-%02d %02d:%02d:%02d", @datetime); } sub get_dummy_context { no strict 'refs'; no warnings 'redefine'; *{"Ean\::session"} = sub { return $SESSION if $SESSION; my $dummy_env = {'psgix.session'=>{}, 'psgix.session.options'=>{}}; $SESSION = Plack::Session->new( $dummy_env ); return $SESSION; }; *{"Ean\::req"} = sub { return $CGI if $CGI; $CGI = CGI->new(); return $CGI; }; *{"Ean\::render_json"} = sub { my ($self,$perl_obj) = @_; return JSON::to_json($perl_obj); }; *{"Ean\::request"} = sub { return $REQUEST if $REQUEST; $REQUEST = DummyRequest->new(); return $REQUEST; }; my $c = Ean->bootstrap; return $c; } done_testing; package DummyRequest; sub new { my ($class) = @_; my $self = {}; $self = bless $self, $class; return $self; } sub cookies { return {}; } sub env { return {}; } __DATA__