文字列の一括置換

プログラムを作成しているとき、変数名だけ変えて、他はすべてコピペしたいときがある。数が多いと面倒なので、Linuxコマンドで一括置換する。

あらかじめ古いテキスト用のファイルと新しいテキスト用のファイルを準備しておく。ここでは「~/py」フォルダーに「old_text.txt」と「new_text.txt」の各ファイルを作成したことにする。

例として、「old_text.txt」ファイルに以下の

古い1
古い2
古い3

をコピー・アンド・ペーストして保存しておく。そして、これを以下のコマンドで書き換える。

$ sed -e "s/古い/新しい/g" ~/py/old_text.txt > ~/py/new_text.txt

すると、「new_text.txt」ファイルに

新しい1
新しい2
新しい3

と置換されて書き込まれる。

(2017/03/16更新)

「ファイル“****”を開く際にエラーが発生しました。」

Windowsで作成したテキストファイルをテキストエディターで開こうとすると、「ファイル“****”を開く際にエラーが発生しました。」と表示が出て、開けない場合がある。

「エンコーディング」は「現在のロケール (UTF-8)」となっている。「再試行」ボタンをクリックしても、やはり「ファイル“****”を開く際にエラーが発生しました。」と表示が出て、開けない。

Windowsで作成したテキストファイルはshift-JISで書かれていると思う。そこで、テキストエディターで「エンコーディング」を「日本語 (SHIFT_JIS)」に変更して「再試行」ボタンをクリックしてみる。だが、今度は「ファイル“****”を開けませんでした。」と表示は変わるが、やはり開けない。

原因ははっきりしないが、テキストエディターで読めるようにするにはとりあえず文字コードをUTF-8に変換するのが手っ取り早い。

例として「ホーム」フォルダーに「file_shift-jis.txt」ファイルがあるとして、これをUTF-8に変換して「file_utf-8.txt」ファイルとする手順を説明する。

○端末に以下のコマンドをコピー&ペーストして「Enter」キーを押す。

nkf -w ~/file_shift-jis.txt > ~/file_utf-8.txt

「file_shift-jis.txt」ファイルはそのまま残り、「file_utf-8.txt」ファイルが新たに作成される。「file_utf-8.txt」ファイルをテキストエディターで開くと、無事にファイルの内容を見ることができる。

(2017/01/10更新)

テレビ視聴アプリの作成

Chinachuの録画予約機能には特に不満はないのだが、テレビ視聴機能が今一つ使い勝手が悪い。ふと、昔、自分でテレビ視聴アプリを作ったことがあったのを思い出し、コンパイルしてみたら、今でも使えるので驚いた。それは今から9年ほど前、私がプログラミングを学んで初めて作ったもので、なつかしい。

プログラムを見ると、関数に引数を渡すということを知らなかったようで、チャンネルごとに関数を作っていた。また、システムに与えるコマンドを直接、プログラムに書き込めばいいものを、わざわざスクリプトファイルを作って、それを呼び出していた。しかもコマンド1つごとにファイルを作っていた。そんなわけでプログラムがやたらと長く、ファイルが50近くもあった。

今から見ると稚拙にもほどがあると思うが、それでも何とかして作り上げてやるという熱意は感じる。それはさて、当時のプログラムに修正を加えたものが、これから作成する視聴アプリである。WindowsでTVTestなどを使っている人から見ると「なにこれ」といったレベルだが、単にテレビを視聴するだけなら十分かなと思う。

準備

①「Ubuntu 16.04 + Chinachu + PT2でテレビ」の記事に基づいて、recpt1で録画できる環境を作る(Chinachuはなくてもよい)。

②端末に以下のコマンドをコピー&ペーストして「Enter」キーを押す。

sudo apt-get -y install libgtk2.0-dev vlc

GUIツールキットとしてGTK+2を使う。

また、再生プレイヤーとしてVLCプレイヤーを使う。

③「[sudo] **** のパスワード:」でパスワードを入力して「Enter」キーを押す。

アプリの作成

①以下のプログラムをテキストエディターにコピー&ペーストし、ファイル名を「tv.c」としてデスクトップに保存する。

#include <gtk/gtk.h>

GtkWidget *table[4];

void system();

// 放送を選択する関数を定義する。
void select_broadcasting(GtkWidget *widget, gpointer data) {
    if (GPOINTER_TO_INT(data) == 0) {
        gtk_widget_show(table[1]);
        gtk_widget_hide(table[2]);
        gtk_widget_hide(table[3]);
    }
    else if (GPOINTER_TO_INT(data) == 1) {
        gtk_widget_show(table[2]);
        gtk_widget_hide(table[3]);
        gtk_widget_hide(table[1]);
    }
    else {  // GPOINTER_TO_INT(data) == 2
        gtk_widget_show(table[3]);
        gtk_widget_hide(table[1]);
        gtk_widget_hide(table[2]);
    }
}

// チャンネルを選択する関数を定義する。
void select_channel(GtkWidget *widget, gpointer data) {
    system("killall recpt1; killall cvlc");
    system("rm temp.ts");
    system(data);
    sleep(2);
    system("cvlc temp.ts &");
}

// ウィンドウを閉じたときの動作を設定する関数を定義する。
void destroy(GtkWidget *widget, gpointer data) {
    system("killall recpt1; killall cvlc");
    system("rm temp.ts");
    gtk_main_quit();
}

int main(int argc, char *argv[]) {
    GtkWidget *window;
    GtkWidget *box;
    GtkWidget *radio_button[3];
    GtkWidget *btn_gr[12], *btn_bs[12], *btn_cs[12];
    GSList *group = NULL;
    gpointer ch1_gr, ch2_gr, ch3_gr, ch4_gr, ch5_gr, ch6_gr, ch7_gr, ch8_gr,
        ch9_gr, ch10_gr, ch11_gr, ch12_gr;
    gpointer ch1_bs, ch2_bs, ch3_bs, ch4_bs, ch5_bs, ch6_bs, ch7_bs, ch8_bs,
        ch9_bs, ch10_bs, ch11_bs, ch12_bs;
    gpointer ch1_cs, ch2_cs, ch3_cs, ch4_cs, ch5_cs, ch6_cs, ch7_cs, ch8_cs,
        ch9_cs, ch10_cs, ch11_cs, ch12_cs;

    // 初期化する。
    gtk_init(&argc, &argv);

    // 地上デジタルの設定を行う。
    ch1_gr = "recpt1 --b25 --strip --sid hd 27 7200 temp.ts &";
    ch2_gr = "recpt1 --b25 --strip --sid hd 26 7200 temp.ts &";
    ch3_gr = "recpt1 --b25 --strip --sid hd 25 7200 temp.ts &";
    ch4_gr = "recpt1 --b25 --strip --sid hd 22 7200 temp.ts &";
    ch5_gr = "recpt1 --b25 --strip --sid hd 21 7200 temp.ts &";
    ch6_gr = "recpt1 --b25 --strip --sid hd 24 7200 temp.ts &";
    ch7_gr = "recpt1 --b25 --strip --sid hd 23 7200 temp.ts &";
    ch8_gr = "recpt1 --b25 --strip --sid hd 16 7200 temp.ts &";
    ch9_gr = "recpt1 --b25 --strip --sid hd 20 7200 temp.ts &";
    ch10_gr = "recpt1 --b25 --strip --sid hd 18 7200 temp.ts &";
    ch11_gr = "recpt1 --b25 --strip --sid hd 32 7200 temp.ts &";
    ch12_gr = "recpt1 --b25 --strip --sid hd 28 7200 temp.ts &";

    // BSの設定を行う。
    ch1_bs = "recpt1 --b25 --strip 101 7200 temp.ts &";
    ch2_bs = NULL;
    ch3_bs = "recpt1 --b25 --strip 103 7200 temp.ts &";
    ch4_bs = "recpt1 --b25 --strip 141 7200 temp.ts &";
    ch5_bs = "recpt1 --b25 --strip 151 7200 temp.ts &";
    ch6_bs = "recpt1 --b25 --strip 161 7200 temp.ts &";
    ch7_bs = "recpt1 --b25 --strip 171 7200 temp.ts &";
    ch8_bs = "recpt1 --b25 --strip 181 7200 temp.ts &";
    ch9_bs = NULL;
    ch10_bs = NULL;
    ch11_bs = "recpt1 --b25 --strip 211 7200 temp.ts &";
    ch12_bs = "recpt1 --b25 --strip 222 7200 temp.ts &";

    // CSの設定を行う。
    ch1_cs = NULL;
    ch2_cs = NULL;
    ch3_cs = NULL;
    ch4_cs = NULL;
    ch5_cs = NULL;
    ch6_cs = NULL;
    ch7_cs = NULL;
    ch8_cs = NULL;
    ch9_cs = NULL;
    ch10_cs = NULL;
    ch11_cs = NULL;
    ch12_cs = NULL;

    // ウィンドウを作成する。
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_size_request(window, 140, 140);
    gtk_window_set_resizable(GTK_WINDOW (window), FALSE);
    gtk_window_set_keep_above(GTK_WINDOW(window), TRUE);

    // ボックスを作成する。
    box = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER(window), box);

    // 放送選択用のテーブルを作成する。
    table[0] = gtk_table_new(3, 1, FALSE);
    gtk_box_pack_start(GTK_BOX(box), table[0], FALSE, TRUE, 0);

    // 放送選択用のラジオボタンを作成する。
    radio_button[0] = gtk_radio_button_new_with_label(group, "GR");
    radio_button[1] = gtk_radio_button_new_with_label_from_widget(
        GTK_RADIO_BUTTON(radio_button[0]), "BS");
    radio_button[2] = gtk_radio_button_new_with_label_from_widget(
        GTK_RADIO_BUTTON(radio_button[0]), "CS");

    // 放送選択用のラジオボタンをテーブルに設置する。
    gtk_table_attach_defaults(GTK_TABLE(table[0]), radio_button[0],
                                        0, 1, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(table[0]), radio_button[1],
                                        1, 2, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(table[0]), radio_button[2],
                                        2, 3, 0, 1);
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(radio_button[0]), TRUE);

    // チャンネル選択用のテーブルを作成する。
    table[1] = gtk_table_new(3, 4, FALSE);
    table[2] = gtk_table_new(3, 4, FALSE);
    table[3] = gtk_table_new(3, 4, FALSE);

    // チャンネル選択用のテーブルをボックスに設置する。
    gtk_box_pack_start(GTK_BOX(box), table[1], FALSE, TRUE, 0);
    gtk_box_pack_start(GTK_BOX(box), table[2], FALSE, TRUE, 0);
    gtk_box_pack_start(GTK_BOX(box), table[3], FALSE, TRUE, 0);

    // 地デジチャンネル選択用のボタンを作成する。
    btn_gr[0] = gtk_button_new_with_label("1");
    btn_gr[1] = gtk_button_new_with_label("2");
    btn_gr[2] = gtk_button_new_with_label("3");
    btn_gr[3] = gtk_button_new_with_label("4");
    btn_gr[4] = gtk_button_new_with_label("5");
    btn_gr[5] = gtk_button_new_with_label("6");
    btn_gr[6] = gtk_button_new_with_label("7");
    btn_gr[7] = gtk_button_new_with_label("8");
    btn_gr[8] = gtk_button_new_with_label("9");
    btn_gr[9] = gtk_button_new_with_label("10");
    btn_gr[10] = gtk_button_new_with_label("11");
    btn_gr[11] = gtk_button_new_with_label("12");

    // 地デジチャンネル選択用のボタンをテーブルに設置する。
    gtk_table_attach_defaults(GTK_TABLE(table[1]), btn_gr[0], 0, 1, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(table[1]), btn_gr[1], 1, 2, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(table[1]), btn_gr[2], 2, 3, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(table[1]), btn_gr[3], 0, 1, 1, 2);
    gtk_table_attach_defaults(GTK_TABLE(table[1]), btn_gr[4], 1, 2, 1, 2);
    gtk_table_attach_defaults(GTK_TABLE(table[1]), btn_gr[5], 2, 3, 1, 2);
    gtk_table_attach_defaults(GTK_TABLE(table[1]), btn_gr[6], 0, 1, 2, 3);
    gtk_table_attach_defaults(GTK_TABLE(table[1]), btn_gr[7], 1, 2, 2, 3);
    gtk_table_attach_defaults(GTK_TABLE(table[1]), btn_gr[8], 2, 3, 2, 3);
    gtk_table_attach_defaults(GTK_TABLE(table[1]), btn_gr[9], 0, 1, 3, 4);
    gtk_table_attach_defaults(GTK_TABLE(table[1]), btn_gr[10], 1, 2, 3, 4);
    gtk_table_attach_defaults(GTK_TABLE(table[1]), btn_gr[11], 2, 3, 3, 4);

    // BSチャンネル選択用のボタンを作成する。
    btn_bs[0] = gtk_button_new_with_label("1");
    btn_bs[1] = gtk_button_new_with_label("2");
    btn_bs[2] = gtk_button_new_with_label("3");
    btn_bs[3] = gtk_button_new_with_label("4");
    btn_bs[4] = gtk_button_new_with_label("5");
    btn_bs[5] = gtk_button_new_with_label("6");
    btn_bs[6] = gtk_button_new_with_label("7");
    btn_bs[7] = gtk_button_new_with_label("8");
    btn_bs[8] = gtk_button_new_with_label("9");
    btn_bs[9] = gtk_button_new_with_label("10");
    btn_bs[10] = gtk_button_new_with_label("11");
    btn_bs[11] = gtk_button_new_with_label("12");

    // BSチャンネル選択用のボタンをデーブルに設置する。
    gtk_table_attach_defaults(GTK_TABLE(table[2]), btn_bs[0], 0, 1, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(table[2]), btn_bs[1], 1, 2, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(table[2]), btn_bs[2], 2, 3, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(table[2]), btn_bs[3], 0, 1, 1, 2);
    gtk_table_attach_defaults(GTK_TABLE(table[2]), btn_bs[4], 1, 2, 1, 2);
    gtk_table_attach_defaults(GTK_TABLE(table[2]), btn_bs[5], 2, 3, 1, 2);
    gtk_table_attach_defaults(GTK_TABLE(table[2]), btn_bs[6], 0, 1, 2, 3);
    gtk_table_attach_defaults(GTK_TABLE(table[2]), btn_bs[7], 1, 2, 2, 3);
    gtk_table_attach_defaults(GTK_TABLE(table[2]), btn_bs[8], 2, 3, 2, 3);
    gtk_table_attach_defaults(GTK_TABLE(table[2]), btn_bs[9], 0, 1, 3, 4);
    gtk_table_attach_defaults(GTK_TABLE(table[2]), btn_bs[10], 1, 2, 3, 4);
    gtk_table_attach_defaults(GTK_TABLE(table[2]), btn_bs[11], 2, 3, 3, 4);

    // CSチャンネル選択用のボタンを作成する。
    btn_cs[0] = gtk_button_new_with_label("1");
    btn_cs[1] = gtk_button_new_with_label("2");
    btn_cs[2] = gtk_button_new_with_label("3");
    btn_cs[3] = gtk_button_new_with_label("4");
    btn_cs[4] = gtk_button_new_with_label("5");
    btn_cs[5] = gtk_button_new_with_label("6");
    btn_cs[6] = gtk_button_new_with_label("7");
    btn_cs[7] = gtk_button_new_with_label("8");
    btn_cs[8] = gtk_button_new_with_label("9");
    btn_cs[9] = gtk_button_new_with_label("10");
    btn_cs[10] = gtk_button_new_with_label("11");
    btn_cs[11] = gtk_button_new_with_label("12");

    // CSチャンネル選択用のボタンをデーブルに設置する。
    gtk_table_attach_defaults(GTK_TABLE(table[3]), btn_cs[0], 0, 1, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(table[3]), btn_cs[1], 1, 2, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(table[3]), btn_cs[2], 2, 3, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(table[3]), btn_cs[3], 0, 1, 1, 2);
    gtk_table_attach_defaults(GTK_TABLE(table[3]), btn_cs[4], 1, 2, 1, 2);
    gtk_table_attach_defaults(GTK_TABLE(table[3]), btn_cs[5], 2, 3, 1, 2);
    gtk_table_attach_defaults(GTK_TABLE(table[3]), btn_cs[6], 0, 1, 2, 3);
    gtk_table_attach_defaults(GTK_TABLE(table[3]), btn_cs[7], 1, 2, 2, 3);
    gtk_table_attach_defaults(GTK_TABLE(table[3]), btn_cs[8], 2, 3, 2, 3);
    gtk_table_attach_defaults(GTK_TABLE(table[3]), btn_cs[9], 0, 1, 3, 4);
    gtk_table_attach_defaults(GTK_TABLE(table[3]), btn_cs[10], 1, 2, 3, 4);
    gtk_table_attach_defaults(GTK_TABLE(table[3]), btn_cs[11], 2, 3, 3, 4);

    // ラジオボタンを選択したときの動作を設定する。
    g_signal_connect(G_OBJECT(radio_button[0]), "toggled",
                              G_CALLBACK(select_broadcasting),
                              GINT_TO_POINTER(0));
    g_signal_connect(G_OBJECT(radio_button[1]), "toggled",
                              G_CALLBACK(select_broadcasting),
                              GINT_TO_POINTER(1));
    g_signal_connect(G_OBJECT(radio_button[2]), "toggled",
                              G_CALLBACK(select_broadcasting),
                              GINT_TO_POINTER(2));

    // 地デジチャンネルボタンをクリックしたときの動作を設定する。
    g_signal_connect(G_OBJECT(btn_gr[0]), "clicked",
                              G_CALLBACK(select_channel), ch1_gr);
    g_signal_connect(G_OBJECT(btn_gr[1]), "clicked",
                              G_CALLBACK(select_channel), ch2_gr);
    g_signal_connect(G_OBJECT(btn_gr[2]), "clicked",
                              G_CALLBACK(select_channel), ch3_gr);
    g_signal_connect(G_OBJECT(btn_gr[3]), "clicked",
                              G_CALLBACK(select_channel), ch4_gr);
    g_signal_connect(G_OBJECT(btn_gr[4]), "clicked",
                              G_CALLBACK(select_channel), ch5_gr);
    g_signal_connect(G_OBJECT(btn_gr[5]), "clicked",
                              G_CALLBACK(select_channel), ch6_gr);
    g_signal_connect(G_OBJECT(btn_gr[6]), "clicked",
                              G_CALLBACK(select_channel), ch7_gr);
    g_signal_connect(G_OBJECT(btn_gr[7]), "clicked",
                              G_CALLBACK(select_channel), ch8_gr);
    g_signal_connect(G_OBJECT(btn_gr[8]), "clicked",
                              G_CALLBACK(select_channel), ch9_gr);
    g_signal_connect(G_OBJECT(btn_gr[9]), "clicked",
                              G_CALLBACK(select_channel), ch10_gr);
    g_signal_connect(G_OBJECT(btn_gr[10]), "clicked",
                              G_CALLBACK(select_channel), ch11_gr);
    g_signal_connect(G_OBJECT(btn_gr[11]), "clicked",
                              G_CALLBACK(select_channel), ch12_gr);

    // BSチャンネルボタンをクリックしたときの動作を設定する。
    g_signal_connect(G_OBJECT(btn_bs[0]), "clicked",
                              G_CALLBACK(select_channel), ch1_bs);
    g_signal_connect(G_OBJECT(btn_bs[1]), "clicked",
                              G_CALLBACK(select_channel), ch2_bs);
    g_signal_connect(G_OBJECT(btn_bs[2]), "clicked",
                              G_CALLBACK(select_channel), ch3_bs);
    g_signal_connect(G_OBJECT(btn_bs[3]), "clicked",
                              G_CALLBACK(select_channel), ch4_bs);
    g_signal_connect(G_OBJECT(btn_bs[4]), "clicked",
                              G_CALLBACK(select_channel), ch5_bs);
    g_signal_connect(G_OBJECT(btn_bs[5]), "clicked",
                              G_CALLBACK(select_channel), ch6_bs);
    g_signal_connect(G_OBJECT(btn_bs[6]), "clicked",
                              G_CALLBACK(select_channel), ch7_bs);
    g_signal_connect(G_OBJECT(btn_bs[7]), "clicked",
                              G_CALLBACK(select_channel), ch8_bs);
    g_signal_connect(G_OBJECT(btn_bs[8]), "clicked",
                              G_CALLBACK(select_channel), ch9_bs);
    g_signal_connect(G_OBJECT(btn_bs[9]), "clicked",
                              G_CALLBACK(select_channel), ch10_bs);
    g_signal_connect(G_OBJECT(btn_bs[10]), "clicked",
                              G_CALLBACK(select_channel), ch11_bs);
    g_signal_connect(G_OBJECT(btn_bs[11]), "clicked",
                              G_CALLBACK(select_channel), ch12_bs);

    // CSチャンネルボタンをクリックしたときの動作を設定する。
    g_signal_connect(G_OBJECT(btn_cs[0]), "clicked",
                              G_CALLBACK(select_channel), ch1_cs);
    g_signal_connect(G_OBJECT(btn_cs[1]), "clicked",
                              G_CALLBACK(select_channel), ch2_cs);
    g_signal_connect(G_OBJECT(btn_cs[2]), "clicked",
                              G_CALLBACK(select_channel), ch3_cs);
    g_signal_connect(G_OBJECT(btn_cs[3]), "clicked",
                              G_CALLBACK(select_channel), ch4_cs);
    g_signal_connect(G_OBJECT(btn_cs[4]), "clicked",
                              G_CALLBACK(select_channel), ch5_cs);
    g_signal_connect(G_OBJECT(btn_cs[5]), "clicked",
                              G_CALLBACK(select_channel), ch6_cs);
    g_signal_connect(G_OBJECT(btn_cs[6]), "clicked",
                              G_CALLBACK(select_channel), ch7_cs);
    g_signal_connect(G_OBJECT(btn_cs[7]), "clicked",
                              G_CALLBACK(select_channel), ch8_cs);
    g_signal_connect(G_OBJECT(btn_cs[8]), "clicked",
                              G_CALLBACK(select_channel), ch9_cs);
    g_signal_connect(G_OBJECT(btn_cs[9]), "clicked",
                              G_CALLBACK(select_channel), ch10_cs);
    g_signal_connect(G_OBJECT(btn_cs[10]), "clicked",
                              G_CALLBACK(select_channel), ch11_cs);
    g_signal_connect(G_OBJECT(btn_cs[11]), "clicked",
                              G_CALLBACK(select_channel), ch12_cs);

    // ウィンドウを閉じたときの動作を設定する。
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);

    // ウィンドウを表示する。
    gtk_widget_show_all(window);
    gtk_widget_hide(table[2]);
    gtk_widget_hide(table[3]);

    gtk_main();

    return 0;
}

②端末に以下のコマンドをコピー&ペーストして「Enter」キーを押す。

gcc -Wall -g ~/デスクトップ/tv.c -o ~/デスクトップ/tv `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0`

デスクトップに「tv」ファイルが生成する。これが視聴アプリである。

使い方

起動

○デスクトップの「tv」ファイル(「tv.c」ファイルではない)をダブルクリックする。

視聴アプリが起動する。

視聴

①見たい放送を選択する。

地デジとBSには私が住んでいる地域に合わせた設定がしてある。CSの設定はしていない。

②見たいチャンネルをクリックする。

デスクトップに「temp.ts」ファイルが生成され、VLCプレイヤーで再生される。録画している番組をリアルタイムで再生することによって視聴の代用としているわけである。

終了

○視聴アプリの「×」ボタンをクリックする。

VLCプレイヤーも終了し、デスクトップの「temp.ts」ファイルも削除される。

(2017/01/07更新)

「システムプログラムの問題が見つかりました」

Ubuntuを起動すると、「システムプログラムの問題が見つかりました」と表示されることがある。一度、表示されると、以降、起動するたびに表示されるようになるので鬱陶しい。

何らかの原因でクラッシュが発生するとcrashファイルが「/var/crash」フォルダーに生成する。そのcrashファイルが原因のようである。したがって、これを削除すれば、以降、表示されなくなる。

私の場合は大抵VirtualBoxが原因である。仮想マシンが突然クラッシュしたとき、crashファイルを生成させることがある。また、仮想マシンを終了させるのを忘れて実マシンを終了してしまったときもcrashファイルを生成させることがある。

①以下のコマンドを端末にコピー&ペーストして「Enter」キーを押す。

ls /var/crash

crashファイルの名前が表示される。一応、何がクラッシュしたのか確認しておく。

②以下のコマンドを端末にコピー&ペーストして「Enter」キーを押す。

sudo rm /var/crash/*

③「[sudo] **** のパスワード:」でパスワードを入力して「Enter」キーを押す。

crashファイルが削除される。

(2017/02/13更新)

Ubuntu 16.04 + Chinachu + PT2でテレビ

以前書いた記事にリンク切れ等がないかをチェックしたり、コマンドをまとめたり、一部削ったりしただけだが、多分これで大丈夫だと思う。もしおかしなところがあったらお知らせ下さい。

準備

①PT2をPCのマザーボードに装着する。

②ICカードリーダーをPCのUSBポートに接続する。

ICカードリーダーにはSCR3310-NTTComを使った。

パッケージのインストール

どれがどれに必要なのかよく分かっていないが、とりあえずこれだけ入れておけば大丈夫そう。

①端末に以下のコマンドをコピー&ペーストして「Enter」キーを押す。

sudo apt-get -y install autoconf build-essential curl git-core libccid libpcsc-perl libpcsclite-dev libpcsclite1 libssl-dev libtool linux-headers-`uname -r` mercurial pcsc-tools pcscd pkg-config yasm

②「[sudo] **** のパスワード:」でパスワードを入力して「Enter」キーを押す。

カードリーダーの動作確認

①端末に以下のコマンドをコピー&ペーストして「Enter」キーを押す。

pcsc_scan

最後に

Japanese Chijou Digital B-CAS Card (pay TV)

のように表示されていればOK。

②「Ctrl」キーと「C」キーを同時に押し、実行中のコマンドを終了する。

ドライバのインストール

上に続けて実行する。

①端末に以下のコマンドをコピー&ペーストして「Enter」キーを押す。

sudo gedit /etc/modprobe.d/blacklist.conf

テキストエディターで「blacklist.conf」ファイルが開かれる。

②最終行に

blacklist earth-pt1

を追記する。

③テキストエディターの「保存」ボタンをクリックする。

④テキストエディターの「×」ボタンをクリックして閉じる。

⑤端末に以下のコマンドをコピー&ペーストして「Enter」キーを押す。

hg clone http://hg.honeyplanet.jp/pt1.oyama/ ~/ダウンロード/pt1_driver_oyama

「~/ダウンロード」フォルダーに「pt1_driver_oyama」フォルダーが保存される。

⑥端末に以下のコマンドをコピー&ペーストして「Enter」キーを押す。

cd ~/ダウンロード/pt1_driver_oyama;hg revert -r c44e16dbb0e2 --all;hg revert -r tip --all

⑦端末に以下のコマンドをコピー&ペーストして「Enter」キーを押す。

gedit driver/pt1_pci.c

テキストエディターで「pt1_pci.c」ファイルが開かれる。

この手順はカーネル4.2以降で必要になったようである。

http://baalzephon.no-ip.org/tech/index.php?Linux%2F%E3%83%86%E3%83%AC%E3%83%93%E9%96%A2%E9%80%A3%2FPT2

⑧11行目の

#include <linux/interrupt.h>

の下に

#include <linux/version.h>

を追記する。

⑨14行目(1行ずれたので元は13行目)の

#include <asm/io.h>

の下に

#if LINUX_VERSION_CODE >=KERNEL_VERSION(4,2,0)
#include <linux/vmalloc.h>
#endif

を追記する。

⑩テキストエディターの「保存」をクリックする。

⑪テキストエディターの「×」ボタンをクリックして閉じる。

⑫端末に以下のコマンドをコピー&ペーストして「Enter」キーを押す。

cd driver;make clean;make;sudo make install;sudo modprobe pt1_drv

⑬PCを再起動する。

ドライバの動作確認

○端末に以下のコマンドをコピー&ペーストして「Enter」キーを押す。

ls -la /dev/pt*video*

下のように表示されればOK。

crw-rw-rw- 1 root video 245, 0 11月 28 09:43 /dev/pt1video0
crw-rw-rw- 1 root video 245, 1 11月 28 09:43 /dev/pt1video1
crw-rw-rw- 1 root video 245, 2 11月 28 09:43 /dev/pt1video2
crw-rw-rw- 1 root video 245, 3 11月 28 09:43 /dev/pt1video3

recpt1のインストール

recpt1は「/pt1_driver_oyama」フォルダーの中にもある。だが、そのrecpt1は後でインストールするChinachuと相性が悪いらしく、番組表の取得で失敗する。そこで別バージョンのrecpt1をインストールする。

①端末に以下のコマンドをコピー&ペーストして「Enter」キーを押す。

wget -P ~/ダウンロード https://github.com/stz2012/recpt1/archive/master.zip;unzip ~/ダウンロード/master.zip -d ~/ダウンロード;cd ~/ダウンロード/recpt1-master/recpt1;./autogen.sh;./configure --enable-b25;make clean;make;sudo make install

②「[sudo] **** のパスワード:」でパスワードを入力して「Enter」キーを押す。

録画テスト

○端末に以下のコマンドをコピー&ペーストして「Enter」キーを押す。

recpt1 --b25 --strip --device /dev/pt1video2 27 30 ~/test.ts

上のコマンドは私の住んでいる地域ではNHK総合を30秒録画するものである。「ホーム」フォルダーに「test.ts」ファイルが生成するが、ちゃんと録画できていればOK。

ドライバの再インストール

カーネルの更新があった場合(パスワードを要求されるアップデートがあった場合、大抵カーネルの更新がある)、再起動後ではドライバが使えなくなるので、再インストールする必要がある。

①端末に以下のコマンドをコピー&ペーストして「Enter」キーを押す。

cd ダウンロード/pt1_driver_oyama/driver;make clean;make;sudo make install

②パスワードを入力して「Enter」キーを押す。

③PCを再起動する。

④端末に以下のコマンドをコピー&ペーストして「Enter」キーを押す。

ls -la /dev/pt*video*

Chinachuのダウンロード及びインストール

①端末に以下のコマンドを入力して「Enter」キーを押す。

git clone git://github.com/kanreisa/Chinachu.git ~/chinachu;cd ~/chinachu/;./chinachu installer

②「what do you install? >」で「1」と入力して「Enter」キーを押す。

Chinachuの設定

上の手順に続けて実行する。

①端末に以下のコマンドを入力して「Enter」キーを押す。

cp config.sample.json config.json;gedit config.json

テキストエディターで「config.json」ファイルが開かれる。

②「config.json」ファイルを以下の内容で上書きする。

{
  "recordedDir" : "./recorded/",
  "temporaryDir": "/tmp/",

  "wuiUsers": [
    "akari:bakuhatsu"
  ],
  "wuiAllowCountries": ["JP"],

  "wuiPort"        : 10772,
  "wuiHost"        : "::",
  "wuiTlsKeyPath"  : null,
  "wuiTlsCertPath" : null,
  "wuiOpenServer"  : false,
  "wuiOpenPort"    : 20772,
  "wuiXFF"         : false,
  "wuiPreviewer"   : true,
  "wuiStreamer"    : true,
  "wuiFiler"       : true,
  "wuiConfigurator": true,

  "recordedFormat": "<date:yyyy年mm月dd日>_<title>.ts",

  "tuners": [
    {
      "name"        : "PT2-S1",
      "isScrambling": false,
      "types"       : [ "BS", "CS" ],
      "command"     : "recpt1 --device /dev/pt1video0 --b25 --strip --sid <sid> <channel> - -"
    },
    {
      "name"        : "PT2-S2",
      "isScrambling": false,
      "types"       : [ "BS", "CS" ],
      "command"     : "recpt1 --device /dev/pt1video1 --b25 --strip --sid <sid> <channel> - -"
    },
    {
      "name"        : "PT2-T1",
      "isScrambling": false,
      "types"       : [ "GR" ],
      "command"     : "recpt1 --device /dev/pt1video2 --b25 --strip --sid <sid> <channel> - -"
    },
    {
      "name"        : "PT2-T2",
      "isScrambling": false,
      "types"       : [ "GR" ],
      "command"     : "recpt1 --device /dev/pt1video3 --b25 --strip --sid <sid> <channel> - -"
    }
  ],

  "channels": [
    { "type": "GR", "channel": "27" },
    { "type": "GR", "channel": "26" },
    { "type": "GR", "channel": "25" },
    { "type": "GR", "channel": "22" },
    { "type": "GR", "channel": "21" },
    { "type": "GR", "channel": "24" },
    { "type": "GR", "channel": "23" },
    { "type": "GR", "channel": "16" },
    { "type": "GR", "channel": "20" },
    { "type": "GR", "channel": "18" },
    { "type": "GR", "channel": "32" },
    { "type": "GR", "channel": "28" },

    { "type": "BS", "channel": "101" },
    { "type": "BS", "channel": "103" },
    { "type": "BS", "channel": "141" },
    { "type": "BS", "channel": "151" },
    { "type": "BS", "channel": "161" },
    { "type": "BS", "channel": "171" },
    { "type": "BS", "channel": "181" },
    { "type": "BS", "channel": "211" },
    { "type": "BS", "channel": "222" }
  ],

  "operRecCmdSpan": 1000
}

「wuiUsers」の「"akari:bakuhatsu"」は「akari」がユーザ名、「bakuhatsu」がパスワードとなる。デフォルトのままでよいと思うが、外部からアクセスできるようにする場合は変えたほうが安全である。

「recordedFormat」は録画ファイル名のフォーマットの設定だが、私の好みに変更している。

「tuners」の設定はPT2用に修正した。

「channels」の設定は私の環境に合わせている。地デジのチャンネル番号は住んでいる地域によって違う。

チャンネル番号については以下のページを参照。

https://ja.wikipedia.org/wiki/%E3%83%86%E3%83%AC%E3%83%93%E5%91%A8%E6%B3%A2%E6%95%B0%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB

「operRecCmdSpan」の設定はChinachuの開発者がPT2で使用した場合は設定したほうがよいと言っているので追加した。

③テキストエディターの「保存」をクリックする。

④テキストエディターの「×」ボタンをクリックして閉じる。

ルール設定ファイルの作成

上に続けて実行する。

○端末に以下のコマンドを入力して「Enter」キーを押す。

echo [] > rules.json

動作チェック

上に続けて実行する。

①端末に以下のコマンドを入力して「Enter」キーを押す。

./chinachu service wui execute

端末に表示されるものを見て、動作しているか確認する。

②「Ctrl」キーと「C」キーを同時に押し、実行中のコマンドを終了する。

③端末に以下のコマンドを入力して「Enter」キーを押す。

./chinachu update -f

これはEPG取得をテストする手順である。

システムへの設定

上に続けて実行する。

①端末に以下のコマンドを入力して「Enter」キーを押す。

./chinachu service operator initscript > /tmp/chinachu-operator;./chinachu service wui initscript > /tmp/chinachu-wui;sudo chown root:root /tmp/chinachu-operator /tmp/chinachu-wui;sudo chmod +x /tmp/chinachu-operator /tmp/chinachu-wui;sudo mv /tmp/chinachu-operator /tmp/chinachu-wui /etc/init.d/

②「[sudo] **** のパスワード:」でパスワードを入力して「Enter」キーを押す。

③端末に以下のコマンドを入力して「Enter」キーを押す。

sudo ln -s /usr/lib/insserv/insserv /sbin/insserv;sudo insserv chinachu-operator;sudo insserv chinachu-wui

「sudo ln -s /usr/lib/insserv/insserv /sbin/insserv」がないとエラーになる。

http://pcok.jp/?p=1731

サービスの開始

上に続けて実行する。

○端末に以下のコマンドを入力して「Enter」キーを押す。

sudo systemctl unmask chinachu-operator;sudo systemctl unmask chinachu-wui;sudo service chinachu-operator start;sudo service chinachu-wui start

「sudo systemctl unmask chinachu-operator」、「sudo systemctl unmask chinachu-wui」がないとエラーになる。

http://d.hatena.ne.jp/ore_de_work/touch/20151018/1445167890

番組表の表示

①Firefoxのアドレスバーに「http://localhost:10772」と入力して「Enter」キーを押す。

②「ユーザ名とパスワードを入力してください」で「ユーザ名」に「akari」、「パスワード」に「bakuhatsu」と入力する。

「wuiUsers」の設定を変更した場合はもちろん、それに合わせる。入力するのは初回だけで、2回目以降は初めから入力されている。

③「OK」をクリックする。

地デジの番組表だけを見たい場合は番組表で「GR」のみにチェックを入れ、BSの番組表だけを見たい場合は「BS」のみにチェックを入れる。

ライブ視聴

①番組表でテレビ局名を右クリックする。

②「ライブ視聴」をクリックする。

③「ストリーミング再生」で「再生」をクリックする。

ライブ視聴するとチューナーがロックされるが、ライブ視聴をやめてもロックが外れず、録画予約に失敗することがある。番組表を閉じるとロックが外れるので、録画予約しているときはいったん番組表を閉じたほうが無難かもしれない。

録画予約

①番組表で録画予約したい番組を右クリックする。

②「予約」をクリックする。

③「手動予約」で「予約」をクリックする。

④「成功」で「OK」をクリックする。

録画ファイルはデフォルトの設定のままなら「~/chinachu/recorded」フォルダーに保存される。

参考サイト

Mercurial > pt1.oyama

http://hg.honeyplanet.jp/pt1.oyama

stz2012

https://github.com/stz2012

kanreisa/Chinachu

https://github.com/kanreisa/Chinachu

(2016/12/01更新)