OSDN Git Service

Prepare for Release of 4.0
authorShyouzou Sugitani <shy@users.sourceforge.jp>
Wed, 23 Dec 2009 18:41:55 +0000 (03:41 +0900)
committerShyouzou Sugitani <shy@users.sourceforge.jp>
Wed, 23 Dec 2009 18:41:55 +0000 (03:41 +0900)
13 files changed:
ChangeLog
NEWS
README
doc/saori.txt
lib/ninix/balloon.py
lib/ninix/dll/lettuce.py [deleted file]
lib/ninix/dll/mciaudio.py
lib/ninix/dll/mciaudior.py
lib/ninix/ngm.py
lib/ninix/prefs.py
lib/ninix/sakura.py
lib/ninix/version.py
locale/ja.po

index 4ebfba3..ee4c336 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+Thu December 24 2009   Shyouzou Sugitani <shy@users.sourceforge.jp>
+       * バージョン4.0(jump off into never-never land)リリース.
+       * locale/ja.poを更新した.
+       * ユーザー設定からヘルパーを削除した.
+         それに合わせてdoc/saori.txtを修正した.
+       * れたす(lettuce.dll)互換モジュールを削除した.
+         (要望があればGStreamerを使用して再度実装する.)
+       * 音声ファイルの再生にはGStreamerを使用するようにした.
+         \_v[]タグとMCIAudio, MCIAudioR互換モジュールを変更した.
+         MCIAudioRはループ演奏に対応した.
+         READMEの「必要なもの」にGStreamer Python bindingsを追加した.
+       
+Fri December 4 2009   Shyouzou Sugitani <shy@users.sourceforge.jp>
+       * Webブラウザの呼び出しにはPythonのwebbrowerモジュールを
+         使用するようにした.(ユーザー設定からWebブラウザを削除した.)
+
 Sun November 29 2009   Shyouzou Sugitani <shy@users.sourceforge.jp>
        * バージョン3.9.9aリリース.
        * CommunicateWindowクラス(とそれを継承しているクラス)を修正.
diff --git a/NEWS b/NEWS
index 6b704e4..ed7dd71 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,50 @@
 Ver.4.0の変更点
 -------------------
--
+- ユーザー設定からヘルパーを削除しました.
+  音声ファイルの再生にはGStreamerを使用するようにしました.
+  GStreamer Python bindingsが必要です.
+- れたす(lettuce.dll)互換モジュールを削除しました.
+  要望があれば再度GStreamerを使用して実装し直したものを追加します.
+- ユーザー設定からWebブラウザを削除しました.
+  使用している環境のデフォルトブラウザを呼び出します.
+- 「きのこ」の'ontop'の処理が確実に行なわれるように修正しました.
+- 「猫どりふ」の見切れをゴースト同様に透明部分も含めたサーフェスの1/3が
+  画面外に出ると発動するよう変更しました.
+- ユーザー設定の項目を減らしました.
+  SHIORIイベントの発生を抑制する項目(PREFS_EVENT_KILL_LIST)と
+  マウスボタンの機能を設定する項目(PREFS_MOUSE_BUTTON1, PREFS_MOUSE_BUTTON3)を
+  削除しました. 
+  また, メニューから個々のゴーストについてサーフェス倍率とスクリプトの
+  再生スピードを設定する項目を削除しました.(全ゴーストが同じ設定になります.)
+- 画面の上下方向の有効範囲(タスクバー等を除いた範囲)をユーザーが指定する
+  ための設定値を削除しました. ウインドウマネージャから情報を得て自動的に
+  処理します.
+- sourceforge.jpにGitリポジトリを作成し, ソースコードの管理をGitに移行しました.
+  今後CVSのリポジトリは更新されません.
+- バルーンを出す際にバルーンがフォーカスを奪わないようにするための設定を
+  削除しました.
+  バルーンを出す際にバルーンがフォーカスを奪わないようにしつつ, バルーンの
+  ウインドウを前面に持ってくる方法が見付からなかったためです.
+  この辺りの処理はウインドウマネージャ次第で変わってしまい, 確実な方法が
+  無いので, ninix-ayaでは何もしないことにしました.
+- サーフェスのツールチップ表示を実装しました.(SSP互換)
+- surfaces.txtの文字コード指定に対応しました.(SSP互換)
+- _niseshiori.so(暗号化辞書の解読用C言語モジュール)を削除しました.
+  ninix-aya本体にはC言語モジュールが無くなりました.
+- 透過ウインドウ処理にGTK+2.10の新機能を使用するように変更しました.
+  このバージョンから正式にサポートされた機能になります.
+- ゴーストのサーフェスをマウスドラッグするボタンを左ボタン(1番)に変更しました.
+- ゴーストのサーフェス移動後の位置の再計算のタイミングを移動直後にしました.
+- osuwari.dll互換SAORIモジュールosuwari.pyを追加しました.
+- OnBallonCloseイベントのサポートを追加しました.
+- OnMouseEnterAll, OnMouseLeaveAll, OnMouseEnter, OnMouseLeave イベントの
+  サポートを追加しました.
+- SERIKOによるサーフェスの書き換えを抑制するオプションを追加しました.
+  (サーフェスの書き換えが起きないだけで内部でSERIKOは動作しています.)
+- YAYAローダー(yaya.py)を追加しました.(動作確認がまだ出来ていません.)
+- メニューコンテキストの配置がSSPに近付くよう変更しました.
+- PNAファイルの処理にNumpyの機能を使い高速化しました.
+- アニメーションの処理を変更し, CPU負荷とコマ飛びを低減しました.
 
 Ver.3.9の変更点
 -------------------
diff --git a/README b/README
index 039ad98..4067f89 100644 (file)
--- a/README
+++ b/README
@@ -48,6 +48,10 @@ UNIX 対応デスクトップアクセサリninixに拡張機能を追加した
   Shift_JIS以外の文字コードを使用している「美坂」使用ゴーストを動作させるのに
   必要です。バージョン 1.0 での動作を確認しています。
 
+- GStreamer Python bindings (http://gstreamer.freedesktop.org/src/gst-python/)
+  音声ファイルの再生に使用しています。 バージョン 0.10.17 での動作を確認して
+  います。
+
 インストール
 ------------
 各種OS用パッケージを使用する場合は ninix-aya 開発プロジェクト
index 2a4484e..7f25067 100644 (file)
@@ -12,15 +12,10 @@ SAORIモジュールはWindowsのDLLとして提供されているため、ninix
 
 設定
 ----
\9f³å£°ã\83\95ã\82¡ã\82¤ã\83«å\86\8dç\94\9fã\81«ã\81¯å\88¥é\80\94対å¿\9cã\82¢ã\83\97ã\83ªã\82±ã\83¼ã\82·ã\83§ã\83³ã\81\8cå¿\85è¦\81ã\81§ã\81\99.
-メニューから設定を選び「ヘルパー」を設定して下さい.
\9f³å£°ã\83\95ã\82¡ã\82¤ã\83«å\86\8dç\94\9fã\81¯GStreamerã\81\8cã\81\9dã\81®ã\83\95ã\82¡ã\82¤ã\83«å½¢å¼\8fã\81®å\86\8dç\94\9fã\81«å¯¾å¿\9cã\81\97ã\81¦ã\81\84ã\82\8cã\81°
+設定は必要ありません.
 それ以外のモジュールは特に設定の必要はありません.
 
-設定例(「パターン : コマンド」)
-\.(mp3)$ : mpg123 -q %s
-\.(wav)$ : aplay -q %s
-\.(mid)$ : timidity -idq %s
-\.(ogg)$ : ogg123 -q %s
 
  現在、以下の互換モジュールが収録されています。
 
@@ -50,11 +45,6 @@ hanayu.py
 りゅう氏が開発されている「花柚」と互換のモジュールです。
 ゴーストの過去一週間の起動時間をグラフ表示します。
 
-lettuce.py
-----------
-七瀬いーうぃ氏が開発されている「れたす」と互換のモジュールです。
-Ogg Vorbis形式の音声を再生する機能を提供します。
-
 wmove.py
 --------
 tmizu氏が開発されている「wmove.dll」と互換のモジュールです。
@@ -85,18 +75,6 @@ SAORI collection
 http://members.jcom.home.ne.jp/umeici/saoricollect.html
 umeici氏提供の総合リンク集です。
 
-TiMidity++
-http://www.goice.co.jp/member/mo/timidity/index-jp.html
-http://timidity.sourceforge.jp/
-Tuuka Toivonen氏によるTiMidityの開発・公開は終了しました。
-現在は、出雲正尚氏らによってTiMidity++が公開されています。
-
-vorbis-tools
-http://www.vorbis.com/
-http://www.vorbis.com/download_unix.psp
-Ogg Vorbis公式サイトのダウンロードページです。
-ogg123が収録されています。
-
 さくらのにえ
 http://nie.counterghost.net/
 
index dbc7d80..a607c74 100644 (file)
@@ -827,7 +827,7 @@ class BalloonWindow:
         cr.set_source_pixbuf(self.balloon_pixbuf, 0, 0)
         cr.paint_with_alpha(self.__alpha_channel)
 
-    def set_markup(self, index, text):
+    def set_markup(self, index, text): # FIXME: escape & -> &amp;
         tags_ = ('sup', 'sub', 's', 'u')
         count_ = {}
         for tag_ in tags_:
diff --git a/lib/ninix/dll/lettuce.py b/lib/ninix/dll/lettuce.py
deleted file mode 100644 (file)
index 88d2a5f..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-#  lettuce.py - a LETTUCE compatible Saori module for ninix
-#  Copyright (C) 2002-2009 by Shyouzou Sugitani <shy@users.sourceforge.jp>
-#  Copyright (C) 2002, 2003 by MATSUMURA Namihiko <nie@counterghost.net>
-#
-#  This program is free software; you can redistribute it and/or modify it
-#  under the terms of the GNU General Public License (version 2) as
-#  published by the Free Software Foundation.  It is distributed in the
-#  hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
-#  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-#  PURPOSE.  See the GNU General Public License for more details.
-#
-
-import os
-import sys
-import signal
-import socket
-
-from ninix.dll import SAORI
-
-
-class Saori(SAORI):
-
-    module_name = 'LETTUCE'
-    dll_name = 'lettuce.dll'
-
-    def __init__(self):
-       SAORI.__init__(self)
-        self.files = {}
-        self.sstpport = None
-        self.__sakura = None
-
-    def need_ghost_backdoor(self, sakura):
-        self.__sakura = sakura
-
-    def load(self, dir=os.curdir):
-        self.dir = dir
-        result = 0
-        if self.loaded:
-           result = 2
-        elif self.__sakura is not None:
-            signal.signal(signal.SIGCHLD, self.signal_handler)
-            self.loaded = 1
-            result = 1
-       return result
-
-    def finalize(self):
-        #for name in self.files:
-        #    pid = self.files[name]['pid']
-        #    if pid:
-        #        os.kill(pid, 9)
-        #        os.waitpid(pid, 0)
-        self.files = {}
-        return 1
-
-    def signal_handler(self, signum, frame):
-        for name in self.files:
-            pid = self.files[name]['pid']
-            if not pid:
-                continue
-            result = os.waitpid(pid, os.WNOHANG)
-            if result:
-                if os.WIFSTOPPED(result[1]):
-                    self.files[name]['status'] = 'pause'
-                else:
-                    self.files[name]['pid'] = None
-                    self.files[name]['status'] = 'stop'
-                    ### send SSTP message ###
-                    if os.WIFEXITED(result[1]) and self.sstpport:
-                        address = ('', int(self.sstpport))
-                        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-                        try:
-                            s.connect(address)
-                        except socket.error:
-                            sys.stderr.write(
-                                '%s: cannot connect to the SSTP server\n' % \
-                                self.module_name)
-                            return
-                        s.send(
-                            ''.join(('SEND SSTP/1.1\r\n'
-                                     'Sender: %s\r\n' % self.module_name,
-                                     'Event: OnApplicationOperationFinish\r\n',
-                                     'Reference0: %s\r\n' % self.dll_name,
-                                     'Reference1: play.finished\r\n',
-                                     'Reference2: %s\r\n' % name,
-                                     'Charset: ASCII\r\n\r\n')))
-                        s.recv(1024)
-                        s.close()
-
-    def request(self, req):
-        req_type, argument = self.evaluate_request(req)
-        if not req_type:
-            return 'SAORI/1.0 400 Bad Request\r\n\r\n'
-        elif req_type == 'GET Version':
-            return 'SAORI/1.0 200 OK\r\n\r\n'
-        elif req_type == 'EXECUTE':
-            if not argument:
-                return 'SAORI/1.0 400 Bad Request\r\n\r\n'
-            command = argument[0]
-            result = 0
-            if command == 'set.hwnd':
-                if len(argument) < 2:
-                    return 'SAORI/1.0 400 Bad Request\r\n\r\n'
-                else:
-                    self.sstpport = argument[1]
-                    result = 1
-            elif command == 'play':
-                if len(argument) < 2:
-                    return 'SAORI/1.0 400 Bad Request\r\n\r\n'
-                else:
-                    name = argument[1].replace('\\', '/').lower() ## FIXME: Shiori -> filename
-                    filepath = os.path.join(self.dir,
-                                            ''.join(('./', name, 'ogg')))
-                if name in self.files:
-                    pid = self.files[name]['pid']
-                    if pid and self.files[name]['status'] == 'play':
-                        try:
-                            os.kill(-pid, 9)
-                            os.waitpid(pid, 0)
-                        except:
-                            pass
-                        self.files[name]['pid'] = 0
-                else:
-                    self.files[name] = {}
-                if filepath:
-                    pid = os.fork()
-                    self.files[name]['pid'] = pid
-                    if pid == 0:
-                        os.setsid()
-                        if os.path.isfile(filepath):
-                            for regex, command in self.prefs.get_helpers_regex():
-                                if regex.search(filepath):
-                                    self.execute_command(command, filepath)
-                        os._exit(0)
-                    self.files[name]['status'] = 'play'
-                    result = 1
-            elif command == 'play.ex':
-                pass # FIXME
-            elif command == 'stop':
-                if len(argument) < 2:
-                    for name in self.files:
-                        pid = self.files[name]['pid']
-                        if pid:
-                            try:
-                                os.kill(-pid, 9)
-                                os.waitpid(pid, 0)
-                            except:
-                                pass
-                            self.files[name]['pid'] = 0
-                    result = 1
-                else:
-                    name = argument[1].replace('\\', '/').lower()
-                    if name in self.files:
-                        pid = self.files[name]['pid']
-                        if pid:
-                            try:
-                                os.kill(-pid, 9)
-                                os.waitpid(pid, 0)                        
-                            except:
-                                pass
-                            self.files[name]['pid'] = 0
-                        result = 1
-            elif command == 'pause':
-                pass # FIXME
-            elif command == 'set.loop':
-                pass # FIXME
-            elif command == 'reset.loop':
-                pass # FIXME
-            return 'SAORI/1.0 200 OK\r\nResult: %s\r\n\r\n' % result
-        else:
-            return 'SAORI/1.0 400 Bad Request\r\n\r\n'
-
-    def execute_command(self, command, arg):
-        if '%s' not in command:
-            sys.stderr.write('cannot execute command (%s missing)\n')
-            return
-        os.system(command.replace('%s', arg, 1))
index 885f337..7ba3370 100644 (file)
 #
 
 import os
-import sys
 import signal
 
+import pygst
+pygst.require("0.10")
+import gst
+
 from ninix.dll import SAORI
 
 
@@ -23,10 +26,15 @@ class Saori(SAORI):
 
     def __init__(self):
         SAORI.__init__(self)
-        self.pid = 0
+        self.player = gst.element_factory_make("playbin", "player")
+        fakesink = gst.element_factory_make("fakesink", "fakesink")
+        self.player.set_property("video-sink", fakesink)
+        bus = self.player.get_bus()
+        bus.add_signal_watch()
+        bus.connect("message", self.on_message)
         self.filepath = None
         self.__sakura = None
-        self.pause = 0
+        self.state = 0 # 0/1/2 - stop/playing/paused
 
     def need_ghost_backdoor(self, sakura):
         self.__sakura = sakura
@@ -38,58 +46,32 @@ class Saori(SAORI):
             return 0
 
     def finalize(self):
-        if self.pid != 0:
-            try:
-                os.kill(-self.pid, 9)
-                os.waitpid(self.pid, 0)
-            except:
-                pass
-           self.pid = 0
+        self.player.set_state(gst.STATE_NULL)
+        self.player = None
         self.filepath = None
         return 1
 
     def execute(self, argv):
         argc = len(argv)
         if argc == 1:
+            assert self.player is not None
             if argv[0] == 'stop':
-                ##self.filepath = None
-                if self.pid != 0:
-                    try:
-                        os.kill(-self.pid, 9)
-                        os.waitpid(self.pid, 0)
-                    except:
-                        pass
-                    self.pid = 0
+                self.player.set_state(gst.STATE_NULL)
             elif argv[0] == 'play':
-                if self.pid != 0:
-                    status = os.waitpid(-self.pid, os.WNOHANG)
-                    if os.WIFEXITED(status) or os.WIFSIGNALED(status):
-                        self.pid = 0
-                    elif self.pause:
-                        os.kill(-self.pid, signal.SIGCONT)
-                        self.pause = 0
-                        return 'SAORI/1.0 204 No Content\r\n\r\n'
-                    else:
-                        os.kill(-self.pid, signal.SIGSTOP)
-                        self.pause = 1
-                        return 'SAORI/1.0 204 No Content\r\n\r\n'
+                if self.state == 2:
+                    self.state = 1
+                    self.player.set_state(gst.STATE_PLAYING)
+                    return 'SAORI/1.0 204 No Content\r\n\r\n'
+                elif self.state == 1:
+                    self.state = 2
+                    self.player.set_state(gst.STATE_PAUSED)
+                    return 'SAORI/1.0 204 No Content\r\n\r\n'
                 if os.path.isfile(self.filepath):
-                    self.pid = os.fork()
-                    if self.pid == 0:
-                        os.setsid()
-                        for regex, command in self.prefs.get_helpers_regex():
-                            if regex.search(self.filepath):
-                                self.execute_command(command, self.filepath)
-                        os._exit(0)
+                    self.player.set_property("uri", "file://" + self.filepath)
+                    self.player.set_state(gst.STATE_PLAYING)
         elif argc == 2:
             if argv[0] == 'load':
-                if self.pid != 0:
-                    try:
-                        os.kill(-self.pid, 9)
-                        os.waitpid(self.pid, 0)
-                    except:
-                        pass
-                    self.pid = 0
+                self.player.set_state(gst.STATE_NULL)
                 filename = argv[1].replace('\\', '/').lower()
                 if os.path.isabs(filename):
                     return 'SAORI/1.0 400 Bad Request\r\n\r\n'
@@ -98,8 +80,13 @@ class Saori(SAORI):
                                              filename)
         return 'SAORI/1.0 204 No Content\r\n\r\n'
 
-    def execute_command(self, command, arg):
-        if '%s' not in command:
-            sys.stderr.write('cannot execute command (%s missing)\n')
-            return
-        os.system(command.replace('%s', arg, 1))
+    def on_message(self, bus, message):
+        t = message.type
+        if t == gst.MESSAGE_EOS:
+            self.player.set_state(gst.STATE_NULL)
+            self.state = 0
+        elif t == gst.MESSAGE_ERROR:
+            self.player.set_state(gst.STATE_NULL)
+            err, debug = message.parse_error()
+            print "Error: %s" % err, debug
+            self.state = 0
index 598c563..6db38c4 100644 (file)
 #  PURPOSE.  See the GNU General Public License for more details.
 #
 
-# TODO:
-# - loop 演奏.
-
 import os
-import sys
 import signal
 
+import pygst
+pygst.require("0.10")
+import gst
+
 from ninix.dll import SAORI
 
 
@@ -26,71 +26,63 @@ class Saori(SAORI):
 
     def __init__(self):
         SAORI.__init__(self)
-        self.pid = 0
+        self.player = gst.element_factory_make("playbin", "player")
+        fakesink = gst.element_factory_make("fakesink", "fakesink")
+        self.player.set_property("video-sink", fakesink)
+        bus = self.player.get_bus()
+        bus.add_signal_watch()
+        bus.connect("message", self.on_message)
         self.filepath = None
-        self.pause = 0
+        self.state = 0 # 0/1/2 - stop/playing/paused
+        self.loop = False
 
     def finalize(self):
-        if self.pid != 0:
-            try:
-                os.kill(-self.pid, 9)
-                os.waitpid(self.pid, 0)
-            except:
-                pass
-           self.pid = 0
+        self.player.set_state(gst.STATE_NULL)
+        self.player = None
         self.filepath = None
         return 1
 
     def execute(self, argv):
         argc = len(argv)
         if argc == 1:
+            assert self.player is not None
             if argv[0] == 'stop':
-                ##self.filepath = None
-                if self.pid != 0:
-                    try:
-                        os.kill(-self.pid, 9)
-                        os.waitpid(self.pid, 0)
-                    except:
-                        pass
-                    self.pid = 0
-            elif argv[0] == 'play':
-                if self.pid != 0:
-                    status = os.waitpid(-self.pid, os.WNOHANG)
-                    if os.WIFEXITED(status) or os.WIFSIGNALED(status):
-                        self.pid = 0
-                    elif self.pause:
-                        os.kill(-self.pid, signal.SIGCONT)
-                        self.pause = 0
-                        return 'SAORI/1.0 204 No Content\r\n\r\n'
-                    else:
-                        os.kill(-self.pid, signal.SIGSTOP)
-                        self.pause = 1
-                        return 'SAORI/1.0 204 No Content\r\n\r\n'
+                self.player.set_state(gst.STATE_NULL)
+            elif argv[0] in ['play', 'loop']:
+                if argv[0] == 'loop':
+                    self.loop = True
+                if self.state == 2:
+                    self.state = 1
+                    self.player.set_state(gst.STATE_PLAYING)
+                    return 'SAORI/1.0 204 No Content\r\n\r\n'
+                elif self.state == 1:
+                    self.state = 2
+                    self.player.set_state(gst.STATE_PAUSED)
+                    return 'SAORI/1.0 204 No Content\r\n\r\n'
                 if os.path.isfile(self.filepath):
-                    self.pid = os.fork()
-                    if self.pid == 0:
-                        os.setsid()
-                        for regex, command in self.prefs.get_helpers_regex():
-                            if regex.search(self.filepath):
-                                self.execute_command(command, self.filepath)
-                        os._exit(0)
+                    self.player.set_property("uri", "file://" + self.filepath)
+                    self.player.set_state(gst.STATE_PLAYING)
         elif argc == 2:
             if argv[0] == 'load':
-                if self.pid != 0:
-                    try:
-                        os.kill(-self.pid, 9)
-                        os.waitpid(self.pid, 0)
-                    except:
-                        pass
-                    self.pid = 0
+                self.player.set_state(gst.STATE_NULL)
                 filename = argv[1].replace('\\', '/')
                 if not os.path.isabs(filename): # XXX
                     filename = filename.lower()
                 self.filepath = os.path.join(self.dir, filename)
         return 'SAORI/1.0 204 No Content\r\n\r\n'
 
-    def execute_command(self, command, arg):
-        if '%s' not in command:
-            sys.stderr.write('cannot execute command (%s missing)\n')
-            return
-        os.system(command.replace('%s', arg, 1))
+    def on_message(self, bus, message):
+        t = message.type
+        if t == gst.MESSAGE_EOS:
+            if self.loop:
+                self.player.set_state(gst.STATE_PLAYING)
+                self.state = 1
+            else:
+                self.player.set_state(gst.STATE_NULL)
+                self.state = 0
+        elif t == gst.MESSAGE_ERROR:
+            self.player.set_state(gst.STATE_NULL)
+            err, debug = message.parse_error()
+            print "Error: %s" % err, debug
+            self.state = 0
+            self.loop = False
index 6feaafe..1e5b833 100644 (file)
@@ -15,8 +15,9 @@ import codecs
 import os
 import re
 import sys
-import urllib
 import time
+import urllib
+import webbrowser
 
 from xml.dom import pulldom
 
@@ -534,8 +535,8 @@ class UI:
         button.set_relief(gtk.RELIEF_NONE)
         self.url['HP'] = [None, button.get_child()]
         vbox2.pack_start(button, False, True, 0)
-        button.connect('clicked',
-                       lambda b, w=self: w.launch_browser(self.url['HP'][0]))
+        button.connect(
+            'clicked', lambda b: webbrowser.open(self.url['HP'][0]))
         button.show()
         button = gtk.Button('')
         button.set_relief(gtk.RELIEF_NONE)
@@ -543,8 +544,7 @@ class UI:
         self.url['Public'] = [None, button.get_child()]
         vbox2.pack_start(button, False, True, 0)
         button.connect(
-            'clicked',
-            lambda b, w=self: w.launch_browser(self.url['Public'][0]))
+            'clicked', lambda b: webbrowser.open(self.url['Public'][0]))
         button.show()
         vbox.pack_start(hbox, False, True, 0)
         hbox.show()
@@ -556,13 +556,6 @@ class UI:
         self.info = textview
         return vbox
 
-    def launch_browser(self, url):
-        command = self.ngm.app.prefs.get('browser')
-        if '%s' not in command:
-            sys.stderr.write('cannot execute command (%s missing)\n')
-            return
-        os.system(' '.join((command.replace('%s', url, 1), '&')))
-
     def update_info_area(self):
         info_list = [(_('Author:'), 'Author'),
                      (_('ArchiveTime:'), 'ArchiveTime'),
index d399f71..b655a78 100644 (file)
@@ -43,7 +43,6 @@ range_script_speed = [(_('None'), -1), # ordinal (-1: no wait)
                       (''.join(('7 (', _('Slow'), ')')), 8)]
 
 # default settings
-DEFAULT_BROWSER = "firefox %s"
 DEFAULT_BALLOON_FONTS = 'Sans'
 
 def get_default_surface_scale():
@@ -110,9 +109,6 @@ def load_prefs():
 
 class PreferenceDialog:
 
-    PREFS_HELPER_PATTERN    = 'helper_%d_pattern'
-    PREFS_HELPER_COMMAND    = 'helper_%d_command'
-
     PREFS_TYPE = {'sakura_name': None,
                   'sakura_surface': int,
                   'default_balloon': None,
@@ -120,9 +116,6 @@ class PreferenceDialog:
                   'script_speed': int,
                   'surface_scale': int,
                   'balloon_scalling': int,
-                  'browser': None,
-                  'helper_%d_pattern': None,
-                  'helper_%d_command': None,
                   'balloon_fonts': None,
                   'allowembryo': int,
                   'check_collision': int,
@@ -146,8 +139,6 @@ class PreferenceDialog:
         self.notebook.show()
         for name, constructor in [
             (_('Font'),            self.make_page_fonts),
-            (_('Browser'),         self.make_page_browser),
-            (_('Helper'),          self.make_page_helper),
             (_('Surface&Balloon'), self.make_page_surface_n_balloon),
             (_('Misc'),            self.make_page_misc),
             (_('Debug'),           self.make_page_debug),
@@ -170,7 +161,6 @@ class PreferenceDialog:
         button.connect('clicked', self.cancel)
         box.add(button)
         button.show()
-        self.rule_editor = RuleEditor(self.window)
 
     def load(self):
         self.__prefs = load_prefs()
@@ -180,15 +170,6 @@ class PreferenceDialog:
         
     def reset(self): ### FIXME ###
         self.set_balloon_fonts(self.get('balloon_fonts', DEFAULT_BALLOON_FONTS))
-        self.set_browser(self.get('browser', DEFAULT_BROWSER))
-        helper_list = []
-        while 1:
-            pattern = self.__prefs.get(self.PREFS_HELPER_PATTERN % len(helper_list)) ## FIXME
-            command = self.__prefs.get(self.PREFS_HELPER_COMMAND % len(helper_list)) ## FIXME
-            if not pattern or not command:
-                break
-            helper_list.append((pattern, command))
-        self.set_helpers(helper_list)
         name = self.get('default_balloon')
         if self.app.find_balloon_by_name(name) is not None:
             self.set_default_balloon(name)
@@ -223,31 +204,12 @@ class PreferenceDialog:
         self.__prefs['sakura_surface'] = self.__saved_prefs['sakura_surface'] = surface
         self.__prefs.save()
 
-    def get_helpers_regex(self):
-        helpers_regex = []
-        for pattern, command in self.get_helpers():
-            try:
-                regex = re.compile(pattern)
-            except re.error:
-                continue
-            helpers_regex.append((regex, command))
-        return helpers_regex
-
     def edit_preferences(self):
         self.show()
 
     def update(self): ## FIXME
         self.__prefs['allowembryo'] = str(1 if self.allowembryo_button.get_active() else 0)
         self.__prefs['balloon_fonts'] = self.fontsel.get_font_name()
-        self.__prefs['browser'] = self.browser.get_text()
-        lstore = self.helpers.get_model()
-        listiter = lstore.get_iter_first()
-        i = 0 ## FIXME
-        while listiter:
-            self.__prefs[self.PREFS_HELPER_PATTERN % i] = lstore.get_value(listiter, 0)
-            self.__prefs[self.PREFS_HELPER_COMMAND % i] = lstore.get_value(listiter, 1)
-            i += 1
-            listiter = lstore.iter_next(listiter)
         name = None
         selected = self.balloon_treeview.get_selection().get_selected()
         if selected:
@@ -307,109 +269,6 @@ class PreferenceDialog:
         page.show()
         return page
 
-    def make_page_browser(self):
-        page = gtk.VBox(spacing=5)
-        page.set_border_width(5)
-        # browser
-        frame = gtk.Frame(unicode(_('Browser'), 'utf-8'))
-        frame.set_size_request(480, -1)
-        page.pack_start(frame)
-        frame.show()
-        box = gtk.VBox(spacing=2)
-        box.set_border_width(5)
-        frame.add(box)
-        box.show()
-        self.browser = gtk.Entry()
-        box.pack_start(self.browser, False)
-        self.browser.show()
-        # help messages
-        frame = gtk.Frame()
-        frame.set_size_request(480, -1)
-        page.pack_start(frame, False)
-        frame.show()
-        box = gtk.VBox(spacing=2)
-        box.set_border_width(5)
-        frame.add(box)
-        box.show()
-        label = gtk.Label(unicode(_('- %s in this command line will be replaced with the URL'), 'utf-8'))
-        label.set_alignment(0, -1)
-        box.pack_start(label, False)
-        label.show()
-        label = gtk.Label(unicode(_('- trailing & is not required.(automagically added)'), 'utf-8'))
-        label.set_alignment(0, -1)
-        box.pack_start(label, False)
-        label.show()
-        page.show()
-        return page
-
-    def make_page_helper(self):
-        page = gtk.VBox(spacing=5)
-        page.set_border_width(5)
-        frame = gtk.Frame(unicode(_('Application'), 'utf-8'))
-        frame.set_size_request(480, -1)
-        page.pack_start(frame)
-        frame.show()
-        box = gtk.VBox(spacing=5)
-        box.set_border_width(5)
-        frame.add(box)
-        box.show()
-        swin = gtk.ScrolledWindow()
-        swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
-        box.pack_start(swin)
-        swin.show()
-        lstore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
-        self.helpers = gtk.TreeView(lstore)
-        column = gtk.TreeViewColumn('Pattern', gtk.CellRendererText(), text=0)
-        self.helpers.append_column(column)
-        column = gtk.TreeViewColumn('Command', gtk.CellRendererText(), text=1)
-        self.helpers.append_column(column)
-        swin.add(self.helpers)
-        self.helpers.show()
-        bbox = gtk.HButtonBox()
-        bbox.set_spacing(10)
-        bbox.set_layout(gtk.BUTTONBOX_EDGE)
-        bbox.set_border_width(5)
-        box.pack_start(bbox, False)
-        bbox.show()
-        button = gtk.Button('New')
-        button.connect('clicked', self.rule_new)
-        bbox.pack_start(button)
-        button.show()
-        button = gtk.Button('Edit')
-        button.connect('clicked', self.rule_edit)
-        bbox.pack_start(button)
-        button.show()
-        button = gtk.Button('Delete')
-        button.connect('clicked', self.rule_delete)
-        bbox.pack_start(button)
-        button.show()
-        button = gtk.Button('Up')
-        button.connect('clicked', self.rule_up)
-        bbox.pack_start(button)
-        button.show()
-        button = gtk.Button('Down')
-        button.connect('clicked', self.rule_down)
-        bbox.pack_start(button)
-        button.show()
-        frame = gtk.Frame()
-        frame.set_size_request(480, -1)
-        page.pack_start(frame, False)
-        frame.show()
-        box = gtk.VBox(spacing=2)
-        box.set_border_width(5)
-        frame.add(box)
-        box.show()
-        label = gtk.Label(unicode(_('- %s in this command line will be replaced with the filename'), 'utf-8'))
-        label.set_alignment(0, -1)
-        box.pack_start(label, False)
-        label.show()
-        label = gtk.Label(unicode(_('- trailing & is not required.(automagically added)'), 'utf-8'))
-        label.set_alignment(0, -1)
-        box.pack_start(label, False)
-        label.show()
-        page.show()
-        return page
-
     def make_page_surface_n_balloon(self):
         page = gtk.VBox(spacing=5)
         page.set_border_width(5)
@@ -583,58 +442,6 @@ class PreferenceDialog:
         button.show()
         return page
 
-    def rule_new(self, widget):
-        self.rule_editor.set_pattern('')
-        self.rule_editor.set_command('')
-        if self.rule_editor.run('New rule...'):
-            pattern = self.rule_editor.get_pattern()
-            command = self.rule_editor.get_command()
-            lstore = self.helpers.get_model()
-            listiter = lstore.append()
-            lstore.set(listiter, 0, pattern, 1, command)
-
-    def rule_edit(self, widget):
-        selection = self.helpers.get_selection()
-        lstore, listiter = selection.get_selected()
-        if not listiter:
-            return
-        pattern = lstore.get_value(listiter, 0)
-        command = lstore.get_value(listiter, 1)
-        self.rule_editor.set_pattern(pattern)
-        self.rule_editor.set_command(command)
-        if self.rule_editor.run('Edit rule...'):
-            pattern = self.rule_editor.get_pattern()
-            command = self.rule_editor.get_command()
-            lstore.set(listiter, 0, pattern, 1, command)
-
-    def rule_delete(self, widget):
-        selection = self.helpers.get_selection()
-        lstore, listiter = selection.get_selected()
-        if not listiter:
-            return
-        lstore.remove(listiter)
-
-    def rule_up(self, widget):
-        selection = self.helpers.get_selection()
-        lstore, listiter = selection.get_selected()
-        if not listiter:
-            return
-        path = lstore.get_path(listiter)
-        if path[0] == 0:
-            return
-        listiter_ = lstore.get_iter(path[0] - 1)
-        if listiter_:
-            lstore.swap(listiter_, listiter)
-
-    def rule_down(self, widget):
-        selection = self.helpers.get_selection()
-        lstore, listiter = selection.get_selected()
-        if not listiter:
-            return
-        listiter_ = lstore.iter_next(listiter)
-        if listiter_:
-            lstore.swap(listiter_, listiter)
-
     def notify(self): ## FIXME
         for sakura in self.app.get_working_ghost():
             sakura.reset_balloon_fonts() ## FIXME
@@ -656,26 +463,6 @@ class PreferenceDialog:
     def set_balloon_fonts(self, name):
         self.fontsel.set_font_name(name)
 
-    def set_browser(self, command):
-        self.browser.set_text(command)
-
-    def set_helpers(self, helper_list):
-        lstore = self.helpers.get_model()
-        lstore.clear()
-        for pattern, command in helper_list:
-            listiter = lstore.append()
-            lstore.set(listiter, 0, pattern, 1, command)
-
-    def get_helpers(self):
-        helper_list = []
-        while 1:
-            pattern = self.__prefs.get(self.PREFS_HELPER_PATTERN % len(helper_list))
-            command = self.__prefs.get(self.PREFS_HELPER_COMMAND % len(helper_list))
-            if not pattern or not command:
-                break
-            helper_list.append((pattern, command))
-        return helper_list
-
     def set_balloon_scalling(self, flag):
         self.balloon_scalling_button.set_active(True if flag else False)
 
@@ -738,80 +525,3 @@ class PreferenceDialog:
 
     def set_seriko_inactive(self, flag):
         self.seriko_inactive_button.set_active(True if flag else False)
-
-
-class RuleEditor:
-
-    def __init__(self, master=None):
-        self.dialog = gtk.Dialog()
-        self.dialog.connect('delete_event', self.cancel)
-        self.dialog.set_modal(True)
-        self.dialog.set_position(gtk.WIN_POS_CENTER)
-        if master is not None:
-            self.dialog.set_transient_for(master)
-        # entries
-        table = gtk.Table(2, 2)
-        table.set_row_spacings(5)
-        table.set_col_spacings(5)
-        table.set_border_width(10)
-        self.dialog.vbox.pack_start(table)
-        label = gtk.Label('Pattern')
-        table.attach(label, 0, 1, 0, 1, xoptions=gtk.FILL)
-        self.pattern_entry = gtk.Entry()
-        self.pattern_entry.set_size_request(300, -1)
-        self.pattern_entry.connect('changed', self.changed)
-        table.attach(self.pattern_entry, 1, 2, 0, 1)
-        label = gtk.Label('Command')
-        table.attach(label, 0, 1, 1, 2, xoptions=gtk.FILL)
-        self.command_entry = gtk.Entry()
-        self.command_entry.set_size_request(300, -1)
-        self.command_entry.connect('changed', self.changed)
-        table.attach(self.command_entry, 1, 2, 1, 2)
-        self.dialog.vbox.show_all()
-        # buttons
-        self.ok_button = gtk.Button('OK')
-        self.ok_button.connect('clicked', self.ok)
-        self.dialog.action_area.pack_start(self.ok_button)
-        button = gtk.Button('Cancel')
-        button.connect('clicked', self.cancel)
-        self.dialog.action_area.pack_start(button)
-        self.dialog.action_area.show_all()
-
-    def set_pattern(self, text):
-        self.pattern_entry.set_text(text)
-
-    def get_pattern(self):
-        return self.pattern_entry.get_text()
-
-    def set_command(self, text):
-        self.command_entry.set_text(text)
-
-    def get_command(self):
-        return self.command_entry.get_text()
-
-    def changed(self, widget, event=None):
-        if self.pattern_entry.get_text() and \
-           self.command_entry.get_text():
-            self.ok_button.set_sensitive(True)
-        else:
-            self.ok_button.set_sensitive(False)
-
-    def run(self, title):
-        self.dialog.set_title(title)
-        self.dialog.show()
-        gtk.main()
-        return self.done
-
-    def hide(self):
-        self.dialog.hide()
-        gtk.main_quit()
-
-    def ok(self, widget, event=None):
-        self.done = 1
-        self.hide()
-        return True
-
-    def cancel(self, widget, event=None):
-        self.done = 0
-        self.hide()
-        return True
index bffe24c..250e8fc 100644 (file)
 #  PURPOSE.  See the GNU General Public License for more details.
 #
 
+import codecs
 import os
+import random
 import re
-import socket
 import select
+import socket
 import sys
 import time
-import random
-import codecs
+import webbrowser
 import StringIO
 
 if 'DISPLAY' in os.environ:
     import gtk ## FIXME
     import gobject
 
+import pygst
+pygst.require("0.10")
+import gst
+
 import ninix.surface
 import ninix.balloon
 import ninix.dll
@@ -145,6 +150,9 @@ class Sakura:
         name = (shiori_dll, shiori_name)
         self.shiori = self.__dll.request(name)
         self.updateman = ninix.update.NetworkUpdate(self)
+        self.audio_player = gst.element_factory_make("playbin", "player")
+        fakesink = gst.element_factory_make("fakesink", "fakesink")
+        self.audio_player.set_property("video-sink", fakesink)
         char = 2
         while self.desc.get('char%d.seriko.defaultsurface' % char) is not None:
             char += 1
@@ -407,10 +415,6 @@ class Sakura:
     def is_anchor(self, link_id):
         return 1 if len(link_id) == 2 and link_id[0] == 'anchor' else 0
 
-    def launch_browser(self, url): ## FIXME
-        command = self.prefs.get('browser')
-        self.execute_command(command, url)
-
     def execute_command(self, command, arg): ## FIXME
         if '%s' not in command:
             sys.stderr.write('cannot execute command (%s missing)\n')
@@ -606,7 +610,7 @@ class Sakura:
         if self.is_anchor(link_id):
             self.notify_event('OnAnchorSelect', link_id[1])
         elif self.is_URL(link_id):
-            self.launch_browser(link_id)
+            webbrowser.open(link_id)
             self.reset_script(1)
             self.stand_by(0)
         elif self.sstp_entry_db:
@@ -620,7 +624,7 @@ class Sakura:
     def notify_site_selection(self, event, args):
         title, url = args
         if self.is_URL(url):
-            self.launch_browser(url)
+            webbrowser.open(url)
         self.enqueue_event('OnRecommandedSiteChoice', title, url)
 
     def notify_surface_click(self, button, click, side, x, y):
@@ -991,6 +995,8 @@ class Sakura:
         self.hide_all()
         self.surface.finalize()
         self.balloon.finalize()
+        self.audio_player.set_state(gst.STATE_NULL)
+        self.audio_player = None
 
     def process_script(self):
         now = time.time()
@@ -1386,7 +1392,7 @@ class Sakura:
     def __yen_j(self, args):
         jump_id = args[0]
         if self.is_URL(jump_id):
-            self.launch_browser(jump_id)
+            webbrowser.open(jump_id)
         elif self.sstp_entry_db:
             self.start_script(self.sstp_entry_db.get(jump_id, r'\e'))
 
@@ -1434,10 +1440,9 @@ class Sakura:
         filename = filename.lower()
         path = os.path.join(self.get_prefix(), 'ghost/master', filename)
         if os.path.isfile(path):
-            for regex, command in self.prefs.get_helpers_regex():
-                if regex.search(path):
-                    self.execute_command(command, path)
-                    break
+            self.audio_player.set_state(gst.STATE_NULL)
+            self.audio_player.set_property("uri", "file://" + path)
+            self.audio_player.set_state(gst.STATE_PLAYING)
 
     def __yen_exclamation(self, args): ## FIXME
         if not args:
@@ -1447,7 +1452,7 @@ class Sakura:
         if args[0] == 'raise' and argc >= 2:
             self.notify_event(*args[1:10])
         elif args[0:2] == ['open', 'browser'] and argc > 2:
-            self.launch_browser(args[2])
+            webbrowser.open(args[2])
         elif args[0:2] == ['open', 'communicatebox']:
             if not self.passivemode:
                 self.balloon.open_communicatebox()
index 2861f79..3465b96 100644 (file)
@@ -10,8 +10,8 @@
 #  PURPOSE.  See the GNU General Public License for more details.
 #
 
-NUMBER = '3.9.9a'
-CODENAME = '"I see no more YASAGURE here."'
+NUMBER = '4.0'
+CODENAME = 'jump off into never-never land'
 
 VERSION = '%s (%s)' % (NUMBER, CODENAME)
 VERSION_INFO = (''.join((r'\h\s[0]\w8ninix-aya %s\n' % VERSION,
index 158c64a..2ae1240 100644 (file)
@@ -5,7 +5,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: ninix-aya 4.0\n"
 "POT-Creation-Date: Tue Sep 23 18:01:59 2003\n"
-"PO-Revision-Date: 2009-07-08 20:34+JST\n"
+"PO-Revision-Date: 2009-12-24 02:48+JST\n"
 "Last-Translator: Shyouzou Sugitani <shy@users.sourcefoge.jp>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
 "MIME-Version: 1.0\n"
@@ -142,115 +142,115 @@ msgstr "設定...(_O)"
 msgid "Katochan(_K)"
 msgstr "落下物(_K)"
 
-#: lib/ninix/ngm.py:276
+#: lib/ninix/ngm.py:277
 msgid "Search for"
 msgstr "検索文字を入力して下さい"
 
-#: lib/ninix/ngm.py:282
+#: lib/ninix/ngm.py:283
 msgid "OK"
 msgstr "OK"
 
-#: lib/ninix/ngm.py:285
+#: lib/ninix/ngm.py:286
 msgid "Cancel"
 msgstr "キャンセル"
 
-#: lib/ninix/ngm.py:342
+#: lib/ninix/ngm.py:343
 msgid "_File"
 msgstr "ファイル(_F)"
 
-#: lib/ninix/ngm.py:343
+#: lib/ninix/ngm.py:344
 msgid "_View"
 msgstr "表示(_V)"
 
-#: lib/ninix/ngm.py:344
+#: lib/ninix/ngm.py:345
 msgid "_Archive"
 msgstr "アーカイブ(_A)"
 
-#: lib/ninix/ngm.py:345
+#: lib/ninix/ngm.py:346
 msgid "_Help"
 msgstr "ヘルプ(_H)"
 
-#: lib/ninix/ngm.py:347
+#: lib/ninix/ngm.py:348
 msgid "Search(_F)"
 msgstr "検索(_F)"
 
-#: lib/ninix/ngm.py:351
+#: lib/ninix/ngm.py:352
 msgid "Search Forward(_S)"
 msgstr "次を検索(_S)"
 
-#: lib/ninix/ngm.py:355
+#: lib/ninix/ngm.py:356
 msgid "Settings(_O)"
 msgstr "設定(_O)"
 
-#: lib/ninix/ngm.py:359
+#: lib/ninix/ngm.py:360
 msgid "DB Network Update(_N)"
 msgstr "DB ネットワーク更新(_N)"
 
-#: lib/ninix/ngm.py:363
+#: lib/ninix/ngm.py:364
 msgid "Close(_X)"
 msgstr "終了(_X)"
 
-#: lib/ninix/ngm.py:367
+#: lib/ninix/ngm.py:368
 msgid "Mask(_M)"
 msgstr "表示マスク(_M)"
 
-#: lib/ninix/ngm.py:371
+#: lib/ninix/ngm.py:372
 msgid "Reset to Default(_Y)"
 msgstr "デフォルトに戻す(_Y)"
 
-#: lib/ninix/ngm.py:375
+#: lib/ninix/ngm.py:376
 msgid "Show All(_Z)"
 msgstr "すべて表示(_Z)"
 
-#: lib/ninix/ngm.py:391
+#: lib/ninix/ngm.py:392
 msgid "Ghost Manager"
 msgstr "ゴーストマネージャ"
 
-#: lib/ninix/ngm.py:425
+#: lib/ninix/ngm.py:426
 msgid "Previous"
 msgstr "前ヘ"
 
-#: lib/ninix/ngm.py:430
+#: lib/ninix/ngm.py:431
 msgid "Next"
 msgstr "次ヘ"
 
-#: lib/ninix/ngm.py:519
+#: lib/ninix/ngm.py:520
 msgid "Install"
 msgstr "Install"
 
-#: lib/ninix/ngm.py:524
+#: lib/ninix/ngm.py:525
 msgid "Update"
 msgstr "Update"
 
-#: lib/ninix/ngm.py:567
+#: lib/ninix/ngm.py:560
 msgid "Author:"
 msgstr "作者:"
 
-#: lib/ninix/ngm.py:568
+#: lib/ninix/ngm.py:561
 msgid "ArchiveTime:"
 msgstr "最終更新時刻:"
 
-#: lib/ninix/ngm.py:569
+#: lib/ninix/ngm.py:562
 msgid "ArchiveSize:"
 msgstr "アーカイブサイズ:"
 
-#: lib/ninix/ngm.py:570
+#: lib/ninix/ngm.py:563
 msgid "NetworkUpdateTime:"
 msgstr "ネットワーク更新時刻:"
 
-#: lib/ninix/ngm.py:571
+#: lib/ninix/ngm.py:564
 msgid "Version:"
 msgstr "バージョン:"
 
-#: lib/ninix/ngm.py:572
+#: lib/ninix/ngm.py:565
 msgid "AIName:"
 msgstr "使用偽AI:"
 
-#: lib/ninix/ngm.py:579 lib/ninix/ngm.py:583
+#: lib/ninix/ngm.py:572 lib/ninix/ngm.py:576
 msgid "SurfaceList:"
 msgstr "使用サーフィス:"
 
-#: lib/ninix/ngm.py:593
+#: lib/ninix/ngm.py:586
 msgid " Web Page"
 msgstr "公開ページ"
 
@@ -266,187 +266,163 @@ msgstr "速い"
 msgid "Slow"
 msgstr "遅い"
 
-#: lib/ninix/prefs.py:148
+#: lib/ninix/prefs.py:141
 msgid "Font"
 msgstr "フォント"
 
-#: lib/ninix/prefs.py:149 lib/ninix/prefs.py:314
-msgid "Browser"
-msgstr "ブラウザ"
-
-#: lib/ninix/prefs.py:150
-msgid "Helper"
-msgstr "ヘルパー"
-
-#: lib/ninix/prefs.py:151
+#: lib/ninix/prefs.py:142
 msgid "Surface&Balloon"
 msgstr "サーフェス&バルーン"
 
-#: lib/ninix/prefs.py:152
+#: lib/ninix/prefs.py:143
 msgid "Misc"
 msgstr "色々"
 
-#: lib/ninix/prefs.py:153
+#: lib/ninix/prefs.py:144
 msgid "Debug"
 msgstr "デバッグ"
 
-#: lib/ninix/prefs.py:300
+#: lib/ninix/prefs.py:262
 msgid "Font(s) for balloons"
 msgstr "バルーンフォント"
 
-#: lib/ninix/prefs.py:334
-msgid "- %s in this command line will be replaced with the URL"
-msgstr "・コマンド中の %s は URL に置き換えられます"
-
-#: lib/ninix/prefs.py:338 lib/ninix/prefs.py:406
-msgid "- trailing & is not required.(automagically added)"
-msgstr "・末尾に & を付ける必要はありません (自動的に付加されます)"
-
-#: lib/ninix/prefs.py:348
-msgid "Application"
-msgstr "アプリケーション"
-
-#: lib/ninix/prefs.py:402
-msgid "- %s in this command line will be replaced with the filename"
-msgstr "・コマンド中の %s はファイル名に置き換えられます"
-
-#: lib/ninix/prefs.py:417
+#: lib/ninix/prefs.py:276
 msgid "Surface Scaling"
 msgstr "サーフェス倍率"
 
-#: lib/ninix/prefs.py:428 lib/ninix/prefs.py:546
+#: lib/ninix/prefs.py:287 lib/ninix/prefs.py:405
 msgid "Default Setting"
 msgstr "デフォルト設定"
 
-#: lib/ninix/prefs.py:436
+#: lib/ninix/prefs.py:295
 msgid "Scale Balloon"
 msgstr "バルーンもいっしょ"
 
-#: lib/ninix/prefs.py:440
+#: lib/ninix/prefs.py:299
 msgid "Default Balloon"
 msgstr "デフォルトのバルーン"
 
-#: lib/ninix/prefs.py:460
+#: lib/ninix/prefs.py:319
 msgid "Balloon Name"
 msgstr "バルーン名"
 
-#: lib/ninix/prefs.py:466
+#: lib/ninix/prefs.py:325
 msgid "Always Use This Balloon"
 msgstr "常にこのバルーンを使う"
 
-#: lib/ninix/prefs.py:470
+#: lib/ninix/prefs.py:329
 msgid "Translucency"
 msgstr "透過処理"
 
-#: lib/ninix/prefs.py:478
+#: lib/ninix/prefs.py:337
 msgid "Use PNA file"
 msgstr "PNAファイルを使用する"
 
-#: lib/ninix/prefs.py:485
+#: lib/ninix/prefs.py:344
 msgid "Surfaces' alpha channel"
 msgstr "サーフェスの透過率"
 
-#: lib/ninix/prefs.py:495
+#: lib/ninix/prefs.py:354
 msgid "Balloons' alpha channel"
 msgstr "バルーンの透過率"
 
-#: lib/ninix/prefs.py:502
+#: lib/ninix/prefs.py:361
 msgid "Animation"
 msgstr "アニメーション"
 
-#: lib/ninix/prefs.py:513
+#: lib/ninix/prefs.py:372
 msgid "Quality"
 msgstr "品質"
 
-#: lib/ninix/prefs.py:521
+#: lib/ninix/prefs.py:380
 msgid "SERIKO INACTIVE"
 msgstr "アニメーション抑制"
 
-#: lib/ninix/prefs.py:531
+#: lib/ninix/prefs.py:390
 msgid "SSTP Setting"
 msgstr "SSTP 設定"
 
-#: lib/ninix/prefs.py:535
+#: lib/ninix/prefs.py:394
 msgid "Allowembryo"
 msgstr "IfGhostに一致するゴーストがいない場合に他のゴーストで再生(SEND/1.4)"
 
-#: lib/ninix/prefs.py:539
+#: lib/ninix/prefs.py:398
 msgid "Script Wait"
 msgstr "表示ウェイト"
 
-#: lib/ninix/prefs.py:554
+#: lib/ninix/prefs.py:413
 msgid "Raise & Lower"
 msgstr "Raise & Lower"
 
-#: lib/ninix/prefs.py:562
+#: lib/ninix/prefs.py:421
 msgid "Sink after Talk"
 msgstr "喋り終わると裏へ沈む"
 
-#: lib/ninix/prefs.py:566
+#: lib/ninix/prefs.py:425
 msgid "Raise before Talk"
 msgstr "喋る時手前に出てくる"
 
-#: lib/ninix/prefs.py:576
+#: lib/ninix/prefs.py:435
 msgid "Surface Debugging"
 msgstr "サーフェスのデバッグ"
 
-#: lib/ninix/prefs.py:580
+#: lib/ninix/prefs.py:439
 msgid "Display Collision Area"
 msgstr "当たり判定領域を表示する"
 
-#: lib/ninix/sakura.py:289
+#: lib/ninix/sakura.py:297
 msgid "Network Update has begun."
 msgstr "ネットワーク更新を開始しました。"
 
-#: lib/ninix/sakura.py:293
+#: lib/ninix/sakura.py:301
 msgid "Network Update completed successfully."
 msgstr "ネットワーク更新に成功しました。"
 
-#: lib/ninix/sakura.py:297
+#: lib/ninix/sakura.py:305
 msgid "Network Update failed."
 msgstr "ネットワーク更新に失敗しました。"
 
-#: lib/ninix/sakura.py:433
+#: lib/ninix/sakura.py:437
 msgid "Sakura&Unyuu"
 msgstr "さくら&うにゅう"
 
-#: lib/ninix/sakura.py:438
+#: lib/ninix/sakura.py:442
 msgid "User"
 msgstr "ユーザーさん"
 
-#: lib/ninix/sakura.py:442 lib/ninix/sakura.py:446
+#: lib/ninix/sakura.py:446 lib/ninix/sakura.py:450
 msgid "Sakura"
 msgstr "さくら"
 
-#: lib/ninix/sakura.py:450
+#: lib/ninix/sakura.py:454
 msgid "Unyuu"
 msgstr "うにゅう"
 
-#: lib/ninix/sakura.py:455
+#: lib/ninix/sakura.py:459
 msgid "Tomoyo"
 msgstr "知世"
 
-#: lib/ninix/sakura.py:757
+#: lib/ninix/sakura.py:761
 msgid "Own Balloon"
 msgstr "専用バルーン"
 
-#: lib/ninix/sakura.py:948
+#: lib/ninix/sakura.py:952
 msgid "Master"
 msgstr "マスター"
 
-#: lib/ninix/sakura.py:1757
+#: lib/ninix/sakura.py:1762
 msgid "I'm afraid I don't have Network Update yet."
 msgstr "ネットワーク更新、\\w4まだ無いの。"
 
-#: lib/ninix/sakura.py:1782
+#: lib/ninix/sakura.py:1787
 msgid "Vanish"
 msgstr "消滅指示"
 
-#: lib/ninix/sakura.py:1789
+#: lib/ninix/sakura.py:1794
 msgid "Yes"
 msgstr "はい"
 
-#: lib/ninix/sakura.py:1793
+#: lib/ninix/sakura.py:1798
 msgid "No"
 msgstr "いいえ"