類似楽曲検索を作ってみました。

しばらくこのブログを止んでましたが、このブログを書きながらやっと作りたかったサイトが出来たので、ご報告。

まだ、作りかけですが、音楽のmp3データに含まれてる音楽サウンドの音声分析をもとに、ある曲の類似楽曲をコンピュータで自動で計算して、似ている感じの曲を表示しようというもの。

楽曲分析のアルゴリズムは、まだまだヨチヨチ歩きの段階ですが、こちら。


類似楽曲検索 - ちゃむサーチhttp://chamu.org/)』

AKB48恋するフォーチュンクッキーの類似楽曲だとこんな感じ。

恋するフォーチュンクッキー

Python - SSHモジュールのポート転送でMySQLにお気軽リモート接続

以前『sshトンネル(ポートフォワード)を使ってリモートのMySQLにつなぐ』という記事を書きましたが、sshコマンドでポートフォワードをしようとすると、パスワードログインの場合、毎回、パスワードを入力しないといけないのが面倒なので、

Python - SSHモジュールを使ってPythonでリモートのホストに自動ログイン。

これだと、リモートのMySQLのメンテナンス(更新)などの作業を自宅のパソコンから自動化したい場合、ポート転送用のPythonスクリプト自動起動するようにしておけば、マシン立ち上げと同時にポート転送が張れるので、便利ですね。


以下は、 Python - SSHモジュールさんのDemoにあったforward.pyを若干いじって、ローカルの3307ポートからリモートのMySQLの3306デフォルトポートへポート転送するようにさせて頂いたスクリプト

#!/usr/bin/env python

import getpass
import os
import socket
import select
import SocketServer
import sys

import ssh

server_host = "サーバーアドレス"
server_port = サーバSSHのログインポート
remote_host = "127.0.0.1"
remote_port = 3306
local_port = 3307
user = "SSHのログインユーザー名"
password = "パスワード"

g_verbose = True


class ForwardServer (SocketServer.ThreadingTCPServer):
    daemon_threads = True
    allow_reuse_address = True
    

class Handler (SocketServer.BaseRequestHandler):

    def handle(self):
        try:
            chan = self.ssh_transport.open_channel('direct-tcpip',
                                                   (self.chain_host, self.chain_port),
                                                   self.request.getpeername())
        except Exception, e:
            verbose('Incoming request to %s:%d failed: %s' % (self.chain_host,
                                                              self.chain_port,
                                                              repr(e)))
            return
        if chan is None:
            verbose('Incoming request to %s:%d was rejected by the SSH server.' %
                    (self.chain_host, self.chain_port))
            return

        verbose('Connected!  Tunnel open %r -> %r -> %r' % (self.request.getpeername(),
                                                            chan.getpeername(), (self.chain_host, self.chain_port)))
        while True:
            r, w, x = select.select([self.request, chan], [], [])
            if self.request in r:
                data = self.request.recv(1024)
                if len(data) == 0:
                    break
                chan.send(data)
            if chan in r:
                data = chan.recv(1024)
                if len(data) == 0:
                    break
                self.request.send(data)
        chan.close()
        self.request.close()
        verbose('Tunnel closed from %r' % (self.request.getpeername(),))


def forward_tunnel(local_port, remote_host, remote_port, transport):
    class SubHander (Handler):
        chain_host = remote_host
        chain_port = remote_port
        ssh_transport = transport
    ForwardServer(('', local_port), SubHander).serve_forever()


def verbose(s):
    if g_verbose:
        print s


def main():
    
    client = ssh.SSHClient()
    client.load_system_host_keys()

    verbose('Connecting to ssh host %s:%d ...' % (server_host, server_port))
    try:
        client.connect(server_host, port=server_port, username=user, password=password)
    except Exception, e:
        print '*** Failed to connect to %s:%d: %r' % (server_host, server_port, e)
        sys.exit(1)

    verbose('Now forwarding port %d to %s:%d ...' % (local_port, remote_host, remote_port))

    try:
        forward_tunnel(local_port, remote_host, remote_port, client.get_transport())
    except KeyboardInterrupt:
        print 'C-c: Port forwarding stopped.'
        sys.exit(0)


if __name__ == '__main__':
    main()


上記を、ローカルのパソコンで動かしておくと、↓こんな感じで、いつでも自宅のパソコンから、リーモートのMySQLにお気軽接続。

>>> import MySQLdb
>>> conn = MySQLdb.connect(db='music', host='127.0.0.1', port=3307 ,user='リモートのmySQLのユーザー名', passwd='パスワード')
>>> cursor = conn.cursor()
>>> cursor.execute( "select count(1) from mp3" )
1L
>>> cursor.fetchall()
((10439L,),)

統合数式処理システムSage (セイジ)にMySQL-pythonをインストール

統合数式処理システムSage からMySQLのデータにアクセスしたかったのでSageにMySQL-pythonをインストール

以下root権限で

1.Sageのシェルを起動

sage -sh

2.SageのシェルからMySQL-pythonをインストール

pypihttps://pypi.python.org/pypi/MySQL-python/)からMySQL-pythonをダウンロードしてインストール

wget https://pypi.python.org/packages/source/M/MySQL-python/MySQL-python-1.2.5.zip
unzip MySQL-python-1.2.5.zip
cd MySQL-python-1.2.5
python setup.py install


3.sageを起動してMySQLdbがimport出来ればOK

$ sage
----------------------------------------------------------------------
| Sage Version 5.8, Release Date: 2013-03-15                         |
| Type "notebook()" for the browser-based notebook interface.        |
| Type "help()" for help.                                            |
----------------------------------------------------------------------
sage: import MySQLdb
sage: 

eyeD3でMP3ファイルのタグ情報を取得する。

eyeD3でMP3ファイルのアーティスト名などのタグ情報を取得してみる。

1.インストール

pip install eyeD3

2.実行例

(1) コマンドラインから

$ eyeD3 'Last Christmas.mp3'
01 Last Christmas.mp3	[ 8.18 MB ]
-------------------------------------------------------------------------------
Time: 03:29	MPEG1, Layer III	[ 320 kb/s @ 44100 Hz - Stereo ]
-------------------------------------------------------------------------------
ID3 v2.3:
title: Last Christmas
artist: Taylor Swift
album: Holiday Collection
recording date: 2007
track: 1		genre: Country (id 2)
OTHER Image: [Size: 176995 bytes] [Type: image/png]
Description: 

-------------------------------------------------------------------------------

(2) Pythonから

$ python
Python 2.7.1 (r271:86832, Jul 31 2011, 19:30:53) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import eyed3
>>> audiofile = eyed3.load("Last Christmas.mp3')
>>> print audiofile.tag.artist.encode('utf-8')
Taylor Swift
>>> print audiofile.tag.album.encode('utf-8')
Holiday Collection
>>> print audiofile.tag.title
Last Christmas
>>> print audiofile.tag.track_num
(1, None)

ネットワーク上のExcelファイルをPythonで直接読み込む(xlrd)

1.python-excelライブラリをインストールする。

http://www.python-excel.org

先日、パッケージ管理システム『pip』をインストールしていたので、PythonExcel ファイルを 読み/書きするためのパッケージ xlrd, xlwt, xlutilsをpipでインストールする。

pip install xlrd xlwt xlutils

2.Pythonでネットワーク上のExcelファイルを直接読み込んで、セルの中身をそのままリストしてみる。

以下のテキストをexcel.pyとして保存し、

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import xlrd
import urllib

def read_xls(url):
    web = urllib.urlopen(url)
    webdata = web.read()
    web.close()

    book = xlrd.open_workbook(file_contents=webdata)
    sheet_1 = book.sheet_by_index(0)
    print 'sheet_name=', sheet_1.name.encode('utf-8')
    print 'ncols=', sheet_1.ncols
    print 'nrows=', sheet_1.nrows

    for col in range(sheet_1.ncols):
        print "----------------------------"
        for row in range(sheet_1.nrows):
            cell=sheet_1.cell(row,col)
            if cell.ctype == xlrd.XL_CELL_TEXT:
                print 'col=', col, 'row=', row, cell.value.encode('utf-8')
            else:
                print 'col=', col, 'row=', row, cell.value


if __name__ == '__main__':
    import sys
    if len( sys.argv ) > 1:
        url = sys.argv[1]

    read_xls(url)


コマンドラインから

./excel.py 'http://www.soumu.go.jp/johotsusintokei/field/data/gt010601.xls'

と打つと、総務省「分野別データ:通信:国際比較」のページ(http://www.soumu.go.jp/johotsusintokei/field/tsuushin08.html)にある「世界のインターネット利用者総数の推移」のExcel ファイル(http://www.soumu.go.jp/johotsusintokei/field/data/gt010802.xls)を直接読み込んで1シート目の各セルの値が、以下の形でプリントされます。

sheet_name= 世界のインターネット利用者総数の推移
ncols= 16
nrows= 7
----------------------------
col= 0 row= 0 世界のインターネット利用者総数の推移
col= 0 row= 1 
col= 0 row= 2 
col= 0 row= 3 利用者総数
col= 0 row= 4 
col= 0 row= 5 
col= 0 row= 6 (出典)「ITU Internet Report 2006: digital life」等
----------------------------
col= 1 row= 0 
col= 1 row= 1 
col= 1 row= 2 1991col= 1 row= 3 4.0
col= 1 row= 4 
col= 1 row= 5 
col= 1 row= 6 
----------------------------
col= 2 row= 0 
col= 2 row= 1 
col= 2 row= 2 1992col= 2 row= 3 7.0
col= 2 row= 4 
col= 2 row= 5 
col= 2 row= 6 
----------------------------
col= 3 row= 0 
col= 3 row= 1 
col= 3 row= 2 1993col= 3 row= 3 10.0
col= 3 row= 4 
col= 3 row= 5 
col= 3 row= 6 
----------------------------
col= 4 row= 0 
col= 4 row= 1 
col= 4 row= 2 1994col= 4 row= 3 21.0
col= 4 row= 4 
col= 4 row= 5 
col= 4 row= 6 
----------------------------
col= 5 row= 0 
col= 5 row= 1 
col= 5 row= 2 1995col= 5 row= 3 40.0
col= 5 row= 4 
col= 5 row= 5 
col= 5 row= 6 
----------------------------
col= 6 row= 0 
col= 6 row= 1 
col= 6 row= 2 1996col= 6 row= 3 74.0
col= 6 row= 4 
col= 6 row= 5 
col= 6 row= 6 
----------------------------
col= 7 row= 0 
col= 7 row= 1 
col= 7 row= 2 1997col= 7 row= 3 117.0
col= 7 row= 4 
col= 7 row= 5 
col= 7 row= 6 
----------------------------
col= 8 row= 0 
col= 8 row= 1 
col= 8 row= 2 1998col= 8 row= 3 145.0
col= 8 row= 4 
col= 8 row= 5 
col= 8 row= 6 
----------------------------
col= 9 row= 0 
col= 9 row= 1 
col= 9 row= 2 1999col= 9 row= 3 235.0
col= 9 row= 4 
col= 9 row= 5 
col= 9 row= 6 
----------------------------
col= 10 row= 0 
col= 10 row= 1 
col= 10 row= 2 2000col= 10 row= 3 390.0
col= 10 row= 4 
col= 10 row= 5 
col= 10 row= 6 
----------------------------
col= 11 row= 0 
col= 11 row= 1 
col= 11 row= 2 2001col= 11 row= 3 496.0
col= 11 row= 4 
col= 11 row= 5 
col= 11 row= 6 
----------------------------
col= 12 row= 0 
col= 12 row= 1 
col= 12 row= 2 2002col= 12 row= 3 623.0
col= 12 row= 4 
col= 12 row= 5 
col= 12 row= 6 
----------------------------
col= 13 row= 0 
col= 13 row= 1  
col= 13 row= 2 2003col= 13 row= 3 688.0
col= 13 row= 4 
col= 13 row= 5 
col= 13 row= 6 
----------------------------
col= 14 row= 0 
col= 14 row= 1 
col= 14 row= 2 2004col= 14 row= 3 875.0
col= 14 row= 4 
col= 14 row= 5 
col= 14 row= 6 
----------------------------
col= 15 row= 0 
col= 15 row= 1 (百万人)
col= 15 row= 2 2005col= 15 row= 3 965.0
col= 15 row= 4 
col= 15 row= 5 
col= 15 row= 6 

ServersMan@VPS(CentOS)にPostfixをインストール

以下、書きかけ

ServersMan@VPSCentOS)にPostfixをインストールしメールサーバーを構築してみました。(Postfixの設定にはWebminを使用)

1.Postfixのインストール

yum install postfix

2.インストールが完了しているか確認

# rpm -qa postfix
postfix-2.6.6-2.2.el6_1.x86_64

3.main.cfの編集

# vi /etc/postfix/main.cf# INTERNET HOST AND DOMAIN NAMES
#
# The myhostname parameter specifies the internet hostname of this
# mail system. The default is to use the fully-qualified domain name
# from gethostname(). $myhostname is used as a default value for many
# other configuration parameters.
#
#myhostname = host.domain.tld
#myhostname = virtual.domain.tld
myhostname = mail.chamu.org ←サーバのホスト名

# The mydomain parameter specifies the local internet domain name.
# The default is to use $myhostname minus the first component.
# $mydomain is used as a default value for many other configuration
# parameters.
#
#mydomain = domain.tld
mydomain = chamu.org ←ドメイン名

# SENDING MAIL
#
# The myorigin parameter specifies the domain that locally-posted
# mail appears to come from. The default is to append $myhostname,
# which is fine for small sites.  If you run a domain with multiple
# machines, you should (1) change this to $mydomain and (2) set up
# a domain-wide alias database that aliases each user to
# user@that.users.mailhost.
#
# For the sake of consistency between sender and recipient addresses,
# myorigin also specifies the default domain name that is appended
# to recipient addresses that have no @domain part.
#
#myorigin = $myhostname
#myorigin = $mydomain
myorigin = $mydomain ←追加

# RECEIVING MAIL

# The inet_interfaces parameter specifies the network interface
# addresses that this mail system receives mail on.  By default,
# the software claims all active interfaces on the machine. The
# parameter also controls delivery of mail to user@[ip.address].
#
# See also the proxy_interfaces parameter, for network addresses that
# are forwarded to us via a proxy or network address translator.
#
# Note: you need to stop/start Postfix when this parameter changes.
#
#inet_interfaces = all
#inet_interfaces = $myhostname
#inet_interfaces = $myhostname, localhost
#inet_interfaces = localhost ←コメントアウト
inet_interfaces = all ←追加

:
# Specify a list of host or domain names, /file/name or type:table
# patterns, separated by commas and/or whitespace. A /file/name
# pattern is replaced by its contents; a type:table is matched when
# a name matches a lookup key (the right-hand side is ignored).
# Continue long lines by starting the next line with whitespace.
#
# See also below, section "REJECTING MAIL FOR UNKNOWN LOCAL USERS".
#
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain ←追加
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain,
#       mail.$mydomain, www.$mydomain, ftp.$mydomain

:
 DELIVERY TO MAILBOX
#
# The home_mailbox parameter specifies the optional pathname of a
# mailbox file relative to a user's home directory. The default
# mailbox file is /var/spool/mail/user or /var/mail/user.  Specify
# "Maildir/" for qmail-style delivery (the / is required).
#
#home_mailbox = Mailbox
#home_mailbox = Maildir/
home_mailbox = Maildir/ ←追加

:
# SHOW SOFTWARE VERSION OR NOT
#
# The smtpd_banner parameter specifies the text that follows the 220
# code in the SMTP server's greeting banner. Some people like to see
# the mail version advertised. By default, Postfix shows no version.
#
# You MUST specify $myhostname at the start of the text. That is an
# RFC requirement. Postfix itself does not care.
#
#smtpd_banner = $myhostname ESMTP $mail_name
#smtpd_banner = $myhostname ESMTP $mail_name ($mail_version)
smtpd_banner = $myhostname ESMTP unknown ←追加

:
# SMTP Auth ←ファイルの最後に追加
smtpd_sasl_auth_enable = yes
smtpd_sasl_local_domain = $myhostname
smtpd_recipient_restrictions =
 permit_mynetworks
 permit_sasl_authenticated
 reject_unauth_destination

4.master.cfの編集

587番ポートでもメール出来るようにするには、vi /etc/postfix/master.cfコマンドで

# vi /etc/postfix/master.cf

#submission inet n       -       n       -       -       smtpd
#  -o smtpd_enforce_tls=yes
#  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_client_restrictions=permit_sasl_authenticated,reject

の部分を以下に変更

submission inet n       -       n       -       -       smtpd
#  -o smtpd_enforce_tls=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject

5.SASLによるSMTP認証用MD5パッケージとplainパッケージのインストール

yum install cyrus-sasl-md5 cyrus-sasl-plain

6.Postfixの起動

(1)sendmail停止

# /etc/rc.d/init.d/sendmail stop
# chkconfig sendmail off

(2)メールサーバー切替え

# alternatives --config mta

2 プログラムがあり 'mta' を提供します。

  選択       コマンド
-----------------------------------------------
*+ 1           /usr/sbin/sendmail.sendmail
   2           /usr/sbin/sendmail.postfix

Enter を押して現在の選択 [+] を保持するか、選択番号を入力します:2

(3)PostfixSMTP-Authの起動

# service postfix start
# chkconfig postfix on
# chkconfig saslauthd on
#chkconfig --list postfix
postfix        	0:off	1:off	2:on	3:on	4:on	5:on	6:off
# chkconfig --list saslauthd
saslauthd      	0:off	1:off	2:on	3:on	4:on	5:on	6:off

7.POP3/IMAPサーバーDovecotのインストール

yum install dovecot

8.インストールが完了しているか確認

# rpm -qa dovecot
dovecot-2.0.9-5.el6.x86_64

9.dovecot.confを編集

vi /etc/dovecot/dovecot.conf
:

# Should each login be processed in it's own process (yes), or should one
# login process be allowed to process multiple connections (no)? Yes is more
# secure, espcially with SSL/TLS enabled. No is faster since there's no need
# to create processes all the time.
#login_process_per_connection = yes
login_process_per_connection = no ←追加
:

# See doc/wiki/Variables.txt for full list. Some examples:
#
#   mail_location = maildir:~/Maildir
#   mail_location = mbox:~/mail:INBOX=/var/mail/%u
#   mail_location = mbox:/var/mail/%d/%1n/%n:INDEX=/var/indexes/%d/%1n/%n
#
# <doc/wiki/MailLocation.txt>
#
#mail_location =
mail_location = maildir:~/Maildir ←追加

10.Dovecotの起動・起動設定

chkconfig --list dovecot
dovecot        	0:off	1:off	2:off	3:off	4:off	5:off	6:off

自動起動が「of」なので

# chkconfig dovecot on
[root@dti-vps-srv30 ~]# chkconfig --list dovecot
dovecot        	0:off	1:off	2:on	3:on	4:on	5:on	6:off

Dovecotの起動
# service dovecot start
Dovecot Imap を起動中:                                     [  OK  ]

# netstat -antup | egrep 'master|dovecot'
tcp        0      0 0.0.0.0:587                 0.0.0.0:*                   LISTEN      23897/master        
tcp        0      0 0.0.0.0:25                  0.0.0.0:*                   LISTEN      23897/master        
tcp        0      0 :::993                      :::*                        LISTEN      24007/dovecot       
tcp        0      0 :::995                      :::*                        LISTEN      24007/dovecot       
tcp        0      0 :::110                      :::*                        LISTEN      24007/dovecot       
tcp        0      0 :::143                      :::*                        LISTEN      24007/dovecot    


4.Postfix および DovecotモジュールのWebminへの登録

「Webmin 設定」の「モジュールのリフレッシュ」により、インストールされたサーバに関するすべてのWebminモジュールを再確認し、Postfix および DovecotモジュールをWebminへ登録します。


5.Postfix の設定

Webminの「サーバ」→「Postfix の設定」→「一般オプション」画面で、以下の各項目を、各自のネットワーク環境に合わせて、下記内容などに変更。

設定する項目 設定内容
発信メールで使用するドメイン ドメイン名を使用」をチェック
メールを受信するドメイン $myhostname, localhost.$mydomain, localhost, $mydomain
メール受信用のネットワーク インターフェイス 「すべて」をチェック
このメール システムのインターネット ホスト名 mail.chamu.org
ローカル インターネット ドメイン chamu.org
ローカル ネットワーク 183.181.10.26/32,28.178.88.0/24,127.0.0.0/8


Webminの「サーバ」→「Postfix の設定」→「ローカル配信」画面の
「ユーザ メールボックス ファイルのホーム相対パス名」の項目を「Maildir/」に変更。


Webminの「サーバ」→「Postfix の設定」→「SMTP サーバ オプション」画面の
SMTP グリーティング バナー」の項目を「$myhostname ESMTP unknown」に
「宛先アドレスの制限」の項目を「permit_mynetworks permit_sasl_authenticated reject_unauth_destination」に変更。


Webminの「サーバ」→「Postfix の設定」→「SMTP 認証と暗号化」画面の
「SASL SMTP 認証を有効にしますか?」の項目を「はい」に変更。




5.Postfix の起動、終了

Webminの「サーバ」→「Postfix の設定」画面で、「Postfixを開始」ボタンをクリックすると、Postfixが起動します。Postfixの終了も同様。

なお、ServersMan@VPSでは認証デーモン、saslauthdが自動起動する設定なので、特に設定の必要はありません。

sshトンネル(ポートフォワード)を使ってリモートのMySQLにつなぐ

自宅のMacからServersMan@VPSに入ってるMySQL直接接続したいが、危険だからMySQLのポートなんか外部に開放したくないと言う時に。

SSHのポートフォワードを使って、自宅MacからリモートMySQLにお気軽接続。


3307はクライアントのMac側に張る仮想のMySQLポート番号。基本的に任意。
3306はサーバ、ServersMan@VPS側のMySQLポート番号。

1.自宅Macから、ServersMan@VPSsshトンネルを張る。

ssh -fNL 3307:localhost:3306 admin@ServersManのアドレス -p ServersMan側のssh接続ポート番号

2.つなぎ方。

mysql -u root -p -h 127.0.0.1 -P 3307

3.自宅のMacからPythonでリモートのMySQLに接続してみる

これが便利なのって、自宅Macから、サーバー側のMySQLデータを直接メンテしたりなど出来るってことかな。

サーバーから自宅Macに、sshトンネルを逆に掘れば、サーバー側にMySQLを入れてなくても、サーバー側から自宅MacMySQLに接続して、サーバー側からデータベースを切り離すってことも出来たりして。

テストデータの作成

mysql -u root -p -h 127.0.0.1 -P 3307

以下は、MySQLコンソールから

use test;

CREATE TABLE mef (c TEXT);

INSERT INTO mef VALUES("今日の天気は晴れです。");
INSERT INTO mef VALUES("Unicode 正規化の機能は、プラグインとリンクしている ICU ライブラリで実装されています。");

select * from mef;
+----------------------------------------------------------------------------------------+
| c                                                                                      |
+----------------------------------------------------------------------------------------+
| 今日の天気は晴れです。                                                                 |
| Unicode 正規化の機能は、プラグインとリンクしている ICU ライブラリで実装されています。  |
+----------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

自宅のMacからPythonでリモートのMySQLに接続してみる

python

以下はpythonコンソールから

>>> import MySQLdb
>>> conn = MySQLdb.connect(db='test', host='127.0.0.1', user='root', passwd='パスワード' port=3307)
>>> cursor = conn.cursor()
>>> cursor.execute( "SELECT * FROM mef ;" )
2L
>>> rows = cursor.fetchall()
>>> print rows[0][0]
今日の天気は晴れです。
>>> print rows[1][0]
Unicode 正規化の機能は、プラグインとリンクしている ICU ライブラリで実装されています。
>>>