PyCodeBattler β

Pythonista 達の熱き闘いが,

今,始まる...!!

[2010/12/19 00:44:06] 登録

名前

リリィ・カーン

ステータス

HP SP 攻撃力 集中力 防御力 素早さ
1498 25 115 68 9 5 2

必殺技

名前 タイプ レベル 消費 SP
パイレーツシップ SuicideAttackType 1 4

コード

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2009-2010, Atzm WATANABE
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# $Id: tvctl.py 43 2010-12-13 13:50:29Z atzm $

import sys
import os
import os.path
import glob
import commands
import gettext
import gobject
import gtk
import gst

from ConfigParser import SafeConfigParser, NoSectionError, NoOptionError
from cStringIO import StringIO

__author__ = '$Author: atzm $'
__copyright__ = 'Copyright 2009-2010, Atzm WATANABE'
__credits__ = [__author__]
__license__ = 'BSD-2'
__version__ = '$Revision: 43 $'
__maintainer__ = __author__
__email__ = 'atzm@atzm.org'
__status__ = 'Development'

CMD_CH = 'ivtv-tune -d %s -t %s -c %d > /dev/null 2>&1'
CMD_BL = 'v4l2-ctl -d %s -t %s > /dev/null 2>&1'
CMD_BL_GET = 'v4l2-ctl -d %s -T'
CMD_IN = 'v4l2-ctl -d %s --set-input %d > /dev/null 2>&1'
CMD_IN_GET = "v4l2-ctl -d %s --get-input | awk '{print $4}'"
CMD_INLST_GET = 'v4l2-ctl -d %s --list-input'
CMD_CTRL_SET = 'v4l2-ctl -d %s -c %s=%d'
CMD_CTRL_GET = "v4l2-ctl -d %s -C %s | awk -F': ' '{print $2}'"
CMD_STND_SET = 'v4l2-ctl -d %s -s %d'
CMD_STND_GET = "v4l2-ctl -d %s -S | head -1 | awk -F= '{print $2}'"
CMD_STNDLST_GET = 'v4l2-ctl -d %s --list-standards'

gettext.install('tvctl')

config = SafeConfigParser()
config.readfp(
    StringIO("""
[gui]
channel_max:   12
channel_width: 3
"""))
config.read(os.path.expanduser('~/.tvctl'))


def v4l2_ctl_get(*args):
    return commands.getoutput(CMD_CTRL_GET % args)


def v4l2_ctl_set(*args):
    return commands.getoutput(CMD_CTRL_SET % args)


def get_inputs(*args):
    val = commands.getoutput(CMD_INLST_GET % args)
    _dict = {}

    for item in [v.split('\n') for v in val.split('\n\n')]:
        _input = _name = None

        for i in item:
            key, value = [v.strip() for v in i.split(':', 1)]
            key = key.lower()

            if key == 'input':
                _input = int(value)
            elif key == 'name':
                _name = value

        if None not in [_input, _name]:
            _dict[_input] = _name

    return _dict


def get_audio_mode(*args):
    val = commands.getoutput(CMD_BL_GET % args)

    for item in [v.split('\n') for v in val.split('\n\n')]:
        for i in item:
            key, value = [v.strip() for v in i.split(':', 1)]
            key = key.lower()

            if key == 'current audio mode':
                return value

    raise RuntimeError(val)


def get_standards(*args):
    val = commands.getoutput(CMD_STNDLST_GET % args)
    _list = [v.split('\n') for v in val.split('\n\n')]

    for item in _list:
        _index = _id = _name = None

        for i in item:
            key, value = [v.strip() for v in i.split(':', 1)]
            key = key.lower()

            # index is zero origin :-)
            if key == 'index':
                _index = int(value)
            elif key == 'id':
                _id = int(value, 16)
            elif key == 'name':
                _name = value

        if None not in [_index, _id, _name]:
            _list[_index] = (_id, _name)

    return _list


class ChannelTable(gtk.Frame):
    def __init__(self, device='/dev/video0',
                 max_ch=config.getint('gui', 'channel_max'),
                 width=config.getint('gui', 'channel_width')):

        gtk.Frame.__init__(self, label=_('Channel'))
        self.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
        self.set_border_width(3)

        self._tooltips = gtk.Tooltips()
        self._table = gtk.Table(width, max_ch / width)
        self._device = device
        self._buttons = {}

        _prev_radio_button = None

        for _ch in range(max_ch):
            ch = _ch + 1
            col = _ch % width
            row = _ch / width
            ch = str(ch)

            b = gtk.RadioButton(group=_prev_radio_button, label=ch)
            b.set_mode(False)
            b.connect('toggled', self._button_toggled, ch)

            try:
                tip = config.get('channel_alias', ch)
                self._tooltips.set_tip(b, tip)
            except (NoSectionError, NoOptionError):
                pass

            self._buttons[ch] = _prev_radio_button = b
            self._table.attach(b, col, col + 1, row, row + 1,
                               gtk.FILL, gtk.FILL, 2, 2)

        self.add(self._table)

    def _button_toggled(self, button, ch):
        if not button.get_active():
            return True

        freq = 'japan-bcast'
        if config.has_option('channel_assign', ch):
            freq, ch = config.get('channel_assign', ch).split()

        os.system(CMD_CH % (self._device, freq, int(ch)))


class AudioModeTable(gtk.Frame):
    def __init__(self, device='/dev/video0'):
        gtk.Frame.__init__(self, label=_('Audio Mode'))
        self.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
        self.set_border_width(3)

        self._vbox = gtk.VBox(True, 2)
        self._device = device
        self._buttons = {}
        self._table = {
            _('Mono'):      'mono',
            _('Stereo'):    'stereo',
            _('Lang1'):     'lang1',
            _('Lang2'):     'lang2',
            _('Bilingual'): 'bilingual',
        }

        _cur_mode = get_audio_mode(device)
        _prev_radio_button = None

        for label in sorted(self._table.keys()):
            mode = self._table[label]
            b = gtk.RadioButton(group=_prev_radio_button, label=label)
            if mode == _cur_mode:
                b.set_active(True)
            b.set_mode(False)
            b.connect('toggled', self._button_toggled, mode)
            self._buttons[label] = _prev_radio_button = b
            self._vbox.pack_start(b)

        self.add(self._vbox)

    def _button_toggled(self, button, mode):
        if not button.get_active():
            return True
        os.system(CMD_BL % (self._device, mode))


class InputTable(gtk.Frame):
    def __init__(self, device='/dev/video0'):
        gtk.Frame.__init__(self, label=_('Input'))
        self.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
        self.set_border_width(3)

        self._vbox = gtk.VBox(True, 2)
        self._device = device
        self._buttons = {}
        self._table = get_inputs(device)

        _cur_input = int(commands.getoutput(CMD_IN_GET % device))
        _prev_radio_button = None

        for num in sorted(self._table.keys()):
            label = self._table[num]
            b = gtk.RadioButton(group=_prev_radio_button, label=label)
            if num == _cur_input:
                b.set_active(True)
            b.set_mode(False)
            b.connect('toggled', self._button_toggled, num)
            self._buttons[label] = _prev_radio_button = b
            self._vbox.pack_start(b)

        self.add(self._vbox)

    def _button_toggled(self, button, num):
        if not button.get_active():
            return True
        os.system(CMD_IN % (self._device, num))


class StandardsComboBox(gtk.ComboBox):
    def __init__(self, device='/dev/video0'):
        self._device = device
        self._standards = get_standards(device)
        self._list_store = gtk.ListStore(gobject.TYPE_STRING)
        self._cell = gtk.CellRendererText()

        gtk.ComboBox.__init__(self, self._list_store)
        self.pack_start(self._cell, True)
        self.add_attribute(self._cell, 'text', 0)

        for _id, _name in self._standards:
            self.append_text(_name)

        self._set_active_by_id(
            int(commands.getoutput(CMD_STND_GET % self._device), 16))

        self.connect('changed', self._changed)

    def _set_active_by_id(self, _id):
        for i in range(len(self._standards)):
            if self._standards[i][0] == _id:
                self.set_active(i)
                break

    def _changed(self, combo_box):
        os.system(CMD_STND_SET % (self._device, combo_box.get_active()))


class V4L2ControlScale(gtk.Frame):
    def __init__(self, label, ctrl, max_val, device='/dev/video0'):
        self._device = device
        self._label = label
        self._ctrl = ctrl
        self._max_val = max_val

        gtk.Frame.__init__(self, label=self._label)
        self.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
        self.set_border_width(3)

        current = v4l2_ctl_get(self._device, self._ctrl)
        default = int(float(current) / self._max_val * 100)

        self._adj = gtk.Adjustment(default, 0, 100, 1, 10, 0)
        self._adj.connect('value-changed', self._adj_value_changed)

        self._hscale = gtk.HScale(self._adj)
        self._hscale.set_value_pos(gtk.POS_RIGHT)
        self._hscale.set_digits(0)

        self.vbox = gtk.VBox(False, 0)
        self.vbox.pack_start(self._hscale)

        self.add(self.vbox)

    def _adj_value_changed(self, adj):
        val = self._max_val * (adj.get_value() / 100)
        return v4l2_ctl_set(self._device, self._ctrl, val)


class VolumeScale(V4L2ControlScale):
    def __init__(self, device='/dev/video0'):
        V4L2ControlScale.__init__(self, device=device, label=_('Volume'),
                                  ctrl='volume', max_val=65535)

        mute = bool(int(v4l2_ctl_get(self._device, 'mute')))

        self._mute_button = gtk.CheckButton(label=_('Mute'))
        self._mute_button.set_active(mute)
        self._mute_button.connect('toggled', self._button_toggled)
        self.get_child().pack_start(self._mute_button)

    def _button_toggled(self, button):
        mute = int(button.get_active())
        v4l2_ctl_set(self._device, 'mute', mute)


class PlayButton(gtk.Button):
    def __init__(self, device='/dev/video0'):
        gtk.Button.__init__(self)

        self._image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PLAY,
                                               gtk.ICON_SIZE_BUTTON)
        self.set_property('image', self._image)

        self._player = gst.element_factory_make('playbin2', 'player')
        self._player.set_property('uri', 'file://' + device)

        bus = self._player.get_bus()
        bus.add_signal_watch()
        bus.connect('message', self._caught_message)

        self.connect('clicked', self._button_clicked)

    def _start(self):
        self._player.set_state(gst.STATE_PLAYING)
        self._image.set_from_stock(gtk.STOCK_MEDIA_STOP, gtk.ICON_SIZE_BUTTON)

    def _stop(self):
        self._player.set_state(gst.STATE_NULL)
        self._image.set_from_stock(gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_BUTTON)

    def _button_clicked(self, button):
        if self._image.get_stock()[0] == gtk.STOCK_MEDIA_PLAY:
            self._start()
        else:
            self._stop()

    def _caught_message(self, bus, msg):
        if msg.type in [gst.MESSAGE_EOS, gst.MESSAGE_ERROR]:
            self._stop()


class DeviceNotebook(gtk.Notebook):
    def __init__(self):
        gtk.Notebook.__init__(self)
        self._devices = glob.glob('/dev/video?')
        self._devices.sort()

        for d in self._devices:
            hbox = gtk.HBox(False, 5)
            hbox.pack_start(ChannelTable(device=d))
            hbox.pack_start(AudioModeTable(device=d))
            hbox.pack_start(InputTable(device=d))

            hbox2 = gtk.HBox(False, 5)
            hbox2.pack_start(PlayButton(device=d))
            hbox2.pack_start(StandardsComboBox(device=d))

            #volume = VolumeScale(device=d)
            #balance = V4L2ControlScale(device=d, label=_('Balance'),
            #                           ctrl='balance', max_val=65535)
            brightness = V4L2ControlScale(device=d, label=_('Brightness'),
                                          ctrl='brightness', max_val=255)
            contrast = V4L2ControlScale(device=d, label=_('Contrast'),
                                        ctrl='contrast', max_val=127)

            vbox = gtk.VBox(False, 0)
            vbox.pack_start(hbox)
            vbox.pack_start(hbox2)
            #vbox.pack_start(volume)
            #vbox.pack_start(balance)
            vbox.pack_start(brightness)
            vbox.pack_start(contrast)

            self.append_page(vbox, gtk.Label(os.path.basename(d)))


def main():
    notebook = DeviceNotebook()

    window = gtk.Window()
    window.set_title(_('TV Controller'))
    window.connect('destroy', lambda w: gtk.main_quit())

    window.add(notebook)
    window.show_all()
    gtk.main()


if __name__ == '__main__':
    main()