Bitcoinチャートのデータベース化

MySQLサーバでBitcoinチャートのデータベース化をしてみました。

 

準備

MySQLサーバをインストールします。

Binanceのサイトでユーザ登録をしAPIキーを取得します。APIキーはjson形式で保存します。

Pythonの環境設定をします。

mkdir environments
cd environments
python3 -m venv test_env
source test_env/bin/activate

Python3のBinance APIをインストールします。

pip3 install python-binance

 

Binanceからデータを取得

BinanceからBTC/USDTチャートデータをダウンロードします。今回の例では日足で1年分でデーターをダウンロードしてCSV出力します。

get_binance_data.py

from binance.client import Client
import os
import json
import time
import csv

binance_key_json = open('../config/binance_account.json', 'r')
binance_key = json.load(binance_key_json)
api_key = binance_key["key"]
api_secret = binance_key["secret"]
client = Client(api_key, api_secret)
#filename = "binance_1m_1yr.csv"
#filename = "binance_5m_1yr.csv"
#filename = "binance_1h_1yr.csv"
filename = "binance_1d_1yr.csv"

def candlesticks():
#    klines = client.get_historical_klines("BTCUSDT", Client.KLINE_INTERVAL_1MINUTE, "1 year ago UTC")
#    klines = client.get_historical_klines("BTCUSDT", Client.KLINE_INTERVAL_5MINUTE, "1 year ago UTC")
#    klines = client.get_historical_klines("BTCUSDT", Client.KLINE_INTERVAL_15MINUTE, "1 year ago UTC")
#    klines = client.get_historical_klines("BTCUSDT", Client.KLINE_INTERVAL_1HOUR, "1 year ago UTC")
    klines = client.get_historical_klines("BTCUSDT", Client.KLINE_INTERVAL_1DAY, "1 year ago UTC")
    return klines

data = candlesticks()
with open(filename, 'w') as csvfile:
    fieldnames = ['timestamp', 'open', 'high', 'low', 'close', 'volume']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writeheader()
    for n in data:
        timestamp = str(int(n[0] / 1000))
        writer.writerow({'timestamp' : timestamp, 'open' : n[1], 'high' : n[2], 'low' : n[3], 'close' : n[4], 'volume' : n[5]})

このスクリプトを走らせるとbinance_1h_1yr.csvというファイルができます。

ますMySQLでデータベース作成とユーザ登録をします。

sudo mysql -u root -p
Enter password:

mysql> CREATE DATABASE Binance;
mysql> use Binance;
Database changed

mysql> CREATE TABLE chart_1d (timestamp INT UNSIGNED NOT NULL UNIQUE, open FLOAT NOT NULL, high FLOAT NOT NULL, low FLOAT NOT NULL, close FLOAT NOT NULL, volume FLOAT NOT NULL);
...

mysql> SHOW tables;
+-------------------+
| Tables_in_Binance |
+-------------------+
| chart_15m         |
| chart_1d          |
| chart_1h          |
| chart_1m          |
| chart_5m          |
+-------------------+
5 rows in set (0.00 sec)

mysql> DESCRIBE chart_1d;
+-----------+------------------+------+-----+---------+-------+
| Field     | Type             | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+-------+
| Timestamp | int(10) unsigned | NO   | PRI | NULL    |       |
| Open      | float            | NO   |     | NULL    |       |
| High      | float            | NO   |     | NULL    |       |
| Low       | float            | NO   |     | NULL    |       |
| Close     | float            | NO   |     | NULL    |       |
| Volume    | float            | NO   |     | NULL    |       |
+-----------+------------------+------+-----+---------+-------+
6 rows in set (0.01 sec)

mysql> SELECT USER,HOST FROM mysql.user;
+------------------+-----------+
| user             | host      |
+------------------+-----------+
| debian-sys-maint | localhost |
| mysql.session    | localhost |
| mysql.sys        | localhost |
| root             | localhost |
+------------------+-----------+
4 rows in set (1.14 sec)

mysql> GRANT SELECT,INSERT,UPDATE,DELETE ON Binance.* TO 'user'@'localhost' IDENTIFIED BY 'pass';
Query OK, 0 rows affected, 1 warning (0.56 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (1.48 sec)

mysql> exit

先程のbinance_1h_1yr.csvというファイルをchart_1d.csvにリネームしてMySQLに読み込ませます。

sudo -s
# csvfile='chart_1d.csv'
# mysqlimport --ignore-lines=1\
             --fields-terminated-by=,\
             --local -u root -p\
             Binance \
             $csvfile

ユーザー名でMySQLにログインします。

mysql -u user -p
Enter password:

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| Binance            |
+--------------------+
2 rows in set (0.12 sec)

mysql> USE Binance;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database change

mysql> SHOW tables;
+-------------------+
| Tables_in_Binance |
+-------------------+
| chart_15m         |
| chart_1d          |
| chart_1h          |
| chart_1m          |
| chart_5m          |
+-------------------+
5 rows in set (0.03 sec)

mysql> DESCRIBE chart_1d;
+----------+------------------+------+-----+---------+-------+
| Field    | Type             | Null | Key | Default | Extra |
+----------+------------------+------+-----+---------+-------+
| Timestamp| int(10) unsigned | NO   |     | NULL    |       |
| Open     | float            | NO   |     | NULL    |       |
| High     | float            | NO   |     | NULL    |       |
| Low      | float            | NO   |     | NULL    |       |
| Close    | float            | NO   |     | NULL    |       |
| Volume   | float            | NO   |     | NULL    |       |
+----------+------------------+------+-----+---------+-------+
6 rows in set (0.13 sec)

mysql> SELECT * FROM chart_1d;
+------------+---------+---------+---------+---------+---------+
| Timestamp  | Open    | High    | Low     | Close   | Volume  |
+------------+---------+---------+---------+---------+---------+
| 1519084800 | 11147.1 |   11786 | 11100.6 |   11201 | 48153.4 |
...

...
| 1550275200 | 3602.49 |  3648.2 | 3597.91 | 3618.41 |   19566 |
| 1550361600 | 3617.22 | 3700.11 |  3604.4 | 3667.58 | 25690.2 |
| 1550448000 | 3667.62 |    3925 |    3655 |  3898.6 | 64042.7 |
| 1550534400 | 3897.35 | 3974.98 |    3856 |  3912.9 |   18106 |
+------------+---------+---------+---------+---------+---------+
365 rows in set (0.16 sec)

チャート情報が出力できていれば完了です。

 

mysql-connector-pythonのインストール

pipでインストールします。

pip3 install mysql-connector-python

簡単なスクリプトを使ってテストしてみます。去年の3月のチャート情報を出力してみます。
test.py

import time
import datetime
import mysql.connector
from contextlib import closing

dbname  = 'Binance'
table   = 'chart_1d'
t_from  = (2018,3,1)
t_to    = (2018,3,31)

_d = datetime.date(t_from[0], t_from[1], t_from[2])
utime_from = time.mktime(_d.timetuple())
_d = datetime.date(t_to[0], t_to[1], t_to[2])
utime_to = time.mktime(_d.timetuple())

def db_read(dbname):
    with closing(mysql.connector.connect(user = 'user', password = 'pass', host = 'localhost', database = dbname)) as conn:
        c = conn.cursor()
        query = "select * from " + str(table) + " where Unixtime > " + str(utime_from) + " and Unixtime < " + str(utime_to) + ";"
        c.execute(query)
        for row in c.fetchall():
            print(row[0], row[1], row[2], row[3], row[4], row[5])

db_read(dbname)

結果:

1519948800 10923.4 11200.0 10770.0 11039.0 23910.7
1520035200 11039.0 11544.0 11015.0 11464.5 21287.2
1520121600 11464.5 11565.0 11050.0 11515.0 17295.9
1520208000 11515.0 11710.0 11415.0 11454.0 15144.2
1520294400 11455.0 11455.0 10555.5 10716.5 29515.6
1520380800 10716.5 10899.0 9389.31 9910.0 50647.7
1520467200 9910.0 10099.0 9060.0 9271.64 41109.5
1520553600 9267.07 9410.0 8329.0 9227.0 64112.3
1520640000 9230.0 9490.0 8667.07 8770.22 37180.0
1520726400 8770.22 9740.0 8450.0 9533.57 44326.0
1520812800 9533.57 9888.88 8780.0 9131.34 42230.8
1520899200 9131.34 9474.0 8823.0 9150.0 40191.4
1520985600 9151.92 9333.78 7900.28 8170.0 49708.1
1521072000 8184.01 8430.0 7650.0 8240.98 52291.0
1521158400 8240.98 8611.64 7900.0 8260.0 38815.4
1521244800 8260.0 8348.62 7721.99 7824.8 33110.2
1521331200 7824.01 8317.4 7322.0 8189.99 59488.2
1521417600 8189.0 8705.23 8088.4 8600.0 55297.1
1521504000 8595.01 9050.0 8280.0 8909.98 44865.1
1521590400 8909.96 9177.01 8750.6 8885.0 39972.4
1521676800 8884.82 9100.0 8465.1 8722.9 40617.6
1521763200 8720.0 8909.0 8269.0 8898.03 39991.0
1521849600 8898.04 8999.95 8491.0 8546.86 35466.6
1521936000 8531.25 8669.85 8365.77 8470.15 29001.8
1522022400 8470.14 8514.89 7831.0 8134.23 44033.6
1522108800 8134.22 8215.94 7730.0 7795.51 37427.6
1522195200 7795.51 8109.0 7728.0 7949.3 26401.3
1522281600 7949.3 7975.0 6941.11 7090.14 54620.9
1522368000 7090.16 7292.43 6600.1 6840.23 65306.0

 

デーベースのアップデート

調べながら作ってみました。
update_binance_database.py

#!/usr/bin/env python3

from binance.client import Client
import os
import sys
import re
import json
import time
import datetime
import mysql.connector
from contextlib import closing
from config.parm_binance import parm_binance, parm_binance_db

def candlesticks(client, tables):
    dict = {}
    for k in tables:
        if tables[k] == 'chart_1d':
            klines = client.get_historical_klines("BTCUSDT", Client.KLINE_INTERVAL_1DAY, "2 day ago UTC")
        elif tables[k] == 'chart_4h':
            klines = client.get_historical_klines("BTCUSDT", Client.KLINE_INTERVAL_4HOUR, "2 day ago UTC")
        elif tables[k] == 'chart_1h':
            klines = client.get_historical_klines("BTCUSDT", Client.KLINE_INTERVAL_1HOUR, "1 day ago UTC")
        elif tables[k] == 'chart_15m':
            klines = client.get_historical_klines("BTCUSDT", Client.KLINE_INTERVAL_15MINUTE, "1 day ago UTC")
        elif tables[k] == 'chart_5m':
            klines = client.get_historical_klines("BTCUSDT", Client.KLINE_INTERVAL_5MINUTE, "1 day ago UTC")
        elif tables[k] == 'chart_1m':
            klines = client.get_historical_klines("BTCUSDT", Client.KLINE_INTERVAL_1MINUTE, "1 day ago UTC")
        dict.update({k : klines})
    return dict

def update(dbname, tables, db_user, db_pass, key, value):
    with closing(mysql.connector.connect(user = db_user, password = db_pass, host = 'localhost', database = dbname)) as conn:
        c = conn.cursor()
        for n in value:
            unixtime = str(int((n[0] / 1000)))
            query = str(unixtime) + ',' + str(n[1]) + ',' + str(n[2]) + ',' + str(n[3]) + ',' + str(n[4]) + ','  + str(n[5])
            query2 = "Open=" + str(n[1]) + ',' + "High=" + str(n[2]) + ',' + "Low=" + str(n[3]) + ',' + "Close=" + str(n[4]) + ','  + "Volume=" + str(n[5])
            action = ("INSERT INTO " + str(tables[key]) + " (Unixtime, Open, High, Low, Close, Volume) VALUES (" + str(query) +
                     ") ON DUPLICATE KEY UPDATE " + str(query2) + ";")
            c.execute(action)
        conn.commit()

def check_db(dbname, tables, db_user, db_pass, line_num):
    line_num = line_num + 2
    with closing(mysql.connector.connect(user = db_user, password = db_pass, host = 'localhost', database = dbname)) as conn:
        c = conn.cursor()
        for key, tb in tables.items():
            action = 'SELECT * FROM ( SELECT * FROM ' + str(tb) + ' ORDER BY Unixtime DESC LIMIT ' + str(line_num) + ') sub ORDER BY Unixtime ASC;'
            c.execute(action)
            _diff1 = int()
            _diff2 = int()
            _t_row0 = int()
            print("\n^" + str(tb))
            for row in c.fetchall():
                if _diff1 != 0 and _diff2 != 0:
                    print(_t_row0, time.ctime(row[0]), 'BTC CLOSE:', row[4])
                _diff2 = _diff1
                _diff1 = row[0]
                _t_row0 = _diff1 - _diff2
    print('')

def read_cmdline():
    arg = str()
    if len(sys.argv) > 1:
        for n in range(1, len(sys.argv)):
            if re.match( r'check|help', sys.argv[n], re.M|re.I):
                arg = sys.argv[n]
        else:
            pass
    else:
        pass
    if arg == 'help':
        help()
        exit(0)
    return arg

def help():
    print("")
    print("Command : python3 update_binance_database.py [arg]")
    print("")
    print("    check      ---   Display latest 25 lines")
    print("    help       ---   Display this help and exit")
    print("")

### MAIN ###
def main():
    binance_config    = parm_binance()
    binance_config_db = parm_binance_db()
    os.environ['TZ']  = binance_config['timezone']
    time.tzset()
    binance_key_json  = open('./config/binance_account.json', 'r')
    binance_key       = json.load(binance_key_json)
    api_key           = binance_key["key"]
    api_secret        = binance_key["secret"]
    client            = Client(api_key, api_secret)
    dbname            = binance_config_db['database']
    tables            = binance_config_db['tables']
    db_user           = binance_config_db['db_user']
    db_pass           = binance_config_db['db_pass']
    line_num          = 25

    arg = read_cmdline()
    if arg == '':
        data = candlesticks(client, tables)
        for key, value in data.items():
            print('{:>5}'.format(key), 'updating...', end='')
            update(dbname, tables, db_user, db_pass, key, value)
            print('[done]')

        print("\n", 'Update completed successfully.', "\n")
    elif arg == 'check':
        check_db(dbname, tables, db_user, db_pass, line_num)

if __name__ == "__main__":
    main()

 

その他

Backup

mysqldump -u root -p --add-drop-table Binance > Binance.sql

Restore

mysql -u root -p Binance < Binance.sql

Passwordの設定

mysql> SHOW VARIABLES LIKE 'validate_password%';
+--------------------------------------+--------+
| Variable_name                        | Value  |
+--------------------------------------+--------+
| validate_password_check_user_name    | OFF    |
| validate_password_dictionary_file    |        |
| validate_password_length             | 8      |
| validate_password_mixed_case_count   | 1      |
| validate_password_number_count       | 1      |
| validate_password_policy             | MEDIUM |
| validate_password_special_char_count | 1      |
+--------------------------------------+--------+
7 rows in set (0.03 sec)

mysql> SET GLOBAL validate_password_length=4;
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL validate_password_policy=LOW;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW VARIABLES LIKE 'validate_password%';
+--------------------------------------+-------+
| Variable_name                        | Value |
+--------------------------------------+-------+
| validate_password_check_user_name    | OFF   |
| validate_password_dictionary_file    |       |
| validate_password_length             | 4     |
| validate_password_mixed_case_count   | 1     |
| validate_password_number_count       | 1     |
| validate_password_policy             | LOW   |
| validate_password_special_char_count | 1     |
+--------------------------------------+-------+
7 rows in set (0.00 sec)

以上です。

チャートのデータベース化のメリット

アルゴリズムの計算に大量のデータをサイトから引張ってきましたが、データベースの更新に必要なだけで済むのでネットワーク負荷がかなり押さえられます。しかし最大のメリットはシュミレーションが出来るようになります。試しに10日分をシュミレーションしてみた結果です。

./report_all.py
^
 DB name      : binance_test0.db
 Action       : profit
 From         : 00:02:00 01/01/19 JST
 TO           : 21:33:00 01/09/19 JST
 Transactions :   202
 Price(high)  :  4017.55
 Price(low)   :  3671.58
 Income       :  -329.13
 Fee          :   582.72
 Profit       :  -911.85

昨日までの一日分

./report_all.py
^
 DB name      : binance_test0.db
 Action       : profit
 From         : 00:12:00 02/19/19 JST
 TO           : 23:45:00 02/19/19 JST
 Transactions :    15
 Price(high)  :  3936.03
 Price(low)   :  3801.62
 Income       :    90.41
 Fee          :    43.73
 Profit       :    46.68

一月分

^
 DB name      : binance_test0.db
 Action       : profit
 From         : 00:03:00 01/19/19 JST
 TO           : 23:45:00 02/19/19 JST
 Transactions :   665
 Price(high)  :  3936.03
 Price(low)   :  3383.00
 Income       :   -25.25
 Fee          :  1769.37
 Profit       : -1794.62

部分的には利益がだせますがトータルではかなりの損失です。

追記:

チャートのデータベース化してシュミレーションをするとかなりCPUパワーとリソースを使います。メモリーが十分(16GB以上)あれば幾分緩和されますがそれでも不具合が生じます。MySQLで次のようなエラーがでました。

ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0

このエラーは何らかの原因で接続に問題が起こりタイムアウトエラーを起こしたときのエラーです。解決方法は2つあり、ひとつはMySQLの設定ファイルに次のように追加します。

[mysqld]
connect_timeout = 100

もう一つは/etc/hosts.allowに次のように追加します。

mysql: ALL: allow

 

KINDLE 3 Hack

一時、ブームを呼び起こした電子Bookですが、だいぶ長く放置して今まで忘れていました。旅行に持っていくこともあったのですが何気に紙の本のほうが良いのです。整理したときに出てきたので少しメンテナンス(hacking)してみました。このKindle 3はARM11なのでDebianは入りそうはないので、もしかしたらOpenWrtならchrootで入るかも知れません。しかし入れたところであまり使いみちなさそうなので、Hackingがどの程度できるのか調べてみました。

USBNET – ストレージモードからUSBNETを使えるようにします。telnetとsshが使えます。sshが使えたところで特に何もできません。HOMEでdelキーを押してから、

;debugOn

次に、delキーをおしてから、

~usbNetwork

とするとUSBNETにが使えるようになります。ちなみに~helpにするとヘルプコマンドがでます。Kindle側は192.168.2.2/24で固定です。

カスタムFont – これが一番役に立つと思います。Kindleのフォントはあまり綺麗でないので入れ替えることができます。

カスタムScreensaver – お気に入りの壁紙をKindleのスクリーンセイバーにできます。

kindlepdfviewer – マルチドキュメントビュワーです。PDFのほかにマンガのCBZファイルを見るのに重宝します。

ほかにもあるのですが特に興味もないのでこのくらいにしておきます。無料のeBookはProject GutenbergかManyBooks.netからmobiフォーマットのファイルをダウンロードします。かなりの蔵書数があるのでこのサイトだけでいいコレクションが出来上がります。

実はKindleはオリジナルファームウェアのほかに中国版というのがあります。

このドゥオカンと呼ばれるファームウェアを入れると中国語(PRC)の音読ができるので中国語の勉強ができます。

Kindle + Simpsons Comics = Kinpsons?

追記:CBR、PDFの変換はcalibreを使うと簡単です。

Kindleとコミックスは相性がよいのでSimpsons Comicsを入れてみました。日本の場合は役人の頭がおかしいのでリンクは貼らずにファイル名だけ記載しておきます。(→NEWS:違法ダウンロード対象拡大に漫画家ら反対 国会内で集会)

  • Simpsons Comics (1-219) (1993-2015) GetComics.INFO

このファイルはCBZ、CBR、PDFの混成ファイルになっています。そこで標準のKindleのビューワーはCBRファイルは読めないのでCBZファイルに変換します。kindlepdfviewerでは試していませんが見れる可能性はありますが、扱いやすいようにCBRとPDFをCBZ形式に変換します。CBRからCBZの変換は次のサイトのスクリプトを使います。

少しスクリプトを変更して次のようにしました。

#!/bin/bash
# Author: Alon Ivtsan
# License: GPL3+

for FILE in *{.cbr,.CBR}
do
[ -e "$FILE" ] || continue
echo Converting $FILE to cbz format.
DIR="${FILE%.*}"
mkdir "$DIR";
unar ./"$FILE" -o "$DIR";
pushd "$DIR";
D2=`ls -d */`;
mv "$D2"/* . && rm -rf "$D2";
[ -f ../"$DIR".cbz ] && rm -f ../"$DIR".cbz
zip -r ../"$DIR".cbz *;
popd;
#zip -r "$DIR".cbz "$DIR";
rm -r "$DIR";
#Remove or comment out this line if you want to keep cbr files
#rm "$FILE";
echo Conversion of $FILE successful!
done

PDFからCBZは次のスクリプトを使います。

Ubuntu Bionicはちょっと問題があってpdftkパッケージがありません。そこで次のサイトを参考にpdftkをインストールします。またImageMagickはPDF変換がデフォルトで禁止されているので次のように修正します。

/etc/ImageMagick-6/policy.xml

<policy domain="coder" rights="read|write" pattern="{PS,PDF,XPS}" />
sudo apt install git default-jdk-headless ant \
    libcommons-lang3-java libbcprov-java

Simpsons Comicsのディレクトリに移動します。

git clone https://gitlab.com/pdftk-java/pdftk.git
cd pdftk
mkdir lib
ln -st lib /usr/share/java/{commons-lang3,bcprov}.jar
ant jar

テスト:

java -jar build/jar/pdftk.jar --help

この新しいツールに合わせてスクリプトを変更します。このスクリプトは1つのPDFのしか処理できないのでバッチ化するといいです。(後から気がついたのですがオリジナルがPDF→CBRですがzipコマンドを使えばPDF→CBZにできます)

#!/bin/bash
#
# PDF2CBR
#
#

PDFTK="pdftk/build/jar/pdftk.jar"

echo "Creating pdf directory..."
mkdir "$1_pages"
cd "$1_pages"

echo "Splitting .pdf file into individual pdfs..."
#pdftk ../$1 burst
java -jar ../$PDFTK ../"$1" burst

echo "Removing PDFtk report"
if [ -e doc_data.txt ]; then
        rm -f doc_data.txt
fi

PAGE_COUNT=`ls | wc -l`
echo "$PAGE_COUNT pdfs generated."

echo "Converting each .pdf page to .jpg..."
for file in *.pdf
do
#       convert -density 150 -quality 100 "$file" "${file%*.pdf}.jpg"
        convert -density 100x100 -quality 100 "$file" "${file%*.pdf}.jpg"
#       convert "$file" "${file%*.pdf}.jpg"
        rm -f "$file"
        let PAGE_COUNT--
        echo "$PAGE_COUNT pages left."
done

#echo "remove .pdf from filenames"
#for file in *.jpg
#do
#       mv "$file" "$file.jpg"
#done

echo "Creating .rar file..."
for file in *.jpg
do
    rar a "$1.rar" "$file"
done

echo "Renaming .rar to .cbr format..."
mv "$1.rar" ../"${1%.pdf}.cbr"

echo "Removing used directory and remaining garbage..."
cd ..
rm -Rf "$1_pages"
if [ -e "$1.cbr" ] ; then
        echo "File $1.cbr generated."
fi

echo "All done! Good reading!"

ファイルをすべてCBZに変換できたところで最後の難関はファイルサイズです。3.9GBあるので最大3GBのKindle 3には入りません。そこでSimpson親父なみのウルトラC的解決をめざします。例のスクリプトを編集します。
cbz4kndle3.sh

#!/bin/bash
# Author: Alon Ivtsan
# License: GPL3+

for FILE in *{.cbz,.CBZ}
do
[ -e "$FILE" ] || continue
echo "Adjusting $FILE for Kindle format."
DIR="${FILE%.*}"
mkdir "$DIR";
unzip ./"$FILE" -d "$DIR";
pushd "$DIR"
#mogrify  -strip -quality 75 -colorspace gray ./*{.jpg,.JPG};
#mogrify  -resize 480x736 -strip -density 50 ./*{.jpg,.JPG};
mogrify  -resize 480x736 -strip ./*{.jpg,.JPG};
[ -f ../"$DIR".cbz ] && rm -f ../"$DIR".cbz
zip -r ../"$DIR".cbz *;
#zip -r "$DIR".cbz "$DIR";
popd;
rm -r "$DIR";
#Remove or comment out this line if you want to keep cbr files
#rm "$FILE";
echo Conversion of $FILE successful!

done

ファイル変換が済んだらKindleをUSBでPCに接続してUSBストレージのルートディレクトリにcomicsディレクトリを作成してファイルをコピーします。
見る場合はShift+P+Dでビューワーを起動します。

Another Reset to Factory Defaults

一旦アップデートするとロールバックできません。デバイスをリセットしても蔵書が消えるだけです。アップデートしたときに間違ったバージョンのjailbreakアプリを入れたために次のエラーがでて復帰ができなくなりました。

Found another jailbreak aborting...
U006

そこでオリジナルのFWを入れてみます。かなり複雑な手順なので次のサイトの通り正確に進めていきます。

リンク先のpastebin pageからkernel-3.0.2 (factory)とmmcblk0p1-3.0.2 (factory)をダウンロードして解凍します。ファイルの拡張子をimgからbinに変えます。

つぎにリンク先の Freescale Advanced Toolkit(ATK)をダウンロードしてWindowsPCにインストールします。大事なことはドライバーの関係上32ビット版のWindowsにインストールします。もしかしたらnokia suiteのシリアルドライバーが使えるかも知れませんが、確証がないので古いXPのPCを引っ張り出してそこにインストールします。起動するときは管理者権限が必要とあったのでアイコンを右クリックして管理者モードで立ち上げます。

つぎにKindleをUSBケーブルでPCにつなぎます。そしてスイッチを30秒程度長押しして、(-)ボリュームボタンを1秒程度押して、スイッチを押さえたままボリュームボタンを離します。するとPCが「ピコッ」と電子音がなるので、デバイスを認識した合図なのでスイッチを離します。

ATKを立ち上げて手順通りに進めます。mmcblk0はサイズが大きいので数時間程度かかります。リカバリーが成功してブートできたらアマゾンのサイトからアップデート用ファイルをダウンロードして次のファイルを順番にアップデートします。

Update_kindle_3.1_B008.bin
Update_kindle_3.3_B008.bin
Update_kindle_3.4_B008.bin
Update_kindle_3.4_3.4.2_B008.bin

アップデートが完了したらjailbreakをインストールしてほかの作業を進めます。

Silent Movie( geekmaster kindle video player)

無声動画のアプリケーションです。動画ファイルをコマンドラインかKual Launcher(/mnt/us/extensions/Videos/menu.json)に登録して使います。無声動画なので字幕付きの動画を変換するといい感じになります。

変換する動画は次のスクリプトで作成します。

ffmpeg_sub.sh mp4ファイル subtextファイル

#!/bin/sh

ffmpeg -i "$1" -vf subtitles="$2" \
     -pix_fmt gray -f rawvideo -s 800x600 -r 7.7  - |./raw2gmv | \
     gzip > "${1%*.mp4}.gmv.gz"

(※)raw2gmvはサイトにあるソースコードをコンパイルして使います。: gcc -o raw2gmv raw2gmv.c

Another eBook reader

標準のeBook readerのほかにFBReader、Cool ReaderとKOReaderがあります。FBReaderはKindle3版は開発が止まっているよなので、Cool Readerをインストールしてみました。cr3-kindle-2012-10-04.zipとcr3runner.zipをダウンロードして、サイトの手順どおりにインストールします。

KOReaderは次のサイトからkoreader-kindle-legacy-arm-kindle-linux-gnueabi-vxxxx.xx.zipをダウンロードしてインストールします。インターフェースが良く出来ていて、ユニークな機能としてNight Modeがあります。

新しいeBook readerがインストールされたところで、ついでにフォントも追加してみました。

このサイトからフォントをダウンロードして/mnt/us/linkfonts/fontsにコピーします。eBookのsettingsでフォントを変更します。

Image viewer

KindleをUSB接続してrootディクトリ(/mnt/us)にpicturesというフォルダーを作ります。そのディレクトリの中にサブフォルダーを作ります。そのフォルダ名がKindleのBook名になります。そのフォルダーに画像(jpg,png,gif)を入れてAlt+Zでライブラリを更新します。USB接続を外してKindleからアクセスします。

参考

イメージファイルのマウント

イメージファイルをマウントするときmountコマンドならOKだがlosetup使うときは注意が必要です。offsetオプションを使うときは--sizelimitオプションを組み合わせないとパーティションの枠を越えてしまいます。

例)

losetup -v -f -o $((40960*512)) --sizelimit $((30736351*512)) eMMC_archlinux.img

本題に入るとイメージファイルのマウントをしたのはSamsungのChromeBookのeMMCにSDのArchlinuxを移し替えるためでした。結果はNGでした。原因は微妙なパーティションの仕様だと推測されます。既存のシステムをハッキングしてOSを入れ変えることはいろいろ制約があり一筋縄にはいきません。それで原点に立ち帰ってArchlinuxの指示通りインストールします。ただしswapを作りたいので次のように追加します。

cgpt add -i 3 -t data -b xxxxxx -s `expr yyyyyy - xxxxxx` -l Swap /dev/mmcblk0

カーネルをコピーしRootはSDのバックアップイメージをマウントするか直接SDをマウントしてcp -a等で移します。リブートして無事立ち上がることを確認してmkswap /dev/mmcblk0p3としてswapを作成しfstabに登録します。eMMCのサイズがSDより若干小さいのでeMMCのサイズに合わせてddコマンドでSDにコピーすればバックアップにもなります。

$ fdisk -l /dev/mmcblk0
Disk /dev/mmcblk0: 14.7 GiB, 15758000128 bytes, 30777344 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 261CDA79-03A0-704F-A217-1B45FA972C54

Device            Start      End  Sectors  Size Type
/dev/mmcblk0p1     8192    40959    32768   16M ChromeOS kernel
/dev/mmcblk0p2    40960 26999999 26959040 12.9G Microsoft basic data
/dev/mmcblk0p3 27000000 30777310  3777311  1.8G Microsoft basic data

$ free
              total        used        free      shared  buff/cache   available
Mem:        2057136      316088     1302804        5280      438244     1674936
Swap:       1888648           0     1888648

参考: