From cc597cf01ef54fb7c558456b35b5a401e2e6f5d4 Mon Sep 17 00:00:00 2001 From: Radek SPRTA Date: Sun, 28 May 2017 17:35:33 +0200 Subject: [PATCH 1/4] Make pyaudio optional --- safeeyes/SettingsDialog.py | 355 +++++++++-------- safeeyes/Utility.py | 714 +++++++++++++++++++---------------- safeeyes/config/lang/cs.json | 2 + safeeyes/config/lang/en.json | 2 + safeeyes/config/lang/es.json | 2 + safeeyes/config/lang/fr.json | 2 + safeeyes/config/lang/ge.json | 2 + safeeyes/config/lang/hi.json | 2 + safeeyes/config/lang/hu.json | 2 + safeeyes/config/lang/id.json | 2 + safeeyes/config/lang/mk.json | 2 + safeeyes/config/lang/pl.json | 2 + safeeyes/config/lang/pt.json | 2 + safeeyes/config/lang/ru.json | 2 + safeeyes/config/lang/sk.json | 2 + safeeyes/config/lang/ta.json | 2 + safeeyes/config/lang/tr.json | 2 + safeeyes/config/lang/vi.json | 2 + setup.py | 41 +- 19 files changed, 653 insertions(+), 489 deletions(-) diff --git a/safeeyes/SettingsDialog.py b/safeeyes/SettingsDialog.py index 842de04..a60723d 100644 --- a/safeeyes/SettingsDialog.py +++ b/safeeyes/SettingsDialog.py @@ -21,175 +21,230 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk, Gdk, GdkX11, GObject from safeeyes import Utility + class SettingsDialog: - """ - Create and initialize SettingsDialog instance. - """ - def __init__(self, config, language, languages, able_to_lock_screen, on_save_settings, glade_file): - self.config = config - self.on_save_settings = on_save_settings - self.languages = [] + """ + Create and initialize SettingsDialog instance. + """ - builder = Gtk.Builder() - builder.add_from_file(glade_file) - builder.connect_signals(self) + def __init__(self, config, language, languages, able_to_lock_screen, on_save_settings, glade_file): + self.config = config + self.on_save_settings = on_save_settings + self.language = language + self.languages = [] - # Get the UI components - self.window = builder.get_object('window_settings') - self.spin_short_break_duration = builder.get_object('spin_short_break_duration') - self.spin_long_break_duration = builder.get_object('spin_long_break_duration') - self.spin_interval_between_two_breaks = builder.get_object('spin_interval_between_two_breaks') - self.spin_short_between_long = builder.get_object('spin_short_between_long') - self.spin_time_to_prepare = builder.get_object('spin_time_to_prepare') - self.spin_idle_time_to_pause = builder.get_object('spin_idle_time_to_pause') - self.spin_postpone_duration = builder.get_object('spin_postpone_duration') - self.switch_show_time_in_tray = builder.get_object('switch_show_time_in_tray') - self.switch_strict_break = builder.get_object('switch_strict_break') - self.switch_postpone = builder.get_object('switch_postpone') - self.switch_audible_alert = builder.get_object('switch_audible_alert') - self.cmb_language = builder.get_object('cmb_language') - self.switch_screen_lock = builder.get_object('switch_screen_lock') - self.spin_time_to_screen_lock = builder.get_object('spin_time_to_screen_lock') + builder = Gtk.Builder() + builder.add_from_file(glade_file) + builder.connect_signals(self) - # Translate the UI labels - builder.get_object('lbl_short_break').set_label(language['ui_controls']['short_break_duration']) - builder.get_object('lbl_long_break').set_label(language['ui_controls']['long_break_duration']) - builder.get_object('lbl_interval_bettween_breaks').set_label(language['ui_controls']['interval_between_two_breaks']) - builder.get_object('lbl_short_per_long').set_label(language['ui_controls']['no_of_short_breaks_between_two_long_breaks']) - builder.get_object('lbl_time_to_prepare').set_label(language['ui_controls']['time_to_prepare_for_break']) - builder.get_object('lbl_idle_time_to_pause').set_label(language['ui_controls']['idle_time']) - builder.get_object('lbl_postpone_duration').set_label(language['ui_controls']['postpone_duration']) - builder.get_object('lbl_allow_postpone').set_label(language['ui_controls']['allow_postpone']) - builder.get_object('lbl_show_time_in_tray').set_label(language['ui_controls']['show_time_in_tray']) - builder.get_object('lbl_strict_break').set_label(language['ui_controls']['strict_break']) - builder.get_object('lbl_audible_alert').set_label(language['ui_controls']['audible_alert']) - builder.get_object('lbl_language').set_label(language['ui_controls']['language']) - builder.get_object('lbl_enable_screen_lock').set_label(language['ui_controls']['enable_screen_lock']) - builder.get_object('lbl_lock_screen_after').set_label(language['ui_controls']['time_to_screen_lock']) - builder.get_object('btn_cancel').set_label(language['ui_controls']['cancel']) - builder.get_object('btn_save').set_label(language['ui_controls']['save']) + # Get the UI components + self.window = builder.get_object('window_settings') + self.spin_short_break_duration = builder.get_object( + 'spin_short_break_duration') + self.spin_long_break_duration = builder.get_object( + 'spin_long_break_duration') + self.spin_interval_between_two_breaks = builder.get_object( + 'spin_interval_between_two_breaks') + self.spin_short_between_long = builder.get_object( + 'spin_short_between_long') + self.spin_time_to_prepare = builder.get_object('spin_time_to_prepare') + self.spin_idle_time_to_pause = builder.get_object( + 'spin_idle_time_to_pause') + self.spin_postpone_duration = builder.get_object( + 'spin_postpone_duration') + self.switch_show_time_in_tray = builder.get_object( + 'switch_show_time_in_tray') + self.switch_strict_break = builder.get_object('switch_strict_break') + self.switch_postpone = builder.get_object('switch_postpone') + self.switch_audible_alert = builder.get_object('switch_audible_alert') + self.cmb_language = builder.get_object('cmb_language') + self.switch_screen_lock = builder.get_object('switch_screen_lock') + self.spin_time_to_screen_lock = builder.get_object( + 'spin_time_to_screen_lock') - # Set the current values of input fields - self.spin_short_break_duration.set_value(config['short_break_duration']) - self.spin_long_break_duration.set_value(config['long_break_duration']) - self.spin_interval_between_two_breaks.set_value(config['break_interval']) - self.spin_short_between_long.set_value(config['no_of_short_breaks_per_long_break']) - self.spin_time_to_prepare.set_value(config['pre_break_warning_time']) - self.spin_idle_time_to_pause.set_value(config['idle_time']) - self.spin_postpone_duration.set_value(config['postpone_duration']) - self.switch_show_time_in_tray.set_active(config['show_time_in_tray']) - self.switch_strict_break.set_active(config['strict_break']) - self.switch_audible_alert.set_active(config['audible_alert']) - self.spin_time_to_screen_lock.set_value(config['time_to_screen_lock']) + # Translate the UI labels + builder.get_object('lbl_short_break').set_label( + language['ui_controls']['short_break_duration']) + builder.get_object('lbl_long_break').set_label( + language['ui_controls']['long_break_duration']) + builder.get_object('lbl_interval_bettween_breaks').set_label( + language['ui_controls']['interval_between_two_breaks']) + builder.get_object('lbl_short_per_long').set_label( + language['ui_controls']['no_of_short_breaks_between_two_long_breaks']) + builder.get_object('lbl_time_to_prepare').set_label( + language['ui_controls']['time_to_prepare_for_break']) + builder.get_object('lbl_idle_time_to_pause').set_label( + language['ui_controls']['idle_time']) + builder.get_object('lbl_postpone_duration').set_label( + language['ui_controls']['postpone_duration']) + builder.get_object('lbl_allow_postpone').set_label( + language['ui_controls']['allow_postpone']) + builder.get_object('lbl_show_time_in_tray').set_label( + language['ui_controls']['show_time_in_tray']) + builder.get_object('lbl_strict_break').set_label( + language['ui_controls']['strict_break']) + builder.get_object('lbl_audible_alert').set_label( + language['ui_controls']['audible_alert']) + builder.get_object('lbl_language').set_label( + language['ui_controls']['language']) + builder.get_object('lbl_enable_screen_lock').set_label( + language['ui_controls']['enable_screen_lock']) + builder.get_object('lbl_lock_screen_after').set_label( + language['ui_controls']['time_to_screen_lock']) + builder.get_object('btn_cancel').set_label( + language['ui_controls']['cancel']) + builder.get_object('btn_save').set_label( + language['ui_controls']['save']) - # Enable idle_time_to_pause only if xprintidle is available - self.spin_idle_time_to_pause.set_sensitive(Utility.command_exist('xprintidle')) + # Set the current values of input fields + self.spin_short_break_duration.set_value( + config['short_break_duration']) + self.spin_long_break_duration.set_value(config['long_break_duration']) + self.spin_interval_between_two_breaks.set_value( + config['break_interval']) + self.spin_short_between_long.set_value( + config['no_of_short_breaks_per_long_break']) + self.spin_time_to_prepare.set_value(config['pre_break_warning_time']) + self.spin_idle_time_to_pause.set_value(config['idle_time']) + self.spin_postpone_duration.set_value(config['postpone_duration']) + self.switch_show_time_in_tray.set_active(config['show_time_in_tray']) + self.switch_strict_break.set_active(config['strict_break']) + self.switch_audible_alert.set_active(config['audible_alert']) + self.spin_time_to_screen_lock.set_value(config['time_to_screen_lock']) - self.switch_screen_lock.set_sensitive(able_to_lock_screen) - self.switch_screen_lock.set_active(able_to_lock_screen and config['enable_screen_lock']) - self.switch_postpone.set_active(config['allow_postpone'] and not config['strict_break']) + # Enable idle_time_to_pause only if xprintidle is available + self.spin_idle_time_to_pause.set_sensitive( + Utility.command_exist('xprintidle')) - # Update relative states - # GtkSwitch state-set signal is available only from 3.14 - if Gtk.get_minor_version() >= 14: - self.switch_strict_break.connect('state-set', self.on_switch_strict_break_activate) - self.switch_screen_lock.connect('state-set', self.on_switch_screen_lock_activate) - self.switch_postpone.connect('state-set', self.on_switch_postpone_activate) - self.on_switch_strict_break_activate(self.switch_strict_break, self.switch_strict_break.get_active()) - self.on_switch_screen_lock_activate(self.switch_screen_lock, self.switch_screen_lock.get_active()) - self.on_switch_postpone_activate(self.switch_postpone, self.switch_postpone.get_active()) + self.switch_screen_lock.set_sensitive(able_to_lock_screen) + self.switch_screen_lock.set_active( + able_to_lock_screen and config['enable_screen_lock']) + self.switch_postpone.set_active( + config['allow_postpone'] and not config['strict_break']) - # Initialize the language combobox - language_list_store = Gtk.ListStore(GObject.TYPE_STRING) - language_index = 2 - lang_code = config['language'] + # Update relative states + # GtkSwitch state-set signal is available only from 3.14 + if Gtk.get_minor_version() >= 14: + self.switch_strict_break.connect( + 'state-set', self.on_switch_strict_break_activate) + self.switch_screen_lock.connect( + 'state-set', self.on_switch_screen_lock_activate) + self.switch_postpone.connect( + 'state-set', self.on_switch_postpone_activate) + self.on_switch_strict_break_activate( + self.switch_strict_break, self.switch_strict_break.get_active()) + self.on_switch_screen_lock_activate( + self.switch_screen_lock, self.switch_screen_lock.get_active()) + self.on_switch_postpone_activate( + self.switch_postpone, self.switch_postpone.get_active()) - # Add 'System Language' as the first option - language_list_store.append([language['ui_controls']['system_language']]) - language_list_store.append(['-']) - self.languages.append('system') - self.languages.append('system') # Dummy record for row separator - if 'system' == lang_code: - self.cmb_language.set_active(0) + # Initialize the language combobox + language_list_store = Gtk.ListStore(GObject.TYPE_STRING) + language_index = 2 + lang_code = config['language'] - for key in sorted(languages.keys()): - language_list_store.append([languages[key]]) - self.languages.append(key) - if key == lang_code: - self.cmb_language.set_active(language_index) - language_index += 1 + # Add 'System Language' as the first option + language_list_store.append( + [language['ui_controls']['system_language']]) + language_list_store.append(['-']) + self.languages.append('system') + self.languages.append('system') # Dummy record for row separator + if 'system' == lang_code: + self.cmb_language.set_active(0) - self.cmb_language.set_model(language_list_store) - self.cmb_language.set_row_separator_func(lambda m,i: m.get_value(i, 0) == '-') - cell = Gtk.CellRendererText() - self.cmb_language.pack_start(cell, True) - self.cmb_language.add_attribute(cell, 'text', 0) + for key in sorted(languages.keys()): + language_list_store.append([languages[key]]) + self.languages.append(key) + if key == lang_code: + self.cmb_language.set_active(language_index) + language_index += 1 + self.cmb_language.set_model(language_list_store) + self.cmb_language.set_row_separator_func( + lambda m, i: m.get_value(i, 0) == '-') + cell = Gtk.CellRendererText() + self.cmb_language.pack_start(cell, True) + self.cmb_language.add_attribute(cell, 'text', 0) - def show(self): - """ - Show the SettingsDialog. - """ - self.window.show_all() + def show(self): + """ + Show the SettingsDialog. + """ + self.window.show_all() + def on_switch_screen_lock_activate(self, switch, state): + """ + Event handler to the state change of the screen_lock switch. + Enable or disable the self.spin_time_to_screen_lock based on the state of the screen_lock switch. + """ + self.spin_time_to_screen_lock.set_sensitive( + self.switch_screen_lock.get_active()) - def on_switch_screen_lock_activate(self, switch, state): - """ - Event handler to the state change of the screen_lock switch. - Enable or disable the self.spin_time_to_screen_lock based on the state of the screen_lock switch. - """ - self.spin_time_to_screen_lock.set_sensitive(self.switch_screen_lock.get_active()) + def on_switch_strict_break_activate(self, switch, state): + """ + Event handler to the state change of the postpone switch. + Enable or disable the self.spin_postpone_duration based on the state of the postpone switch. + """ + strict_break_enable = state # self.switch_strict_break.get_active() + self.switch_postpone.set_sensitive(not strict_break_enable) + if strict_break_enable: + self.switch_postpone.set_active(False) + def on_switch_postpone_activate(self, switch, state): + """ + Event handler to the state change of the postpone switch. + Enable or disable the self.spin_postpone_duration based on the state of the postpone switch. + """ + self.spin_postpone_duration.set_sensitive( + self.switch_postpone.get_active()) - def on_switch_strict_break_activate(self, switch, state): - """ - Event handler to the state change of the postpone switch. - Enable or disable the self.spin_postpone_duration based on the state of the postpone switch. - """ - strict_break_enable = state #self.switch_strict_break.get_active() - self.switch_postpone.set_sensitive(not strict_break_enable) - if strict_break_enable: - self.switch_postpone.set_active(False) + def on_window_delete(self, *args): + """ + Event handler for Settings dialog close action. + """ + self.window.destroy() - def on_switch_postpone_activate(self, switch, state): - """ - Event handler to the state change of the postpone switch. - Enable or disable the self.spin_postpone_duration based on the state of the postpone switch. - """ - self.spin_postpone_duration.set_sensitive(self.switch_postpone.get_active()) + def on_save_clicked(self, button): + """ + Event handler for Save button click. + """ + self.config[ + 'short_break_duration'] = self.spin_short_break_duration.get_value_as_int() + self.config[ + 'long_break_duration'] = self.spin_long_break_duration.get_value_as_int() + self.config[ + 'break_interval'] = self.spin_interval_between_two_breaks.get_value_as_int() + self.config[ + 'no_of_short_breaks_per_long_break'] = self.spin_short_between_long.get_value_as_int() + self.config[ + 'pre_break_warning_time'] = self.spin_time_to_prepare.get_value_as_int() + self.config[ + 'idle_time'] = self.spin_idle_time_to_pause.get_value_as_int() + self.config[ + 'postpone_duration'] = self.spin_postpone_duration.get_value_as_int() + self.config[ + 'show_time_in_tray'] = self.switch_show_time_in_tray.get_active() + self.config['strict_break'] = self.switch_strict_break.get_active() + self.config['language'] = self.languages[ + self.cmb_language.get_active()] + self.config[ + 'time_to_screen_lock'] = self.spin_time_to_screen_lock.get_value_as_int() + self.config['enable_screen_lock'] = self.switch_screen_lock.get_active() + self.config['allow_postpone'] = self.switch_postpone.get_active() - def on_window_delete(self, *args): - """ - Event handler for Settings dialog close action. - """ - self.window.destroy() + # Check if pyaudio is installed when turning audible notifications on + if self.switch_audible_alert.get_active() and not Utility.pyaudio_installed(): + # Notify user if pyaudio is not installed + Utility.pyaudio_popup(self, self.language) + else: + self.config[ + 'audible_alert'] = self.switch_audible_alert.get_active() + self.on_save_settings(self.config) # Call the provided save method + self.window.destroy() # Close the settings window - def on_save_clicked(self, button): - """ - Event handler for Save button click. - """ - self.config['short_break_duration'] = self.spin_short_break_duration.get_value_as_int() - self.config['long_break_duration'] = self.spin_long_break_duration.get_value_as_int() - self.config['break_interval'] = self.spin_interval_between_two_breaks.get_value_as_int() - self.config['no_of_short_breaks_per_long_break'] = self.spin_short_between_long.get_value_as_int() - self.config['pre_break_warning_time'] = self.spin_time_to_prepare.get_value_as_int() - self.config['idle_time'] = self.spin_idle_time_to_pause.get_value_as_int() - self.config['postpone_duration'] = self.spin_postpone_duration.get_value_as_int() - self.config['show_time_in_tray'] = self.switch_show_time_in_tray.get_active() - self.config['strict_break'] = self.switch_strict_break.get_active() - self.config['audible_alert'] = self.switch_audible_alert.get_active() - self.config['language'] = self.languages[self.cmb_language.get_active()] - self.config['time_to_screen_lock'] = self.spin_time_to_screen_lock.get_value_as_int() - self.config['enable_screen_lock'] = self.switch_screen_lock.get_active() - self.config['allow_postpone'] = self.switch_postpone.get_active() - - self.on_save_settings(self.config) # Call the provided save method - self.window.destroy() # Close the settings window - - - def on_cancel_clicked(self, button): - """ - Event handler for Cancel button click. - """ - self.window.destroy() + def on_cancel_clicked(self, button): + """ + Event handler for Cancel button click. + """ + self.window.destroy() diff --git a/safeeyes/Utility.py b/safeeyes/Utility.py index 159031a..e7c53ce 100644 --- a/safeeyes/Utility.py +++ b/safeeyes/Utility.py @@ -18,11 +18,27 @@ import gi gi.require_version('Gdk', '3.0') -from gi.repository import Gdk, GLib +from gi.repository import Gtk, Gdk, GLib from html.parser import HTMLParser from distutils.version import LooseVersion from logging.handlers import RotatingFileHandler -import babel.dates, os, errno, re, subprocess, threading, logging, locale, json, shutil, pyaudio, wave +import babel.dates +import os +import errno +import re +import subprocess +import threading +import logging +import locale +import json +import shutil +import wave + +try: + import pyaudio + print('Pyaudio here') +except ImportError: + print('Install pyaudio for audible notifications.') bin_directory = os.path.dirname(os.path.realpath(__file__)) home_directory = os.path.expanduser('~') @@ -31,425 +47,473 @@ config_directory = os.path.join(home_directory, '.config/safeeyes') config_file_path = os.path.join(config_directory, 'safeeyes.json') style_sheet_path = os.path.join(config_directory, 'style/safeeyes_style.css') system_config_file_path = os.path.join(bin_directory, "config/safeeyes.json") -system_style_sheet_path = os.path.join(bin_directory, "config/style/safeeyes_style.css") +system_style_sheet_path = os.path.join( + bin_directory, "config/style/safeeyes_style.css") log_file_path = os.path.join(config_directory, 'safeeyes.log') + +def pyaudio_installed(): + """ + Check if pyaudio is installed. + + Returns: + bool: True of pyaudio is installed, false otherwise. + """ + try: + import pyaudio + return True + except ImportError: + return False + + +def pyaudio_popup(parent, language): + """ + Show a popup informing user to install pyaudio. + """ + dialog = Gtk.MessageDialog( + parent, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, + language['ui_controls']['pyaudio_not_installed']) + dialog.format_secondary_text( + language['ui_controls']['pyaudio_explanation']) + dialog.run() + dialog.destroy() + + def play_notification(): - """ - Play the alert.wav - """ - logging.info('Playing audible alert') - CHUNK = 1024 + """ + Play the alert.wav + """ + logging.info('Playing audible alert') + CHUNK = 1024 - try: - # Open the sound file - path = get_resource_path('alert.wav') - if path is None: - return - sound = wave.open(path, 'rb') + try: + # Open the sound file + path = get_resource_path('alert.wav') + if path is None: + return + sound = wave.open(path, 'rb') - # Create a sound stream - wrapper = pyaudio.PyAudio() - stream = wrapper.open(format=wrapper.get_format_from_width(sound.getsampwidth()), - channels=sound.getnchannels(), - rate=sound.getframerate(), - output=True) + # Create a sound stream + wrapper = pyaudio.PyAudio() + stream = wrapper.open(format=wrapper.get_format_from_width(sound.getsampwidth()), + channels=sound.getnchannels(), + rate=sound.getframerate(), + output=True) - # Write file data into the sound stream - data = sound.readframes(CHUNK) - while data != b'': - stream.write(data) - data = sound.readframes(CHUNK) + # Write file data into the sound stream + data = sound.readframes(CHUNK) + while data != b'': + stream.write(data) + data = sound.readframes(CHUNK) - # Close steam - stream.stop_stream() - stream.close() - sound.close() - wrapper.terminate() + # Close steam + stream.stop_stream() + stream.close() + sound.close() + wrapper.terminate() - except Exception as e: - logging.warning('Unable to play audible alert') - logging.exception(e) + except Exception as e: + logging.warning('Unable to play audible alert') + logging.exception(e) def get_resource_path(resource_name): - """ - Return the user-defined resource if a system resource is overridden by the user. - Otherwise, return the system resource. Return None if the specified resource does not exist. - """ - if resource_name is None: - return None - resource_location = os.path.join(config_directory, 'resource', resource_name) - if not os.path.isfile(resource_location): - resource_location = os.path.join(bin_directory, 'resource', resource_name) - if not os.path.isfile(resource_location): - logging.error('Resource not found: ' + resource_name) - resource_location = None + """ + Return the user-defined resource if a system resource is overridden by the user. + Otherwise, return the system resource. Return None if the specified resource does not exist. + """ + if resource_name is None: + return None + resource_location = os.path.join( + config_directory, 'resource', resource_name) + if not os.path.isfile(resource_location): + resource_location = os.path.join( + bin_directory, 'resource', resource_name) + if not os.path.isfile(resource_location): + logging.error('Resource not found: ' + resource_name) + resource_location = None - return resource_location + return resource_location def system_idle_time(): - """ - Get system idle time in minutes. - Return the idle time if xprintidle is available, otherwise return 0. - """ - try: - return int(subprocess.check_output(['xprintidle']).decode('utf-8')) / 60000 # Convert to minutes - except: - return 0 + """ + Get system idle time in minutes. + Return the idle time if xprintidle is available, otherwise return 0. + """ + try: + # Convert to minutes + return int(subprocess.check_output(['xprintidle']).decode('utf-8')) / 60000 + except: + return 0 def start_thread(target_function, **args): - """ - Execute the function in a separate thread. - """ - thread = threading.Thread(target=target_function, kwargs=args) - thread.start() + """ + Execute the function in a separate thread. + """ + thread = threading.Thread(target=target_function, kwargs=args) + thread.start() def execute_main_thread(target_function, args=None): - """ - Execute the given function in main thread. - """ - if args: - GLib.idle_add(lambda: target_function(args)) - else: - GLib.idle_add(lambda: target_function()) + """ + Execute the given function in main thread. + """ + if args: + GLib.idle_add(lambda: target_function(args)) + else: + GLib.idle_add(lambda: target_function()) def is_active_window_skipped(skip_break_window_classes, take_break_window_classes, unfullscreen_allowed=False): - """ - Check for full-screen applications. - This method must be executed by the main thread. If not, it will cause to random failure. - """ - logging.info('Searching for full-screen application') - screen = Gdk.Screen.get_default() + """ + Check for full-screen applications. + This method must be executed by the main thread. If not, it will cause to random failure. + """ + logging.info('Searching for full-screen application') + screen = Gdk.Screen.get_default() - active_window = screen.get_active_window() - if active_window: - active_xid = str(active_window.get_xid()) - cmdlist = ['xprop', '-root', '-notype','-id',active_xid, 'WM_CLASS', '_NET_WM_STATE'] + active_window = screen.get_active_window() + if active_window: + active_xid = str(active_window.get_xid()) + cmdlist = ['xprop', '-root', '-notype', '-id', + active_xid, 'WM_CLASS', '_NET_WM_STATE'] - try: - stdout = subprocess.check_output(cmdlist).decode('utf-8') - except subprocess.CalledProcessError: - logging.warning('Error in finding full-screen application') - pass - else: - if stdout: - is_fullscreen = 'FULLSCREEN' in stdout - # Extract the process name - process_names = re.findall('"(.+?)"', stdout) - if process_names: - process = process_names[1].lower() - if process in skip_break_window_classes: - return True - elif process in take_break_window_classes: - if is_fullscreen and unfullscreen_allowed: - try: - active_window.unfullscreen() - except: - logging.error('Error in unfullscreen the window ' + process) - pass - return False + try: + stdout = subprocess.check_output(cmdlist).decode('utf-8') + except subprocess.CalledProcessError: + logging.warning('Error in finding full-screen application') + pass + else: + if stdout: + is_fullscreen = 'FULLSCREEN' in stdout + # Extract the process name + process_names = re.findall('"(.+?)"', stdout) + if process_names: + process = process_names[1].lower() + if process in skip_break_window_classes: + return True + elif process in take_break_window_classes: + if is_fullscreen and unfullscreen_allowed: + try: + active_window.unfullscreen() + except: + logging.error( + 'Error in unfullscreen the window ' + process) + pass + return False - return is_fullscreen + return is_fullscreen - return False + return False def __system_locale(): - """ - Return the system locale. If not available, return en_US.UTF-8. - """ - locale.setlocale(locale.LC_ALL, '') - system_locale = locale.getlocale(locale.LC_TIME)[0] - if not system_locale: - system_locale = 'en_US.UTF-8' - return system_locale + """ + Return the system locale. If not available, return en_US.UTF-8. + """ + locale.setlocale(locale.LC_ALL, '') + system_locale = locale.getlocale(locale.LC_TIME)[0] + if not system_locale: + system_locale = 'en_US.UTF-8' + return system_locale def format_time(time): - """ - Format time based on the system time. - """ - system_locale = __system_locale() - return babel.dates.format_time(time, format='short', locale=system_locale) + """ + Format time based on the system time. + """ + system_locale = __system_locale() + return babel.dates.format_time(time, format='short', locale=system_locale) def mkdir(path): - """ - Create directory if not exists. - """ - try: - os.makedirs(path) - except OSError as exc: - if exc.errno == errno.EEXIST and os.path.isdir(path): - pass - else: - logging.error('Error while creating ' + str(path)) - raise + """ + Create directory if not exists. + """ + try: + os.makedirs(path) + except OSError as exc: + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: + logging.error('Error while creating ' + str(path)) + raise + def parse_language_code(lang_code): - """ - Convert the user defined language code to a valid one. - This includes converting to lower case and finding system locale language, - if the given lang_code code is 'system'. - """ - # Convert to lower case - lang_code = str(lang_code).lower() + """ + Convert the user defined language code to a valid one. + This includes converting to lower case and finding system locale language, + if the given lang_code code is 'system'. + """ + # Convert to lower case + lang_code = str(lang_code).lower() - # If it is system, use the system language - if lang_code == 'system': - logging.info('Use system language for Safe Eyes') - system_locale = __system_locale() - lang_code = system_locale[0:2].lower() + # If it is system, use the system language + if lang_code == 'system': + logging.info('Use system language for Safe Eyes') + system_locale = __system_locale() + lang_code = system_locale[0:2].lower() - # Check whether translation is available for this language. - # If not available, use English by default. - language_file_path = os.path.join(system_language_directory, lang_code + '.json') - if not os.path.exists(language_file_path): - logging.warn('The language {} does not exist. Use English instead'.format(lang_code)) - lang_code = 'en' + # Check whether translation is available for this language. + # If not available, use English by default. + language_file_path = os.path.join( + system_language_directory, lang_code + '.json') + if not os.path.exists(language_file_path): + logging.warn( + 'The language {} does not exist. Use English instead'.format(lang_code)) + lang_code = 'en' - return lang_code + return lang_code def load_language(lang_code): - """ - Load the desired language from the available list based on the preference. - """ - # Convert the user defined language code to a valid one - lang_code = parse_language_code(lang_code) + """ + Load the desired language from the available list based on the preference. + """ + # Convert the user defined language code to a valid one + lang_code = parse_language_code(lang_code) - # Construct the translation file path - language_file_path = os.path.join(system_language_directory, lang_code + '.json') + # Construct the translation file path + language_file_path = os.path.join( + system_language_directory, lang_code + '.json') - language = None - # Read the language file and construct the json object - with open(language_file_path) as language_file: - language = json.load(language_file) + language = None + # Read the language file and construct the json object + with open(language_file_path) as language_file: + language = json.load(language_file) - return language + return language def read_lang_files(): - """ - Read all the language translations and build a key-value mapping of language names - in English and ISO 639-1 (Filename without extension). - """ - languages = {} - for lang_file_name in os.listdir(system_language_directory): - lang_file_path = os.path.join(system_language_directory, lang_file_name) - if os.path.isfile(lang_file_path): - with open(lang_file_path) as lang_file: - lang = json.load(lang_file) - languages[lang_file_name.lower().replace('.json', '')] = lang['meta_info']['language_name'] + """ + Read all the language translations and build a key-value mapping of language names + in English and ISO 639-1 (Filename without extension). + """ + languages = {} + for lang_file_name in os.listdir(system_language_directory): + lang_file_path = os.path.join( + system_language_directory, lang_file_name) + if os.path.isfile(lang_file_path): + with open(lang_file_path) as lang_file: + lang = json.load(lang_file) + languages[lang_file_name.lower().replace('.json', '')] = lang[ + 'meta_info']['language_name'] + + return languages - return languages def lock_screen_command(): - """ - Function tries to detect the screensaver command based on the current envinroment - Possible results: - Gnome, Unity, Budgie: ['gnome-screensaver-command', '--lock'] - Cinnamon: ['cinnamon-screensaver-command', '--lock'] - Pantheon, LXDE: ['light-locker-command', '--lock'] - Mate: ['mate-screensaver-command', '--lock'] - KDE: ['qdbus', 'org.freedesktop.ScreenSaver', '/ScreenSaver', 'Lock'] - XFCE: ['xflock4'] - Otherwise: None - """ - desktop_session = os.environ.get('DESKTOP_SESSION') - current_desktop = os.environ.get('XDG_CURRENT_DESKTOP') - if desktop_session is not None: - desktop_session = desktop_session.lower() - if ('xfce' in desktop_session or desktop_session.startswith('xubuntu') or (current_desktop is not None and 'xfce' in current_desktop)) and command_exist('xflock4'): - return ['xflock4'] - elif desktop_session == 'cinnamon' and command_exist('cinnamon-screensaver-command'): - return ['cinnamon-screensaver-command', '--lock'] - elif (desktop_session == 'pantheon' or desktop_session.startswith('lubuntu')) and command_exist('light-locker-command'): - return ['light-locker-command', '--lock'] - elif desktop_session == 'mate' and command_exist('mate-screensaver-command'): - return ['mate-screensaver-command', '--lock'] - elif desktop_session == 'kde' or 'plasma' in desktop_session or desktop_session.startswith('kubuntu') or os.environ.get('KDE_FULL_SESSION') == 'true': - return ['qdbus', 'org.freedesktop.ScreenSaver', '/ScreenSaver', 'Lock'] - elif desktop_session in ['gnome','unity', 'budgie-desktop'] or desktop_session.startswith('ubuntu'): - if command_exist('gnome-screensaver-command'): - return ['gnome-screensaver-command', '--lock'] - else: - # From Gnome 3.8 no gnome-screensaver-command - return ['dbus-send', '--type=method_call', '--dest=org.gnome.ScreenSaver', '/org/gnome/ScreenSaver', 'org.gnome.ScreenSaver.Lock'] - elif os.environ.get('GNOME_DESKTOP_SESSION_ID'): - if not 'deprecated' in os.environ.get('GNOME_DESKTOP_SESSION_ID') and command_exist('gnome-screensaver-command'): - # Gnome 2 - return ['gnome-screensaver-command', '--lock'] - return None + """ + Function tries to detect the screensaver command based on the current envinroment + Possible results: + Gnome, Unity, Budgie: ['gnome-screensaver-command', '--lock'] + Cinnamon: ['cinnamon-screensaver-command', '--lock'] + Pantheon, LXDE: ['light-locker-command', '--lock'] + Mate: ['mate-screensaver-command', '--lock'] + KDE: ['qdbus', 'org.freedesktop.ScreenSaver', '/ScreenSaver', 'Lock'] + XFCE: ['xflock4'] + Otherwise: None + """ + desktop_session = os.environ.get('DESKTOP_SESSION') + current_desktop = os.environ.get('XDG_CURRENT_DESKTOP') + if desktop_session is not None: + desktop_session = desktop_session.lower() + if ('xfce' in desktop_session or desktop_session.startswith('xubuntu') or (current_desktop is not None and 'xfce' in current_desktop)) and command_exist('xflock4'): + return ['xflock4'] + elif desktop_session == 'cinnamon' and command_exist('cinnamon-screensaver-command'): + return ['cinnamon-screensaver-command', '--lock'] + elif (desktop_session == 'pantheon' or desktop_session.startswith('lubuntu')) and command_exist('light-locker-command'): + return ['light-locker-command', '--lock'] + elif desktop_session == 'mate' and command_exist('mate-screensaver-command'): + return ['mate-screensaver-command', '--lock'] + elif desktop_session == 'kde' or 'plasma' in desktop_session or desktop_session.startswith('kubuntu') or os.environ.get('KDE_FULL_SESSION') == 'true': + return ['qdbus', 'org.freedesktop.ScreenSaver', '/ScreenSaver', 'Lock'] + elif desktop_session in ['gnome', 'unity', 'budgie-desktop'] or desktop_session.startswith('ubuntu'): + if command_exist('gnome-screensaver-command'): + return ['gnome-screensaver-command', '--lock'] + else: + # From Gnome 3.8 no gnome-screensaver-command + return ['dbus-send', '--type=method_call', '--dest=org.gnome.ScreenSaver', '/org/gnome/ScreenSaver', 'org.gnome.ScreenSaver.Lock'] + elif os.environ.get('GNOME_DESKTOP_SESSION_ID'): + if not 'deprecated' in os.environ.get('GNOME_DESKTOP_SESSION_ID') and command_exist('gnome-screensaver-command'): + # Gnome 2 + return ['gnome-screensaver-command', '--lock'] + return None def lock_desktop(command): - """ - Lock the screen using the predefined commands - """ - if command: - try: - subprocess.Popen(command) - except Exception as e: - logging.error('Error in executing the commad' + str(command) + ' to lock screen') + """ + Lock the screen using the predefined commands + """ + if command: + try: + subprocess.Popen(command) + except Exception as e: + logging.error('Error in executing the commad' + + str(command) + ' to lock screen') def html_to_text(html): - """ - Convert HTML to plain text - """ - extractor = __HTMLTextExtractor() - extractor.feed(html) - return extractor.get_data() + """ + Convert HTML to plain text + """ + extractor = __HTMLTextExtractor() + extractor.feed(html) + return extractor.get_data() def command_exist(command): - """ - Check whether the given command exist in the system or not. - """ - if shutil.which(command): - return True - else: - return False + """ + Check whether the given command exist in the system or not. + """ + if shutil.which(command): + return True + else: + return False def merge_configs(new_config, old_config): - """ - Merge the values of old_config into the new_config. - """ - new_config = new_config.copy() - new_config.update(old_config) - return new_config + """ + Merge the values of old_config into the new_config. + """ + new_config = new_config.copy() + new_config.update(old_config) + return new_config def __initialize_safeeyes(): - """ - Create the config file and style sheet in ~/.config/safeeyes directory. - """ - logging.info('Copy the config files to ~/.config/safeeyes') + """ + Create the config file and style sheet in ~/.config/safeeyes directory. + """ + logging.info('Copy the config files to ~/.config/safeeyes') - style_dir_path = os.path.join(home_directory, '.config/safeeyes/style') - startup_dir_path = os.path.join(home_directory, '.config/autostart') + style_dir_path = os.path.join(home_directory, '.config/safeeyes/style') + startup_dir_path = os.path.join(home_directory, '.config/autostart') - # Remove the ~/.config/safeeyes directory - shutil.rmtree(config_directory, ignore_errors=True) + # Remove the ~/.config/safeeyes directory + shutil.rmtree(config_directory, ignore_errors=True) - # Remove the startup file - try: - os.remove(os.path.join(home_directory, os.path.join(startup_dir_path, 'safeeyes.desktop'))) - except: - pass + # Remove the startup file + try: + os.remove(os.path.join(home_directory, os.path.join( + startup_dir_path, 'safeeyes.desktop'))) + except: + pass - # Create the ~/.config/safeeyes/style directory - mkdir(style_dir_path) - mkdir(startup_dir_path) + # Create the ~/.config/safeeyes/style directory + mkdir(style_dir_path) + mkdir(startup_dir_path) - # Copy the safeeyes.json - shutil.copy2(system_config_file_path, config_file_path) + # Copy the safeeyes.json + shutil.copy2(system_config_file_path, config_file_path) - # Copy the new startup file - try: - os.symlink("/usr/share/applications/safeeyes.desktop", os.path.join(startup_dir_path, 'safeeyes.desktop')) - except OSError as exc: - pass + # Copy the new startup file + try: + os.symlink("/usr/share/applications/safeeyes.desktop", + os.path.join(startup_dir_path, 'safeeyes.desktop')) + except OSError as exc: + pass - # Copy the new style sheet - if not os.path.isfile(style_sheet_path): - shutil.copy2(system_style_sheet_path, style_sheet_path) + # Copy the new style sheet + if not os.path.isfile(style_sheet_path): + shutil.copy2(system_style_sheet_path, style_sheet_path) def intialize_logging(): - """ - Initialize the logging framework using the Safe Eyes specific configurations. - """ - # Create the directory to store log file if not exist - if not os.path.exists(config_directory): - try: - os.makedirs(config_directory) - except: - pass + """ + Initialize the logging framework using the Safe Eyes specific configurations. + """ + # Create the directory to store log file if not exist + if not os.path.exists(config_directory): + try: + os.makedirs(config_directory) + except: + pass - # Configure logging. - log_formatter = logging.Formatter('%(asctime)s [%(levelname)s]:[%(threadName)s] %(message)s') + # Configure logging. + log_formatter = logging.Formatter( + '%(asctime)s [%(levelname)s]:[%(threadName)s] %(message)s') - # Apped the logs and overwrite once reached 5MB - handler = RotatingFileHandler(log_file_path, mode='a', maxBytes=5*1024*1024, backupCount=2, encoding=None, delay=0) - handler.setFormatter(log_formatter) - handler.setLevel(logging.INFO) + # Apped the logs and overwrite once reached 5MB + handler = RotatingFileHandler( + log_file_path, mode='a', maxBytes=5 * 1024 * 1024, backupCount=2, encoding=None, delay=0) + handler.setFormatter(log_formatter) + handler.setLevel(logging.INFO) - root_logger = logging.getLogger() - root_logger.setLevel(logging.INFO) - root_logger.addHandler(handler) + root_logger = logging.getLogger() + root_logger.setLevel(logging.INFO) + root_logger.addHandler(handler) def read_config(): - """ - Read the configuration from the config directory. - If does not exist or outdated by major version, copy the system config and - startup script to user directory. - If the user config is outdated by minor version, update the config by the new values. - """ - logging.info('Reading the configuration file') + """ + Read the configuration from the config directory. + If does not exist or outdated by major version, copy the system config and + startup script to user directory. + If the user config is outdated by minor version, update the config by the new values. + """ + logging.info('Reading the configuration file') - if not os.path.isfile(config_file_path): - logging.info('Safe Eyes configuration file not found') - __initialize_safeeyes() + if not os.path.isfile(config_file_path): + logging.info('Safe Eyes configuration file not found') + __initialize_safeeyes() - # Read the configurations - with open(config_file_path) as config_file: - user_config = json.load(config_file) + # Read the configurations + with open(config_file_path) as config_file: + user_config = json.load(config_file) - with open(system_config_file_path) as config_file: - system_config = json.load(config_file) + with open(system_config_file_path) as config_file: + system_config = json.load(config_file) - user_config_version = str(user_config['meta']['config_version']) - system_config_version = str(system_config['meta']['config_version']) + user_config_version = str(user_config['meta']['config_version']) + system_config_version = str(system_config['meta']['config_version']) - if LooseVersion(user_config_version) < LooseVersion(system_config_version): - # Outdated user config - logging.info('Update the old config version {} with new config version {}'.format(user_config_version, system_config_version)) - user_config_major_version = user_config_version.split('.')[0] - system_config_major_version = system_config_version.split('.')[0] + if LooseVersion(user_config_version) < LooseVersion(system_config_version): + # Outdated user config + logging.info('Update the old config version {} with new config version {}'.format( + user_config_version, system_config_version)) + user_config_major_version = user_config_version.split('.')[0] + system_config_major_version = system_config_version.split('.')[0] - if LooseVersion(user_config_major_version) < LooseVersion(system_config_major_version): - # Major version change - __initialize_safeeyes() - # Update the user_config - user_config = system_config - else: - # Minor version change - new_config = system_config.copy() - new_config.update(user_config) - # Update the version - new_config['meta']['config_version'] = system_config_version + if LooseVersion(user_config_major_version) < LooseVersion(system_config_major_version): + # Major version change + __initialize_safeeyes() + # Update the user_config + user_config = system_config + else: + # Minor version change + new_config = system_config.copy() + new_config.update(user_config) + # Update the version + new_config['meta']['config_version'] = system_config_version - # Write the configuration to file - with open(config_file_path, 'w') as config_file: - json.dump(new_config, config_file, indent=4, sort_keys=True) + # Write the configuration to file + with open(config_file_path, 'w') as config_file: + json.dump(new_config, config_file, indent=4, sort_keys=True) - # Update the user_config - user_config = new_config + # Update the user_config + user_config = new_config - return user_config + return user_config class __HTMLTextExtractor(HTMLParser): - """ - Helper class to convert HTML to text - """ - def __init__(self): - self.reset() - self.strict = False - self.convert_charrefs= True - self.fed = [] + """ + Helper class to convert HTML to text + """ - def handle_data(self, d): - self.fed.append(d) + def __init__(self): + self.reset() + self.strict = False + self.convert_charrefs = True + self.fed = [] - def get_data(self): - return ''.join(self.fed) + def handle_data(self, d): + self.fed.append(d) + + def get_data(self): + return ''.join(self.fed) diff --git a/safeeyes/config/lang/cs.json b/safeeyes/config/lang/cs.json index c38d266..931daaa 100644 --- a/safeeyes/config/lang/cs.json +++ b/safeeyes/config/lang/cs.json @@ -43,6 +43,8 @@ "no_of_short_breaks_between_two_long_breaks": "Počet krátkých přestávek mezi dvěma dlouhými", "postpone": "Odložit", "postpone_duration": "O kolik odložit (v minutách)", + "pyaudio_not_installed": "Nelze zapnout zvuková upozornění", + "pyaudio_explanation": "Nejdříve musíte nainstalovat pyaudio", "quit": "Ukončit", "save": "Uložit", "settings": "Nastavení", diff --git a/safeeyes/config/lang/en.json b/safeeyes/config/lang/en.json index c53b3e1..2ec82a8 100644 --- a/safeeyes/config/lang/en.json +++ b/safeeyes/config/lang/en.json @@ -43,6 +43,8 @@ "no_of_short_breaks_between_two_long_breaks": "Number of short breaks between two long breaks", "postpone": "Postpone", "postpone_duration": "Postpone duration (in minutes)", + "pyaudio_not_installed": "Cannot enable audible notifications", + "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Quit", "save": "Save", "settings": "Settings", diff --git a/safeeyes/config/lang/es.json b/safeeyes/config/lang/es.json index 25426bc..e1db18a 100644 --- a/safeeyes/config/lang/es.json +++ b/safeeyes/config/lang/es.json @@ -43,6 +43,8 @@ "no_of_short_breaks_between_two_long_breaks": "Número de pausas cortas entre dos pausas largas", "postpone": "Posponer", "postpone_duration": "Duración de cada posposición (en minutos)", + "pyaudio_not_installed": "Cannot enable audible notifications", + "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Salir", "save": "Guardar", "settings": "Preferencias", diff --git a/safeeyes/config/lang/fr.json b/safeeyes/config/lang/fr.json index dea77ae..924e2fe 100644 --- a/safeeyes/config/lang/fr.json +++ b/safeeyes/config/lang/fr.json @@ -43,6 +43,8 @@ "no_of_short_breaks_between_two_long_breaks": "Nombre de pauses courtes entre deux pauses longues", "postpone": "Reporter", "postpone_duration": "Durée de report (en minutes)", + "pyaudio_not_installed": "Cannot enable audible notifications", + "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Quitter", "save": "Enregistrer", "settings": "Paramètres", diff --git a/safeeyes/config/lang/ge.json b/safeeyes/config/lang/ge.json index 3506ec4..53cf55d 100644 --- a/safeeyes/config/lang/ge.json +++ b/safeeyes/config/lang/ge.json @@ -43,6 +43,8 @@ "no_of_short_breaks_between_two_long_breaks": "მცირე შესვენებების რაოდენობა ორ დიდ შესვენებას შორის", "postpone": "Postpone", "postpone_duration": "Postpone duration (in minutes)", + "pyaudio_not_installed": "Cannot enable audible notifications", + "pyaudio_explanation": "To enable them, install pyaudio", "quit": "გასვლა", "save": "დამახსოვრება", "settings": "პარამეტრები", diff --git a/safeeyes/config/lang/hi.json b/safeeyes/config/lang/hi.json index 8bc82a3..2218cba 100644 --- a/safeeyes/config/lang/hi.json +++ b/safeeyes/config/lang/hi.json @@ -43,6 +43,8 @@ "no_of_short_breaks_between_two_long_breaks": "दो बड़े आराम के बीच कितने छोटे आराम", "postpone": "Postpone", "postpone_duration": "Postpone duration (in minutes)", + "pyaudio_not_installed": "Cannot enable audible notifications", + "pyaudio_explanation": "To enable them, install pyaudio", "quit": "बंद", "save": "रखें", "settings": "सेटिंग्स", diff --git a/safeeyes/config/lang/hu.json b/safeeyes/config/lang/hu.json index 28407bb..6e6fb63 100644 --- a/safeeyes/config/lang/hu.json +++ b/safeeyes/config/lang/hu.json @@ -43,6 +43,8 @@ "no_of_short_breaks_between_two_long_breaks": "Hány rövid szünet legyen a hosszabbak között?", "postpone": "Postpone", "postpone_duration": "Postpone duration (in minutes)", + "pyaudio_not_installed": "Cannot enable audible notifications", + "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Kilépés", "save": "Mentés", "settings": "Beállítások", diff --git a/safeeyes/config/lang/id.json b/safeeyes/config/lang/id.json index 11bf9e2..4a51c07 100644 --- a/safeeyes/config/lang/id.json +++ b/safeeyes/config/lang/id.json @@ -43,6 +43,8 @@ "no_of_short_breaks_between_two_long_breaks": "Jumlah istirahat singkat di antara dua istirahat panjang", "postpone": "Postpone", "postpone_duration": "Postpone duration (in minutes)", + "pyaudio_not_installed": "Cannot enable audible notifications", + "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Keluar", "save": "Simpan", "settings": "Pengaturan", diff --git a/safeeyes/config/lang/mk.json b/safeeyes/config/lang/mk.json index 82702ec..1fd701e 100644 --- a/safeeyes/config/lang/mk.json +++ b/safeeyes/config/lang/mk.json @@ -43,6 +43,8 @@ "no_of_short_breaks_between_two_long_breaks": "Број на кратки паузи помеѓу две долги", "postpone": "Одложи", "postpone_duration": "Траење на одложувањето (Во секунди)", + "pyaudio_not_installed": "Cannot enable audible notifications", + "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Исклучи", "save": "Зачувај", "settings": "Подесувања", diff --git a/safeeyes/config/lang/pl.json b/safeeyes/config/lang/pl.json index 0667dcb..1518109 100644 --- a/safeeyes/config/lang/pl.json +++ b/safeeyes/config/lang/pl.json @@ -43,6 +43,8 @@ "no_of_short_breaks_between_two_long_breaks": "Liczba krótkich przerw między długimi przerwami", "postpone": "Odrocz", "postpone_duration": "Odroczenie przerwy (w minutach)", + "pyaudio_not_installed": "Cannot enable audible notifications", + "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Wyjdź", "save": "Zapisz", "settings": "Ustawienia", diff --git a/safeeyes/config/lang/pt.json b/safeeyes/config/lang/pt.json index c502644..7b38748 100644 --- a/safeeyes/config/lang/pt.json +++ b/safeeyes/config/lang/pt.json @@ -43,6 +43,8 @@ "no_of_short_breaks_between_two_long_breaks": "Número de pausas curtas entre duas pausas longas", "postpone": "Adiar", "postpone_duration": "Duração do adiamento (em minutos)", + "pyaudio_not_installed": "Cannot enable audible notifications", + "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Sair", "save": "Salvar", "settings": "Configuração", diff --git a/safeeyes/config/lang/ru.json b/safeeyes/config/lang/ru.json index 33b1aee..7f6da0d 100644 --- a/safeeyes/config/lang/ru.json +++ b/safeeyes/config/lang/ru.json @@ -43,6 +43,8 @@ "no_of_short_breaks_between_two_long_breaks": "Количество коротких перерывов между двумя длинными", "postpone": "Отложить", "postpone_duration": "Отложить на время (в минутах)", + "pyaudio_not_installed": "Cannot enable audible notifications", + "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Выйти", "save": "Сохранить", "settings": "Настройки", diff --git a/safeeyes/config/lang/sk.json b/safeeyes/config/lang/sk.json index 2304027..24148f1 100644 --- a/safeeyes/config/lang/sk.json +++ b/safeeyes/config/lang/sk.json @@ -43,6 +43,8 @@ "no_of_short_breaks_between_two_long_breaks": "Počet krátkych prestávok medzi dvomi dlhými prestávkami", "postpone": "Postpone", "postpone_duration": "Postpone duration (in minutes)", + "pyaudio_not_installed": "Cannot enable audible notifications", + "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Koniec", "save": "Uložiť", "settings": "Nastavenia", diff --git a/safeeyes/config/lang/ta.json b/safeeyes/config/lang/ta.json index 527cb5c..e56fa3e 100644 --- a/safeeyes/config/lang/ta.json +++ b/safeeyes/config/lang/ta.json @@ -43,6 +43,8 @@ "no_of_short_breaks_between_two_long_breaks": "இரண்டு நீண்ட இடைவேளைகளுக்கிடையிலான குறுகிய இடைவேளைகள்", "postpone": "ஒத்தி வை", "postpone_duration": "இடைவேளையை ஒத்தி வைக்கும் காலம் (நிமிடங்களில்)", + "pyaudio_not_installed": "Cannot enable audible notifications", + "pyaudio_explanation": "To enable them, install pyaudio", "quit": "நிறுத்து", "save": "சேமி", "settings": "அமைப்பு", diff --git a/safeeyes/config/lang/tr.json b/safeeyes/config/lang/tr.json index ecb803d..8a503b5 100644 --- a/safeeyes/config/lang/tr.json +++ b/safeeyes/config/lang/tr.json @@ -43,6 +43,8 @@ "no_of_short_breaks_between_two_long_breaks": "İki uzun mola arasındaki kısa mola sayısı", "postpone": "Ertele", "postpone_duration": "Ertelme süresi (dakika)", + "pyaudio_not_installed": "Cannot enable audible notifications", + "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Çıkış", "save": "Kaydet", "settings": "Ayarlar", diff --git a/safeeyes/config/lang/vi.json b/safeeyes/config/lang/vi.json index aa67e3c..92f1436 100644 --- a/safeeyes/config/lang/vi.json +++ b/safeeyes/config/lang/vi.json @@ -48,6 +48,8 @@ "no_of_short_breaks_between_two_long_breaks": "Số lần nghỉ ngơi ngắn giữa hai lần nghỉ ngơi dài", "postpone": "Tạm hoãn", "postpone_duration": "Thời gian tạm hoãn (tính bằng phút)", + "pyaudio_not_installed": "Cannot enable audible notifications", + "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Thoát", "save": "Lưu", "settings": "Cài đặt", diff --git a/setup.py b/setup.py index ce30fdd..1e237b0 100644 --- a/setup.py +++ b/setup.py @@ -4,10 +4,10 @@ import setuptools requires = [ - 'python-xlib', - 'pyaudio', - 'psutil', - 'babel'] + 'python-xlib', + 'pyaudio', + 'psutil', + 'babel'] here = os.path.abspath(os.path.dirname(__file__)) @@ -15,6 +15,7 @@ here = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(here, 'README.md')) as f: long_description = '\n' + f.read() + def _data_files(path): for root, dirs, files in os.walk(path): if not files: @@ -37,18 +38,30 @@ setuptools.setup( 'glade/*.glade', 'resource/*']}, data_files=[('/usr/share/applications', ['share/applications/safeeyes.desktop']), - ('/usr/share/icons/hicolor/16x16/apps', ['share/icons/hicolor/16x16/apps/safeeyes.png']), - ('/usr/share/icons/hicolor/24x24/apps', ['share/icons/hicolor/24x24/apps/safeeyes.png']), - ('/usr/share/icons/hicolor/48x48/apps', ['share/icons/hicolor/48x48/apps/safeeyes.png']), - ('/usr/share/icons/hicolor/32x32/apps', ['share/icons/hicolor/32x32/apps/safeeyes.png']), - ('/usr/share/icons/hicolor/64x64/apps', ['share/icons/hicolor/64x64/apps/safeeyes.png']), - ('/usr/share/icons/hicolor/128x128/apps', ['share/icons/hicolor/128x128/apps/safeeyes.png']), - ('/usr/share/icons/hicolor/48x48/status', ['share/icons/hicolor/48x48/status/safeeyes_enabled.png', 'share/icons/hicolor/48x48/status/safeeyes_disabled.png']), - ('/usr/share/icons/hicolor/32x32/status', ['share/icons/hicolor/32x32/status/safeeyes_enabled.png', 'share/icons/hicolor/32x32/status/safeeyes_disabled.png']), - ('/usr/share/icons/hicolor/24x24/status', ['share/icons/hicolor/24x24/status/safeeyes_enabled.png', 'share/icons/hicolor/24x24/status/safeeyes_disabled.png', 'share/icons/hicolor/24x24/status/safeeyes_timer.png']), - ('/usr/share/icons/hicolor/16x16/status', ['share/icons/hicolor/16x16/status/safeeyes_enabled.png', 'share/icons/hicolor/16x16/status/safeeyes_disabled.png', 'share/icons/hicolor/16x16/status/safeeyes_timer.png']) + ('/usr/share/icons/hicolor/16x16/apps', + ['share/icons/hicolor/16x16/apps/safeeyes.png']), + ('/usr/share/icons/hicolor/24x24/apps', + ['share/icons/hicolor/24x24/apps/safeeyes.png']), + ('/usr/share/icons/hicolor/48x48/apps', + ['share/icons/hicolor/48x48/apps/safeeyes.png']), + ('/usr/share/icons/hicolor/32x32/apps', + ['share/icons/hicolor/32x32/apps/safeeyes.png']), + ('/usr/share/icons/hicolor/64x64/apps', + ['share/icons/hicolor/64x64/apps/safeeyes.png']), + ('/usr/share/icons/hicolor/128x128/apps', + ['share/icons/hicolor/128x128/apps/safeeyes.png']), + ('/usr/share/icons/hicolor/48x48/status', + ['share/icons/hicolor/48x48/status/safeeyes_enabled.png', 'share/icons/hicolor/48x48/status/safeeyes_disabled.png']), + ('/usr/share/icons/hicolor/32x32/status', + ['share/icons/hicolor/32x32/status/safeeyes_enabled.png', 'share/icons/hicolor/32x32/status/safeeyes_disabled.png']), + ('/usr/share/icons/hicolor/24x24/status', ['share/icons/hicolor/24x24/status/safeeyes_enabled.png', + 'share/icons/hicolor/24x24/status/safeeyes_disabled.png', 'share/icons/hicolor/24x24/status/safeeyes_timer.png']), + ('/usr/share/icons/hicolor/16x16/status', ['share/icons/hicolor/16x16/status/safeeyes_enabled.png', + 'share/icons/hicolor/16x16/status/safeeyes_disabled.png', 'share/icons/hicolor/16x16/status/safeeyes_timer.png']) ], install_requires=requires, + extras_require={ + 'audio': ['pyaudio']}, entry_points={'console_scripts': ['safeeyes = safeeyes.__main__:main']}, keywords='linux utility health eye-strain safe-eyes', classifiers=[ From 883e05954d9a96130e42f9bbd1dc81b479d63dec Mon Sep 17 00:00:00 2001 From: p-bo Date: Thu, 17 Aug 2017 19:51:00 +0200 Subject: [PATCH 2/4] Add files via upload --- safeeyes/config/lang/cs.json | 56 +++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/safeeyes/config/lang/cs.json b/safeeyes/config/lang/cs.json index 931daaa..ac3481c 100644 --- a/safeeyes/config/lang/cs.json +++ b/safeeyes/config/lang/cs.json @@ -4,57 +4,59 @@ "language_name_en": "Czech" }, "app_info": { - "description": "Safe Eyes protects your eyes from eye strain (asthenopia) by reminding you to take breaks while you're working long hours at the computer." + "description": "Safe Eyes chrání vaše oči před následky přetěžování (asthenopie) když dlouho hledíte do obrazovky počítače a to připomínáním potřebných přestávek." }, "exercises": { "short_break_close_eyes": "Zavřete oči", - "short_break_roll_eyes": "Kroužete očima", - "short_break_rotate_clockwise": "Kroužete očima ve směru hodinových ručiček", - "short_break_rotate_counter_clockwise": "Kroužete očima proti směru hodinových ručiček", - "short_break_blink": "Mrkejte", - "short_break_focus_far_distance": "Soustřeďte se na bod v dálce", - "short_break_drink_water": "Dejte si nějakou vodu", + "short_break_roll_eyes": "Zakroužete očima (několikrát na každou stranu)", + "short_break_rotate_clockwise": "Zakroužete očima ve směru hodinových ručiček", + "short_break_rotate_counter_clockwise": "Zakroužete očima proti směru hodinových ručiček", + "short_break_blink": "Zamrkejte", + "short_break_focus_far_distance": "Zaostřete pohled na nějaký vzdálený objekt", + "short_break_drink_water": "Napijte se vody", "long_break_walk": "Na chvíli se projděte", - "long_break_lean_back": "Opřete se do židle a relaxujte" + "long_break_lean_back": "Opřete se zády do židle a uvolněte se" }, "messages": { - "ready_for_a_break": "Připravte se na přestávku za {} sekund", + "audible_alert_disabled": "Nedaří se zapnout zvuková oznamování", + "ready_for_a_short_break": "Připravte se na krátkou přestávku za {} sekund", + "ready_for_a_long_break": "Připravte se na dlouhou přestávku za {} sekund", "disabled_until_restart": "Pozastaveno do restartu", - "disabled_until_x": "Pozastaveno na {}", - "next_break_at": "Příští přestávka v {}" + "disabled_until_x": "Pozastaveno do {}", + "next_break_at": "Příští přestávka v {}", + "software_required": "Tato funkce vyžaduje instalaci {}" }, "ui_controls": { "about": "O aplikaci", - "allow_postpone": "Allow postponing the breaks", - "audible_alert": "Zvukové upozornění na konec přestávky", - "cancel": "Zrušit", - "close": "Close", + "allow_postpone": "Umožňit odkládání přestávek", + "audible_alert": "Zvukové upozornění na konci přestávky", + "cancel": "Storno", + "close": "Zavřít", "disable": "Pozastavit Safe Eyes", - "enable": "Zapnout Safe Eyes", - "enable_screen_lock": "Po každé dlouhé přestávce uzamknout obrazovku", + "disable_keyboard_shortcut": "Ochranná doba po kterou vypnout klávesovou zkratku aby nedošlo k neúmyslenému přeskočení (v sekundách)", + "enable": "Spustit Safe Eyes", + "enable_screen_lock": "Po uplynutí každé velké přestávky ponechat obrazovku uzamčenou", "for_x_hour": "Na {} hodinu", "for_x_hours": "Na {} hodiny", "for_x_minutes": "Na {} minut", - "idle_time": "Pozastavit při nečinnosti delší než (minut)", - "interval_between_two_breaks": "Interval mezi dvěma přestávkami", + "idle_time": "Pozastavit časovač při nečinnosti uživatele delší než (minut)", + "interval_between_two_breaks": "Interval mezi dvěma po sobě jdoucími přestávkami", "language": "Jazyk", - "license": "License", + "license": "Licence", "long_break_duration": "Trvání dlouhé přestávky (v sekundách)", "no_of_short_breaks_between_two_long_breaks": "Počet krátkých přestávek mezi dvěma dlouhými", "postpone": "Odložit", "postpone_duration": "O kolik odložit (v minutách)", - "pyaudio_not_installed": "Nelze zapnout zvuková upozornění", - "pyaudio_explanation": "Nejdříve musíte nainstalovat pyaudio", "quit": "Ukončit", "save": "Uložit", "settings": "Nastavení", "short_break_duration": "Trvání krátké přestávky (v sekundách)", - "show_time_in_tray": "Show the next break time in system tray", + "show_time_in_tray": "Zobrazovat v oznamovací oblasti systémového panelu kdy nastane příští přestávka", "skip": "Přeskočit", "strict_break": "Povinná přestávka (skrýt tlačítko pro přeskočení)", - "system_language": "Systémový jazyk", - "time_to_prepare_for_break": "Čas k přípravě na přestávku (v sekundách)", - "time_to_screen_lock": "O kolik nejvýše přeskočit, obcházející zámek obrazovky (v sekundách)", - "until_restart": "Do restartu" + "system_language": "Jazyk systému", + "time_to_prepare_for_break": "Jakou dobu dopředu hlásit blížící se přestávku (v sekundách)", + "time_to_screen_lock": "Časový limit pro přeskočení přestávky a tedy obejití zámku obrazovky (v sekundách)", + "until_restart": "Do restartu počítače" } } From 570efc20fd15ca9cc11f9829682174fc27295d19 Mon Sep 17 00:00:00 2001 From: Radek SPRTA Date: Fri, 25 Aug 2017 22:12:25 +0200 Subject: [PATCH 3/4] Edit translations --- safeeyes/config/lang/cs.json | 10 +++++----- safeeyes/config/lang/sk.json | 30 +++++++++++++++++------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/safeeyes/config/lang/cs.json b/safeeyes/config/lang/cs.json index ac3481c..d827224 100644 --- a/safeeyes/config/lang/cs.json +++ b/safeeyes/config/lang/cs.json @@ -4,7 +4,7 @@ "language_name_en": "Czech" }, "app_info": { - "description": "Safe Eyes chrání vaše oči před následky přetěžování (asthenopie) když dlouho hledíte do obrazovky počítače a to připomínáním potřebných přestávek." + "description": "Safe Eyes chrání vaše oči před následky přetěžování (asthenopie), když dlouho hledíte do obrazovky počítače, připomínáním potřebných přestávek." }, "exercises": { "short_break_close_eyes": "Zavřete oči", @@ -28,18 +28,18 @@ }, "ui_controls": { "about": "O aplikaci", - "allow_postpone": "Umožňit odkládání přestávek", + "allow_postpone": "Umožnit odkládání přestávek", "audible_alert": "Zvukové upozornění na konci přestávky", "cancel": "Storno", "close": "Zavřít", "disable": "Pozastavit Safe Eyes", - "disable_keyboard_shortcut": "Ochranná doba po kterou vypnout klávesovou zkratku aby nedošlo k neúmyslenému přeskočení (v sekundách)", + "disable_keyboard_shortcut": "Délka (s) vypnutí klávesové zkratky (prevence neúmyslného přeskočení)", "enable": "Spustit Safe Eyes", "enable_screen_lock": "Po uplynutí každé velké přestávky ponechat obrazovku uzamčenou", "for_x_hour": "Na {} hodinu", "for_x_hours": "Na {} hodiny", "for_x_minutes": "Na {} minut", - "idle_time": "Pozastavit časovač při nečinnosti uživatele delší než (minut)", + "idle_time": "Pozastavit časovač při nečinnosti delší než (minut)", "interval_between_two_breaks": "Interval mezi dvěma po sobě jdoucími přestávkami", "language": "Jazyk", "license": "Licence", @@ -51,7 +51,7 @@ "save": "Uložit", "settings": "Nastavení", "short_break_duration": "Trvání krátké přestávky (v sekundách)", - "show_time_in_tray": "Zobrazovat v oznamovací oblasti systémového panelu kdy nastane příští přestávka", + "show_time_in_tray": "Zobrazovat čas příští přestávky v oznamovací oblasti", "skip": "Přeskočit", "strict_break": "Povinná přestávka (skrýt tlačítko pro přeskočení)", "system_language": "Jazyk systému", diff --git a/safeeyes/config/lang/sk.json b/safeeyes/config/lang/sk.json index 24148f1..22abb01 100644 --- a/safeeyes/config/lang/sk.json +++ b/safeeyes/config/lang/sk.json @@ -4,7 +4,7 @@ "language_name_en": "Slovak" }, "app_info": { - "description": "Safe Eyes protects your eyes from eye strain (asthenopia) by reminding you to take breaks while you're working long hours at the computer." + "description": "Safe Eyes vám pripomína robiť si prestávky, keď trávite dlhé hodiny u počítača a tak chráni vaše oči pred přílišným namáhaním (asthenopií)." }, "exercises": { "short_break_close_eyes": "Pevne zavri oči", @@ -18,43 +18,47 @@ "long_break_lean_back": "Opri sa o kreslo a relaxuj" }, "messages": { - "ready_for_a_break": "Priprav sa na prestávku o {} sekúnd", + "audible_alert_disabled": "Nieje možné zapnúť zvukové upozornenie", + "ready_for_a_short_break": "Priprav sa na prestávku o {} sekúnd", + "ready_for_a_long_break": "Priprav sa na prestávku o {} sekúnd", "disabled_until_restart": "Zakázať do reštartu", "disabled_until_x": "Zakázať do {}", - "next_break_at": "Ďalšia prestávka o {}" + "next_break_at": "Ďalšia prestávka o {}", + "software_required": "Pro ích povolenie nainštalujte {}" }, "ui_controls": { "about": "Ohľadom", - "allow_postpone": "Allow postponing the breaks", + "allow_postpone": "Povoliť odkladanie prestávok", "audible_alert": "Zvukový signál na konci prestávky", "cancel": "Zrušiť", "close": "Close", "disable": "Zakázať Safe Eyes", + "disable_keyboard_shortcut": "Dlžka po kterú zakázať klávesovú skratku v sekundách.", "enable": "Povoliť Safe Eyes", - "enable_screen_lock": "Lock the screen after every long break", + "enable_screen_lock": "Zablokovať obrazovku po každej dlhej prestávke", "for_x_hour": "Počas {} hodiny", "for_x_hours": "Počas {} hodín", "for_x_minutes": "Počas {} minút", "idle_time": "Pozastaviť pri nečinnosti dlhšej ako (v minútach)", "interval_between_two_breaks": "Interval medzi dvomi prestávkami", "language": "Jazyk", - "license": "License", + "license": "Licencie", "long_break_duration": "Trvanie dlhej prestávky (v sekundách)", "no_of_short_breaks_between_two_long_breaks": "Počet krátkych prestávok medzi dvomi dlhými prestávkami", - "postpone": "Postpone", - "postpone_duration": "Postpone duration (in minutes)", - "pyaudio_not_installed": "Cannot enable audible notifications", - "pyaudio_explanation": "To enable them, install pyaudio", + "postpone": "Odložiť", + "postpone_duration": "O koĺko odložiť (minút)", + "pyaudio_not_installed": "Nieje možné zapnúť zvukové upozornenia", + "pyaudio_explanation": "Ak ich chcete povoliť, nainštalujte pyaudio", "quit": "Koniec", "save": "Uložiť", "settings": "Nastavenia", "short_break_duration": "Trvanie krátkej prestávky (v sekundách)", - "show_time_in_tray": "Show the next break time in system tray", + "show_time_in_tray": "Zobrazit čas následujúcej prestávky v system tray", "skip": "Preskočiť", "strict_break": "Povinná prestávka (Skryje tlačitko Preskočiť)", - "system_language": "System Language", + "system_language": "Jazyk systému", "time_to_prepare_for_break": "Čas na prípravu na prestávku (v sekundách)", - "time_to_screen_lock": "Maximum time to skip, bypassing the lock screen (in seconds)", + "time_to_screen_lock": "O koľko sekúnd najviac preskočiť (obchádza zámok obrazovky)", "until_restart": "Do reštartu" } } From a6992d2f2aa90b6dd4fd860bc2ce99d6ef4b27e1 Mon Sep 17 00:00:00 2001 From: Radek SPRTA Date: Fri, 25 Aug 2017 22:21:19 +0200 Subject: [PATCH 4/4] Revert "Make pyaudio optional" This reverts commit cc597cf01ef54fb7c558456b35b5a401e2e6f5d4. --- safeeyes/SettingsDialog.py | 355 ++++++++--------- safeeyes/Utility.py | 714 ++++++++++++++++------------------- safeeyes/config/lang/en.json | 2 - safeeyes/config/lang/es.json | 2 - safeeyes/config/lang/fr.json | 2 - safeeyes/config/lang/ge.json | 2 - safeeyes/config/lang/hi.json | 2 - safeeyes/config/lang/hu.json | 2 - safeeyes/config/lang/id.json | 2 - safeeyes/config/lang/mk.json | 2 - safeeyes/config/lang/pl.json | 2 - safeeyes/config/lang/pt.json | 2 - safeeyes/config/lang/ru.json | 2 - safeeyes/config/lang/sk.json | 2 - safeeyes/config/lang/ta.json | 2 - safeeyes/config/lang/tr.json | 2 - safeeyes/config/lang/vi.json | 2 - setup.py | 41 +- 18 files changed, 489 insertions(+), 651 deletions(-) diff --git a/safeeyes/SettingsDialog.py b/safeeyes/SettingsDialog.py index a60723d..842de04 100644 --- a/safeeyes/SettingsDialog.py +++ b/safeeyes/SettingsDialog.py @@ -21,230 +21,175 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk, Gdk, GdkX11, GObject from safeeyes import Utility - class SettingsDialog: - """ - Create and initialize SettingsDialog instance. - """ + """ + Create and initialize SettingsDialog instance. + """ + def __init__(self, config, language, languages, able_to_lock_screen, on_save_settings, glade_file): + self.config = config + self.on_save_settings = on_save_settings + self.languages = [] - def __init__(self, config, language, languages, able_to_lock_screen, on_save_settings, glade_file): - self.config = config - self.on_save_settings = on_save_settings - self.language = language - self.languages = [] + builder = Gtk.Builder() + builder.add_from_file(glade_file) + builder.connect_signals(self) - builder = Gtk.Builder() - builder.add_from_file(glade_file) - builder.connect_signals(self) + # Get the UI components + self.window = builder.get_object('window_settings') + self.spin_short_break_duration = builder.get_object('spin_short_break_duration') + self.spin_long_break_duration = builder.get_object('spin_long_break_duration') + self.spin_interval_between_two_breaks = builder.get_object('spin_interval_between_two_breaks') + self.spin_short_between_long = builder.get_object('spin_short_between_long') + self.spin_time_to_prepare = builder.get_object('spin_time_to_prepare') + self.spin_idle_time_to_pause = builder.get_object('spin_idle_time_to_pause') + self.spin_postpone_duration = builder.get_object('spin_postpone_duration') + self.switch_show_time_in_tray = builder.get_object('switch_show_time_in_tray') + self.switch_strict_break = builder.get_object('switch_strict_break') + self.switch_postpone = builder.get_object('switch_postpone') + self.switch_audible_alert = builder.get_object('switch_audible_alert') + self.cmb_language = builder.get_object('cmb_language') + self.switch_screen_lock = builder.get_object('switch_screen_lock') + self.spin_time_to_screen_lock = builder.get_object('spin_time_to_screen_lock') - # Get the UI components - self.window = builder.get_object('window_settings') - self.spin_short_break_duration = builder.get_object( - 'spin_short_break_duration') - self.spin_long_break_duration = builder.get_object( - 'spin_long_break_duration') - self.spin_interval_between_two_breaks = builder.get_object( - 'spin_interval_between_two_breaks') - self.spin_short_between_long = builder.get_object( - 'spin_short_between_long') - self.spin_time_to_prepare = builder.get_object('spin_time_to_prepare') - self.spin_idle_time_to_pause = builder.get_object( - 'spin_idle_time_to_pause') - self.spin_postpone_duration = builder.get_object( - 'spin_postpone_duration') - self.switch_show_time_in_tray = builder.get_object( - 'switch_show_time_in_tray') - self.switch_strict_break = builder.get_object('switch_strict_break') - self.switch_postpone = builder.get_object('switch_postpone') - self.switch_audible_alert = builder.get_object('switch_audible_alert') - self.cmb_language = builder.get_object('cmb_language') - self.switch_screen_lock = builder.get_object('switch_screen_lock') - self.spin_time_to_screen_lock = builder.get_object( - 'spin_time_to_screen_lock') + # Translate the UI labels + builder.get_object('lbl_short_break').set_label(language['ui_controls']['short_break_duration']) + builder.get_object('lbl_long_break').set_label(language['ui_controls']['long_break_duration']) + builder.get_object('lbl_interval_bettween_breaks').set_label(language['ui_controls']['interval_between_two_breaks']) + builder.get_object('lbl_short_per_long').set_label(language['ui_controls']['no_of_short_breaks_between_two_long_breaks']) + builder.get_object('lbl_time_to_prepare').set_label(language['ui_controls']['time_to_prepare_for_break']) + builder.get_object('lbl_idle_time_to_pause').set_label(language['ui_controls']['idle_time']) + builder.get_object('lbl_postpone_duration').set_label(language['ui_controls']['postpone_duration']) + builder.get_object('lbl_allow_postpone').set_label(language['ui_controls']['allow_postpone']) + builder.get_object('lbl_show_time_in_tray').set_label(language['ui_controls']['show_time_in_tray']) + builder.get_object('lbl_strict_break').set_label(language['ui_controls']['strict_break']) + builder.get_object('lbl_audible_alert').set_label(language['ui_controls']['audible_alert']) + builder.get_object('lbl_language').set_label(language['ui_controls']['language']) + builder.get_object('lbl_enable_screen_lock').set_label(language['ui_controls']['enable_screen_lock']) + builder.get_object('lbl_lock_screen_after').set_label(language['ui_controls']['time_to_screen_lock']) + builder.get_object('btn_cancel').set_label(language['ui_controls']['cancel']) + builder.get_object('btn_save').set_label(language['ui_controls']['save']) - # Translate the UI labels - builder.get_object('lbl_short_break').set_label( - language['ui_controls']['short_break_duration']) - builder.get_object('lbl_long_break').set_label( - language['ui_controls']['long_break_duration']) - builder.get_object('lbl_interval_bettween_breaks').set_label( - language['ui_controls']['interval_between_two_breaks']) - builder.get_object('lbl_short_per_long').set_label( - language['ui_controls']['no_of_short_breaks_between_two_long_breaks']) - builder.get_object('lbl_time_to_prepare').set_label( - language['ui_controls']['time_to_prepare_for_break']) - builder.get_object('lbl_idle_time_to_pause').set_label( - language['ui_controls']['idle_time']) - builder.get_object('lbl_postpone_duration').set_label( - language['ui_controls']['postpone_duration']) - builder.get_object('lbl_allow_postpone').set_label( - language['ui_controls']['allow_postpone']) - builder.get_object('lbl_show_time_in_tray').set_label( - language['ui_controls']['show_time_in_tray']) - builder.get_object('lbl_strict_break').set_label( - language['ui_controls']['strict_break']) - builder.get_object('lbl_audible_alert').set_label( - language['ui_controls']['audible_alert']) - builder.get_object('lbl_language').set_label( - language['ui_controls']['language']) - builder.get_object('lbl_enable_screen_lock').set_label( - language['ui_controls']['enable_screen_lock']) - builder.get_object('lbl_lock_screen_after').set_label( - language['ui_controls']['time_to_screen_lock']) - builder.get_object('btn_cancel').set_label( - language['ui_controls']['cancel']) - builder.get_object('btn_save').set_label( - language['ui_controls']['save']) + # Set the current values of input fields + self.spin_short_break_duration.set_value(config['short_break_duration']) + self.spin_long_break_duration.set_value(config['long_break_duration']) + self.spin_interval_between_two_breaks.set_value(config['break_interval']) + self.spin_short_between_long.set_value(config['no_of_short_breaks_per_long_break']) + self.spin_time_to_prepare.set_value(config['pre_break_warning_time']) + self.spin_idle_time_to_pause.set_value(config['idle_time']) + self.spin_postpone_duration.set_value(config['postpone_duration']) + self.switch_show_time_in_tray.set_active(config['show_time_in_tray']) + self.switch_strict_break.set_active(config['strict_break']) + self.switch_audible_alert.set_active(config['audible_alert']) + self.spin_time_to_screen_lock.set_value(config['time_to_screen_lock']) - # Set the current values of input fields - self.spin_short_break_duration.set_value( - config['short_break_duration']) - self.spin_long_break_duration.set_value(config['long_break_duration']) - self.spin_interval_between_two_breaks.set_value( - config['break_interval']) - self.spin_short_between_long.set_value( - config['no_of_short_breaks_per_long_break']) - self.spin_time_to_prepare.set_value(config['pre_break_warning_time']) - self.spin_idle_time_to_pause.set_value(config['idle_time']) - self.spin_postpone_duration.set_value(config['postpone_duration']) - self.switch_show_time_in_tray.set_active(config['show_time_in_tray']) - self.switch_strict_break.set_active(config['strict_break']) - self.switch_audible_alert.set_active(config['audible_alert']) - self.spin_time_to_screen_lock.set_value(config['time_to_screen_lock']) + # Enable idle_time_to_pause only if xprintidle is available + self.spin_idle_time_to_pause.set_sensitive(Utility.command_exist('xprintidle')) - # Enable idle_time_to_pause only if xprintidle is available - self.spin_idle_time_to_pause.set_sensitive( - Utility.command_exist('xprintidle')) + self.switch_screen_lock.set_sensitive(able_to_lock_screen) + self.switch_screen_lock.set_active(able_to_lock_screen and config['enable_screen_lock']) + self.switch_postpone.set_active(config['allow_postpone'] and not config['strict_break']) - self.switch_screen_lock.set_sensitive(able_to_lock_screen) - self.switch_screen_lock.set_active( - able_to_lock_screen and config['enable_screen_lock']) - self.switch_postpone.set_active( - config['allow_postpone'] and not config['strict_break']) + # Update relative states + # GtkSwitch state-set signal is available only from 3.14 + if Gtk.get_minor_version() >= 14: + self.switch_strict_break.connect('state-set', self.on_switch_strict_break_activate) + self.switch_screen_lock.connect('state-set', self.on_switch_screen_lock_activate) + self.switch_postpone.connect('state-set', self.on_switch_postpone_activate) + self.on_switch_strict_break_activate(self.switch_strict_break, self.switch_strict_break.get_active()) + self.on_switch_screen_lock_activate(self.switch_screen_lock, self.switch_screen_lock.get_active()) + self.on_switch_postpone_activate(self.switch_postpone, self.switch_postpone.get_active()) - # Update relative states - # GtkSwitch state-set signal is available only from 3.14 - if Gtk.get_minor_version() >= 14: - self.switch_strict_break.connect( - 'state-set', self.on_switch_strict_break_activate) - self.switch_screen_lock.connect( - 'state-set', self.on_switch_screen_lock_activate) - self.switch_postpone.connect( - 'state-set', self.on_switch_postpone_activate) - self.on_switch_strict_break_activate( - self.switch_strict_break, self.switch_strict_break.get_active()) - self.on_switch_screen_lock_activate( - self.switch_screen_lock, self.switch_screen_lock.get_active()) - self.on_switch_postpone_activate( - self.switch_postpone, self.switch_postpone.get_active()) + # Initialize the language combobox + language_list_store = Gtk.ListStore(GObject.TYPE_STRING) + language_index = 2 + lang_code = config['language'] - # Initialize the language combobox - language_list_store = Gtk.ListStore(GObject.TYPE_STRING) - language_index = 2 - lang_code = config['language'] + # Add 'System Language' as the first option + language_list_store.append([language['ui_controls']['system_language']]) + language_list_store.append(['-']) + self.languages.append('system') + self.languages.append('system') # Dummy record for row separator + if 'system' == lang_code: + self.cmb_language.set_active(0) - # Add 'System Language' as the first option - language_list_store.append( - [language['ui_controls']['system_language']]) - language_list_store.append(['-']) - self.languages.append('system') - self.languages.append('system') # Dummy record for row separator - if 'system' == lang_code: - self.cmb_language.set_active(0) + for key in sorted(languages.keys()): + language_list_store.append([languages[key]]) + self.languages.append(key) + if key == lang_code: + self.cmb_language.set_active(language_index) + language_index += 1 - for key in sorted(languages.keys()): - language_list_store.append([languages[key]]) - self.languages.append(key) - if key == lang_code: - self.cmb_language.set_active(language_index) - language_index += 1 + self.cmb_language.set_model(language_list_store) + self.cmb_language.set_row_separator_func(lambda m,i: m.get_value(i, 0) == '-') + cell = Gtk.CellRendererText() + self.cmb_language.pack_start(cell, True) + self.cmb_language.add_attribute(cell, 'text', 0) - self.cmb_language.set_model(language_list_store) - self.cmb_language.set_row_separator_func( - lambda m, i: m.get_value(i, 0) == '-') - cell = Gtk.CellRendererText() - self.cmb_language.pack_start(cell, True) - self.cmb_language.add_attribute(cell, 'text', 0) - def show(self): - """ - Show the SettingsDialog. - """ - self.window.show_all() + def show(self): + """ + Show the SettingsDialog. + """ + self.window.show_all() - def on_switch_screen_lock_activate(self, switch, state): - """ - Event handler to the state change of the screen_lock switch. - Enable or disable the self.spin_time_to_screen_lock based on the state of the screen_lock switch. - """ - self.spin_time_to_screen_lock.set_sensitive( - self.switch_screen_lock.get_active()) - def on_switch_strict_break_activate(self, switch, state): - """ - Event handler to the state change of the postpone switch. - Enable or disable the self.spin_postpone_duration based on the state of the postpone switch. - """ - strict_break_enable = state # self.switch_strict_break.get_active() - self.switch_postpone.set_sensitive(not strict_break_enable) - if strict_break_enable: - self.switch_postpone.set_active(False) + def on_switch_screen_lock_activate(self, switch, state): + """ + Event handler to the state change of the screen_lock switch. + Enable or disable the self.spin_time_to_screen_lock based on the state of the screen_lock switch. + """ + self.spin_time_to_screen_lock.set_sensitive(self.switch_screen_lock.get_active()) - def on_switch_postpone_activate(self, switch, state): - """ - Event handler to the state change of the postpone switch. - Enable or disable the self.spin_postpone_duration based on the state of the postpone switch. - """ - self.spin_postpone_duration.set_sensitive( - self.switch_postpone.get_active()) - def on_window_delete(self, *args): - """ - Event handler for Settings dialog close action. - """ - self.window.destroy() + def on_switch_strict_break_activate(self, switch, state): + """ + Event handler to the state change of the postpone switch. + Enable or disable the self.spin_postpone_duration based on the state of the postpone switch. + """ + strict_break_enable = state #self.switch_strict_break.get_active() + self.switch_postpone.set_sensitive(not strict_break_enable) + if strict_break_enable: + self.switch_postpone.set_active(False) - def on_save_clicked(self, button): - """ - Event handler for Save button click. - """ - self.config[ - 'short_break_duration'] = self.spin_short_break_duration.get_value_as_int() - self.config[ - 'long_break_duration'] = self.spin_long_break_duration.get_value_as_int() - self.config[ - 'break_interval'] = self.spin_interval_between_two_breaks.get_value_as_int() - self.config[ - 'no_of_short_breaks_per_long_break'] = self.spin_short_between_long.get_value_as_int() - self.config[ - 'pre_break_warning_time'] = self.spin_time_to_prepare.get_value_as_int() - self.config[ - 'idle_time'] = self.spin_idle_time_to_pause.get_value_as_int() - self.config[ - 'postpone_duration'] = self.spin_postpone_duration.get_value_as_int() - self.config[ - 'show_time_in_tray'] = self.switch_show_time_in_tray.get_active() - self.config['strict_break'] = self.switch_strict_break.get_active() - self.config['language'] = self.languages[ - self.cmb_language.get_active()] - self.config[ - 'time_to_screen_lock'] = self.spin_time_to_screen_lock.get_value_as_int() - self.config['enable_screen_lock'] = self.switch_screen_lock.get_active() - self.config['allow_postpone'] = self.switch_postpone.get_active() + def on_switch_postpone_activate(self, switch, state): + """ + Event handler to the state change of the postpone switch. + Enable or disable the self.spin_postpone_duration based on the state of the postpone switch. + """ + self.spin_postpone_duration.set_sensitive(self.switch_postpone.get_active()) - # Check if pyaudio is installed when turning audible notifications on - if self.switch_audible_alert.get_active() and not Utility.pyaudio_installed(): - # Notify user if pyaudio is not installed - Utility.pyaudio_popup(self, self.language) - else: - self.config[ - 'audible_alert'] = self.switch_audible_alert.get_active() + def on_window_delete(self, *args): + """ + Event handler for Settings dialog close action. + """ + self.window.destroy() - self.on_save_settings(self.config) # Call the provided save method - self.window.destroy() # Close the settings window - def on_cancel_clicked(self, button): - """ - Event handler for Cancel button click. - """ - self.window.destroy() + def on_save_clicked(self, button): + """ + Event handler for Save button click. + """ + self.config['short_break_duration'] = self.spin_short_break_duration.get_value_as_int() + self.config['long_break_duration'] = self.spin_long_break_duration.get_value_as_int() + self.config['break_interval'] = self.spin_interval_between_two_breaks.get_value_as_int() + self.config['no_of_short_breaks_per_long_break'] = self.spin_short_between_long.get_value_as_int() + self.config['pre_break_warning_time'] = self.spin_time_to_prepare.get_value_as_int() + self.config['idle_time'] = self.spin_idle_time_to_pause.get_value_as_int() + self.config['postpone_duration'] = self.spin_postpone_duration.get_value_as_int() + self.config['show_time_in_tray'] = self.switch_show_time_in_tray.get_active() + self.config['strict_break'] = self.switch_strict_break.get_active() + self.config['audible_alert'] = self.switch_audible_alert.get_active() + self.config['language'] = self.languages[self.cmb_language.get_active()] + self.config['time_to_screen_lock'] = self.spin_time_to_screen_lock.get_value_as_int() + self.config['enable_screen_lock'] = self.switch_screen_lock.get_active() + self.config['allow_postpone'] = self.switch_postpone.get_active() + + self.on_save_settings(self.config) # Call the provided save method + self.window.destroy() # Close the settings window + + + def on_cancel_clicked(self, button): + """ + Event handler for Cancel button click. + """ + self.window.destroy() diff --git a/safeeyes/Utility.py b/safeeyes/Utility.py index e7c53ce..159031a 100644 --- a/safeeyes/Utility.py +++ b/safeeyes/Utility.py @@ -18,27 +18,11 @@ import gi gi.require_version('Gdk', '3.0') -from gi.repository import Gtk, Gdk, GLib +from gi.repository import Gdk, GLib from html.parser import HTMLParser from distutils.version import LooseVersion from logging.handlers import RotatingFileHandler -import babel.dates -import os -import errno -import re -import subprocess -import threading -import logging -import locale -import json -import shutil -import wave - -try: - import pyaudio - print('Pyaudio here') -except ImportError: - print('Install pyaudio for audible notifications.') +import babel.dates, os, errno, re, subprocess, threading, logging, locale, json, shutil, pyaudio, wave bin_directory = os.path.dirname(os.path.realpath(__file__)) home_directory = os.path.expanduser('~') @@ -47,473 +31,425 @@ config_directory = os.path.join(home_directory, '.config/safeeyes') config_file_path = os.path.join(config_directory, 'safeeyes.json') style_sheet_path = os.path.join(config_directory, 'style/safeeyes_style.css') system_config_file_path = os.path.join(bin_directory, "config/safeeyes.json") -system_style_sheet_path = os.path.join( - bin_directory, "config/style/safeeyes_style.css") +system_style_sheet_path = os.path.join(bin_directory, "config/style/safeeyes_style.css") log_file_path = os.path.join(config_directory, 'safeeyes.log') - -def pyaudio_installed(): - """ - Check if pyaudio is installed. - - Returns: - bool: True of pyaudio is installed, false otherwise. - """ - try: - import pyaudio - return True - except ImportError: - return False - - -def pyaudio_popup(parent, language): - """ - Show a popup informing user to install pyaudio. - """ - dialog = Gtk.MessageDialog( - parent, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, - language['ui_controls']['pyaudio_not_installed']) - dialog.format_secondary_text( - language['ui_controls']['pyaudio_explanation']) - dialog.run() - dialog.destroy() - - def play_notification(): - """ - Play the alert.wav - """ - logging.info('Playing audible alert') - CHUNK = 1024 + """ + Play the alert.wav + """ + logging.info('Playing audible alert') + CHUNK = 1024 - try: - # Open the sound file - path = get_resource_path('alert.wav') - if path is None: - return - sound = wave.open(path, 'rb') + try: + # Open the sound file + path = get_resource_path('alert.wav') + if path is None: + return + sound = wave.open(path, 'rb') - # Create a sound stream - wrapper = pyaudio.PyAudio() - stream = wrapper.open(format=wrapper.get_format_from_width(sound.getsampwidth()), - channels=sound.getnchannels(), - rate=sound.getframerate(), - output=True) + # Create a sound stream + wrapper = pyaudio.PyAudio() + stream = wrapper.open(format=wrapper.get_format_from_width(sound.getsampwidth()), + channels=sound.getnchannels(), + rate=sound.getframerate(), + output=True) - # Write file data into the sound stream - data = sound.readframes(CHUNK) - while data != b'': - stream.write(data) - data = sound.readframes(CHUNK) + # Write file data into the sound stream + data = sound.readframes(CHUNK) + while data != b'': + stream.write(data) + data = sound.readframes(CHUNK) - # Close steam - stream.stop_stream() - stream.close() - sound.close() - wrapper.terminate() + # Close steam + stream.stop_stream() + stream.close() + sound.close() + wrapper.terminate() - except Exception as e: - logging.warning('Unable to play audible alert') - logging.exception(e) + except Exception as e: + logging.warning('Unable to play audible alert') + logging.exception(e) def get_resource_path(resource_name): - """ - Return the user-defined resource if a system resource is overridden by the user. - Otherwise, return the system resource. Return None if the specified resource does not exist. - """ - if resource_name is None: - return None - resource_location = os.path.join( - config_directory, 'resource', resource_name) - if not os.path.isfile(resource_location): - resource_location = os.path.join( - bin_directory, 'resource', resource_name) - if not os.path.isfile(resource_location): - logging.error('Resource not found: ' + resource_name) - resource_location = None + """ + Return the user-defined resource if a system resource is overridden by the user. + Otherwise, return the system resource. Return None if the specified resource does not exist. + """ + if resource_name is None: + return None + resource_location = os.path.join(config_directory, 'resource', resource_name) + if not os.path.isfile(resource_location): + resource_location = os.path.join(bin_directory, 'resource', resource_name) + if not os.path.isfile(resource_location): + logging.error('Resource not found: ' + resource_name) + resource_location = None - return resource_location + return resource_location def system_idle_time(): - """ - Get system idle time in minutes. - Return the idle time if xprintidle is available, otherwise return 0. - """ - try: - # Convert to minutes - return int(subprocess.check_output(['xprintidle']).decode('utf-8')) / 60000 - except: - return 0 + """ + Get system idle time in minutes. + Return the idle time if xprintidle is available, otherwise return 0. + """ + try: + return int(subprocess.check_output(['xprintidle']).decode('utf-8')) / 60000 # Convert to minutes + except: + return 0 def start_thread(target_function, **args): - """ - Execute the function in a separate thread. - """ - thread = threading.Thread(target=target_function, kwargs=args) - thread.start() + """ + Execute the function in a separate thread. + """ + thread = threading.Thread(target=target_function, kwargs=args) + thread.start() def execute_main_thread(target_function, args=None): - """ - Execute the given function in main thread. - """ - if args: - GLib.idle_add(lambda: target_function(args)) - else: - GLib.idle_add(lambda: target_function()) + """ + Execute the given function in main thread. + """ + if args: + GLib.idle_add(lambda: target_function(args)) + else: + GLib.idle_add(lambda: target_function()) def is_active_window_skipped(skip_break_window_classes, take_break_window_classes, unfullscreen_allowed=False): - """ - Check for full-screen applications. - This method must be executed by the main thread. If not, it will cause to random failure. - """ - logging.info('Searching for full-screen application') - screen = Gdk.Screen.get_default() + """ + Check for full-screen applications. + This method must be executed by the main thread. If not, it will cause to random failure. + """ + logging.info('Searching for full-screen application') + screen = Gdk.Screen.get_default() - active_window = screen.get_active_window() - if active_window: - active_xid = str(active_window.get_xid()) - cmdlist = ['xprop', '-root', '-notype', '-id', - active_xid, 'WM_CLASS', '_NET_WM_STATE'] + active_window = screen.get_active_window() + if active_window: + active_xid = str(active_window.get_xid()) + cmdlist = ['xprop', '-root', '-notype','-id',active_xid, 'WM_CLASS', '_NET_WM_STATE'] - try: - stdout = subprocess.check_output(cmdlist).decode('utf-8') - except subprocess.CalledProcessError: - logging.warning('Error in finding full-screen application') - pass - else: - if stdout: - is_fullscreen = 'FULLSCREEN' in stdout - # Extract the process name - process_names = re.findall('"(.+?)"', stdout) - if process_names: - process = process_names[1].lower() - if process in skip_break_window_classes: - return True - elif process in take_break_window_classes: - if is_fullscreen and unfullscreen_allowed: - try: - active_window.unfullscreen() - except: - logging.error( - 'Error in unfullscreen the window ' + process) - pass - return False + try: + stdout = subprocess.check_output(cmdlist).decode('utf-8') + except subprocess.CalledProcessError: + logging.warning('Error in finding full-screen application') + pass + else: + if stdout: + is_fullscreen = 'FULLSCREEN' in stdout + # Extract the process name + process_names = re.findall('"(.+?)"', stdout) + if process_names: + process = process_names[1].lower() + if process in skip_break_window_classes: + return True + elif process in take_break_window_classes: + if is_fullscreen and unfullscreen_allowed: + try: + active_window.unfullscreen() + except: + logging.error('Error in unfullscreen the window ' + process) + pass + return False - return is_fullscreen + return is_fullscreen - return False + return False def __system_locale(): - """ - Return the system locale. If not available, return en_US.UTF-8. - """ - locale.setlocale(locale.LC_ALL, '') - system_locale = locale.getlocale(locale.LC_TIME)[0] - if not system_locale: - system_locale = 'en_US.UTF-8' - return system_locale + """ + Return the system locale. If not available, return en_US.UTF-8. + """ + locale.setlocale(locale.LC_ALL, '') + system_locale = locale.getlocale(locale.LC_TIME)[0] + if not system_locale: + system_locale = 'en_US.UTF-8' + return system_locale def format_time(time): - """ - Format time based on the system time. - """ - system_locale = __system_locale() - return babel.dates.format_time(time, format='short', locale=system_locale) + """ + Format time based on the system time. + """ + system_locale = __system_locale() + return babel.dates.format_time(time, format='short', locale=system_locale) def mkdir(path): - """ - Create directory if not exists. - """ - try: - os.makedirs(path) - except OSError as exc: - if exc.errno == errno.EEXIST and os.path.isdir(path): - pass - else: - logging.error('Error while creating ' + str(path)) - raise - + """ + Create directory if not exists. + """ + try: + os.makedirs(path) + except OSError as exc: + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: + logging.error('Error while creating ' + str(path)) + raise def parse_language_code(lang_code): - """ - Convert the user defined language code to a valid one. - This includes converting to lower case and finding system locale language, - if the given lang_code code is 'system'. - """ - # Convert to lower case - lang_code = str(lang_code).lower() + """ + Convert the user defined language code to a valid one. + This includes converting to lower case and finding system locale language, + if the given lang_code code is 'system'. + """ + # Convert to lower case + lang_code = str(lang_code).lower() - # If it is system, use the system language - if lang_code == 'system': - logging.info('Use system language for Safe Eyes') - system_locale = __system_locale() - lang_code = system_locale[0:2].lower() + # If it is system, use the system language + if lang_code == 'system': + logging.info('Use system language for Safe Eyes') + system_locale = __system_locale() + lang_code = system_locale[0:2].lower() - # Check whether translation is available for this language. - # If not available, use English by default. - language_file_path = os.path.join( - system_language_directory, lang_code + '.json') - if not os.path.exists(language_file_path): - logging.warn( - 'The language {} does not exist. Use English instead'.format(lang_code)) - lang_code = 'en' + # Check whether translation is available for this language. + # If not available, use English by default. + language_file_path = os.path.join(system_language_directory, lang_code + '.json') + if not os.path.exists(language_file_path): + logging.warn('The language {} does not exist. Use English instead'.format(lang_code)) + lang_code = 'en' - return lang_code + return lang_code def load_language(lang_code): - """ - Load the desired language from the available list based on the preference. - """ - # Convert the user defined language code to a valid one - lang_code = parse_language_code(lang_code) + """ + Load the desired language from the available list based on the preference. + """ + # Convert the user defined language code to a valid one + lang_code = parse_language_code(lang_code) - # Construct the translation file path - language_file_path = os.path.join( - system_language_directory, lang_code + '.json') + # Construct the translation file path + language_file_path = os.path.join(system_language_directory, lang_code + '.json') - language = None - # Read the language file and construct the json object - with open(language_file_path) as language_file: - language = json.load(language_file) + language = None + # Read the language file and construct the json object + with open(language_file_path) as language_file: + language = json.load(language_file) - return language + return language def read_lang_files(): - """ - Read all the language translations and build a key-value mapping of language names - in English and ISO 639-1 (Filename without extension). - """ - languages = {} - for lang_file_name in os.listdir(system_language_directory): - lang_file_path = os.path.join( - system_language_directory, lang_file_name) - if os.path.isfile(lang_file_path): - with open(lang_file_path) as lang_file: - lang = json.load(lang_file) - languages[lang_file_name.lower().replace('.json', '')] = lang[ - 'meta_info']['language_name'] - - return languages + """ + Read all the language translations and build a key-value mapping of language names + in English and ISO 639-1 (Filename without extension). + """ + languages = {} + for lang_file_name in os.listdir(system_language_directory): + lang_file_path = os.path.join(system_language_directory, lang_file_name) + if os.path.isfile(lang_file_path): + with open(lang_file_path) as lang_file: + lang = json.load(lang_file) + languages[lang_file_name.lower().replace('.json', '')] = lang['meta_info']['language_name'] + return languages def lock_screen_command(): - """ - Function tries to detect the screensaver command based on the current envinroment - Possible results: - Gnome, Unity, Budgie: ['gnome-screensaver-command', '--lock'] - Cinnamon: ['cinnamon-screensaver-command', '--lock'] - Pantheon, LXDE: ['light-locker-command', '--lock'] - Mate: ['mate-screensaver-command', '--lock'] - KDE: ['qdbus', 'org.freedesktop.ScreenSaver', '/ScreenSaver', 'Lock'] - XFCE: ['xflock4'] - Otherwise: None - """ - desktop_session = os.environ.get('DESKTOP_SESSION') - current_desktop = os.environ.get('XDG_CURRENT_DESKTOP') - if desktop_session is not None: - desktop_session = desktop_session.lower() - if ('xfce' in desktop_session or desktop_session.startswith('xubuntu') or (current_desktop is not None and 'xfce' in current_desktop)) and command_exist('xflock4'): - return ['xflock4'] - elif desktop_session == 'cinnamon' and command_exist('cinnamon-screensaver-command'): - return ['cinnamon-screensaver-command', '--lock'] - elif (desktop_session == 'pantheon' or desktop_session.startswith('lubuntu')) and command_exist('light-locker-command'): - return ['light-locker-command', '--lock'] - elif desktop_session == 'mate' and command_exist('mate-screensaver-command'): - return ['mate-screensaver-command', '--lock'] - elif desktop_session == 'kde' or 'plasma' in desktop_session or desktop_session.startswith('kubuntu') or os.environ.get('KDE_FULL_SESSION') == 'true': - return ['qdbus', 'org.freedesktop.ScreenSaver', '/ScreenSaver', 'Lock'] - elif desktop_session in ['gnome', 'unity', 'budgie-desktop'] or desktop_session.startswith('ubuntu'): - if command_exist('gnome-screensaver-command'): - return ['gnome-screensaver-command', '--lock'] - else: - # From Gnome 3.8 no gnome-screensaver-command - return ['dbus-send', '--type=method_call', '--dest=org.gnome.ScreenSaver', '/org/gnome/ScreenSaver', 'org.gnome.ScreenSaver.Lock'] - elif os.environ.get('GNOME_DESKTOP_SESSION_ID'): - if not 'deprecated' in os.environ.get('GNOME_DESKTOP_SESSION_ID') and command_exist('gnome-screensaver-command'): - # Gnome 2 - return ['gnome-screensaver-command', '--lock'] - return None + """ + Function tries to detect the screensaver command based on the current envinroment + Possible results: + Gnome, Unity, Budgie: ['gnome-screensaver-command', '--lock'] + Cinnamon: ['cinnamon-screensaver-command', '--lock'] + Pantheon, LXDE: ['light-locker-command', '--lock'] + Mate: ['mate-screensaver-command', '--lock'] + KDE: ['qdbus', 'org.freedesktop.ScreenSaver', '/ScreenSaver', 'Lock'] + XFCE: ['xflock4'] + Otherwise: None + """ + desktop_session = os.environ.get('DESKTOP_SESSION') + current_desktop = os.environ.get('XDG_CURRENT_DESKTOP') + if desktop_session is not None: + desktop_session = desktop_session.lower() + if ('xfce' in desktop_session or desktop_session.startswith('xubuntu') or (current_desktop is not None and 'xfce' in current_desktop)) and command_exist('xflock4'): + return ['xflock4'] + elif desktop_session == 'cinnamon' and command_exist('cinnamon-screensaver-command'): + return ['cinnamon-screensaver-command', '--lock'] + elif (desktop_session == 'pantheon' or desktop_session.startswith('lubuntu')) and command_exist('light-locker-command'): + return ['light-locker-command', '--lock'] + elif desktop_session == 'mate' and command_exist('mate-screensaver-command'): + return ['mate-screensaver-command', '--lock'] + elif desktop_session == 'kde' or 'plasma' in desktop_session or desktop_session.startswith('kubuntu') or os.environ.get('KDE_FULL_SESSION') == 'true': + return ['qdbus', 'org.freedesktop.ScreenSaver', '/ScreenSaver', 'Lock'] + elif desktop_session in ['gnome','unity', 'budgie-desktop'] or desktop_session.startswith('ubuntu'): + if command_exist('gnome-screensaver-command'): + return ['gnome-screensaver-command', '--lock'] + else: + # From Gnome 3.8 no gnome-screensaver-command + return ['dbus-send', '--type=method_call', '--dest=org.gnome.ScreenSaver', '/org/gnome/ScreenSaver', 'org.gnome.ScreenSaver.Lock'] + elif os.environ.get('GNOME_DESKTOP_SESSION_ID'): + if not 'deprecated' in os.environ.get('GNOME_DESKTOP_SESSION_ID') and command_exist('gnome-screensaver-command'): + # Gnome 2 + return ['gnome-screensaver-command', '--lock'] + return None def lock_desktop(command): - """ - Lock the screen using the predefined commands - """ - if command: - try: - subprocess.Popen(command) - except Exception as e: - logging.error('Error in executing the commad' + - str(command) + ' to lock screen') + """ + Lock the screen using the predefined commands + """ + if command: + try: + subprocess.Popen(command) + except Exception as e: + logging.error('Error in executing the commad' + str(command) + ' to lock screen') def html_to_text(html): - """ - Convert HTML to plain text - """ - extractor = __HTMLTextExtractor() - extractor.feed(html) - return extractor.get_data() + """ + Convert HTML to plain text + """ + extractor = __HTMLTextExtractor() + extractor.feed(html) + return extractor.get_data() def command_exist(command): - """ - Check whether the given command exist in the system or not. - """ - if shutil.which(command): - return True - else: - return False + """ + Check whether the given command exist in the system or not. + """ + if shutil.which(command): + return True + else: + return False def merge_configs(new_config, old_config): - """ - Merge the values of old_config into the new_config. - """ - new_config = new_config.copy() - new_config.update(old_config) - return new_config + """ + Merge the values of old_config into the new_config. + """ + new_config = new_config.copy() + new_config.update(old_config) + return new_config def __initialize_safeeyes(): - """ - Create the config file and style sheet in ~/.config/safeeyes directory. - """ - logging.info('Copy the config files to ~/.config/safeeyes') + """ + Create the config file and style sheet in ~/.config/safeeyes directory. + """ + logging.info('Copy the config files to ~/.config/safeeyes') - style_dir_path = os.path.join(home_directory, '.config/safeeyes/style') - startup_dir_path = os.path.join(home_directory, '.config/autostart') + style_dir_path = os.path.join(home_directory, '.config/safeeyes/style') + startup_dir_path = os.path.join(home_directory, '.config/autostart') - # Remove the ~/.config/safeeyes directory - shutil.rmtree(config_directory, ignore_errors=True) + # Remove the ~/.config/safeeyes directory + shutil.rmtree(config_directory, ignore_errors=True) - # Remove the startup file - try: - os.remove(os.path.join(home_directory, os.path.join( - startup_dir_path, 'safeeyes.desktop'))) - except: - pass + # Remove the startup file + try: + os.remove(os.path.join(home_directory, os.path.join(startup_dir_path, 'safeeyes.desktop'))) + except: + pass - # Create the ~/.config/safeeyes/style directory - mkdir(style_dir_path) - mkdir(startup_dir_path) + # Create the ~/.config/safeeyes/style directory + mkdir(style_dir_path) + mkdir(startup_dir_path) - # Copy the safeeyes.json - shutil.copy2(system_config_file_path, config_file_path) + # Copy the safeeyes.json + shutil.copy2(system_config_file_path, config_file_path) - # Copy the new startup file - try: - os.symlink("/usr/share/applications/safeeyes.desktop", - os.path.join(startup_dir_path, 'safeeyes.desktop')) - except OSError as exc: - pass + # Copy the new startup file + try: + os.symlink("/usr/share/applications/safeeyes.desktop", os.path.join(startup_dir_path, 'safeeyes.desktop')) + except OSError as exc: + pass - # Copy the new style sheet - if not os.path.isfile(style_sheet_path): - shutil.copy2(system_style_sheet_path, style_sheet_path) + # Copy the new style sheet + if not os.path.isfile(style_sheet_path): + shutil.copy2(system_style_sheet_path, style_sheet_path) def intialize_logging(): - """ - Initialize the logging framework using the Safe Eyes specific configurations. - """ - # Create the directory to store log file if not exist - if not os.path.exists(config_directory): - try: - os.makedirs(config_directory) - except: - pass + """ + Initialize the logging framework using the Safe Eyes specific configurations. + """ + # Create the directory to store log file if not exist + if not os.path.exists(config_directory): + try: + os.makedirs(config_directory) + except: + pass - # Configure logging. - log_formatter = logging.Formatter( - '%(asctime)s [%(levelname)s]:[%(threadName)s] %(message)s') + # Configure logging. + log_formatter = logging.Formatter('%(asctime)s [%(levelname)s]:[%(threadName)s] %(message)s') - # Apped the logs and overwrite once reached 5MB - handler = RotatingFileHandler( - log_file_path, mode='a', maxBytes=5 * 1024 * 1024, backupCount=2, encoding=None, delay=0) - handler.setFormatter(log_formatter) - handler.setLevel(logging.INFO) + # Apped the logs and overwrite once reached 5MB + handler = RotatingFileHandler(log_file_path, mode='a', maxBytes=5*1024*1024, backupCount=2, encoding=None, delay=0) + handler.setFormatter(log_formatter) + handler.setLevel(logging.INFO) - root_logger = logging.getLogger() - root_logger.setLevel(logging.INFO) - root_logger.addHandler(handler) + root_logger = logging.getLogger() + root_logger.setLevel(logging.INFO) + root_logger.addHandler(handler) def read_config(): - """ - Read the configuration from the config directory. - If does not exist or outdated by major version, copy the system config and - startup script to user directory. - If the user config is outdated by minor version, update the config by the new values. - """ - logging.info('Reading the configuration file') + """ + Read the configuration from the config directory. + If does not exist or outdated by major version, copy the system config and + startup script to user directory. + If the user config is outdated by minor version, update the config by the new values. + """ + logging.info('Reading the configuration file') - if not os.path.isfile(config_file_path): - logging.info('Safe Eyes configuration file not found') - __initialize_safeeyes() + if not os.path.isfile(config_file_path): + logging.info('Safe Eyes configuration file not found') + __initialize_safeeyes() - # Read the configurations - with open(config_file_path) as config_file: - user_config = json.load(config_file) + # Read the configurations + with open(config_file_path) as config_file: + user_config = json.load(config_file) - with open(system_config_file_path) as config_file: - system_config = json.load(config_file) + with open(system_config_file_path) as config_file: + system_config = json.load(config_file) - user_config_version = str(user_config['meta']['config_version']) - system_config_version = str(system_config['meta']['config_version']) + user_config_version = str(user_config['meta']['config_version']) + system_config_version = str(system_config['meta']['config_version']) - if LooseVersion(user_config_version) < LooseVersion(system_config_version): - # Outdated user config - logging.info('Update the old config version {} with new config version {}'.format( - user_config_version, system_config_version)) - user_config_major_version = user_config_version.split('.')[0] - system_config_major_version = system_config_version.split('.')[0] + if LooseVersion(user_config_version) < LooseVersion(system_config_version): + # Outdated user config + logging.info('Update the old config version {} with new config version {}'.format(user_config_version, system_config_version)) + user_config_major_version = user_config_version.split('.')[0] + system_config_major_version = system_config_version.split('.')[0] - if LooseVersion(user_config_major_version) < LooseVersion(system_config_major_version): - # Major version change - __initialize_safeeyes() - # Update the user_config - user_config = system_config - else: - # Minor version change - new_config = system_config.copy() - new_config.update(user_config) - # Update the version - new_config['meta']['config_version'] = system_config_version + if LooseVersion(user_config_major_version) < LooseVersion(system_config_major_version): + # Major version change + __initialize_safeeyes() + # Update the user_config + user_config = system_config + else: + # Minor version change + new_config = system_config.copy() + new_config.update(user_config) + # Update the version + new_config['meta']['config_version'] = system_config_version - # Write the configuration to file - with open(config_file_path, 'w') as config_file: - json.dump(new_config, config_file, indent=4, sort_keys=True) + # Write the configuration to file + with open(config_file_path, 'w') as config_file: + json.dump(new_config, config_file, indent=4, sort_keys=True) - # Update the user_config - user_config = new_config + # Update the user_config + user_config = new_config - return user_config + return user_config class __HTMLTextExtractor(HTMLParser): - """ - Helper class to convert HTML to text - """ + """ + Helper class to convert HTML to text + """ + def __init__(self): + self.reset() + self.strict = False + self.convert_charrefs= True + self.fed = [] - def __init__(self): - self.reset() - self.strict = False - self.convert_charrefs = True - self.fed = [] + def handle_data(self, d): + self.fed.append(d) - def handle_data(self, d): - self.fed.append(d) - - def get_data(self): - return ''.join(self.fed) + def get_data(self): + return ''.join(self.fed) diff --git a/safeeyes/config/lang/en.json b/safeeyes/config/lang/en.json index 2ec82a8..c53b3e1 100644 --- a/safeeyes/config/lang/en.json +++ b/safeeyes/config/lang/en.json @@ -43,8 +43,6 @@ "no_of_short_breaks_between_two_long_breaks": "Number of short breaks between two long breaks", "postpone": "Postpone", "postpone_duration": "Postpone duration (in minutes)", - "pyaudio_not_installed": "Cannot enable audible notifications", - "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Quit", "save": "Save", "settings": "Settings", diff --git a/safeeyes/config/lang/es.json b/safeeyes/config/lang/es.json index e1db18a..25426bc 100644 --- a/safeeyes/config/lang/es.json +++ b/safeeyes/config/lang/es.json @@ -43,8 +43,6 @@ "no_of_short_breaks_between_two_long_breaks": "Número de pausas cortas entre dos pausas largas", "postpone": "Posponer", "postpone_duration": "Duración de cada posposición (en minutos)", - "pyaudio_not_installed": "Cannot enable audible notifications", - "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Salir", "save": "Guardar", "settings": "Preferencias", diff --git a/safeeyes/config/lang/fr.json b/safeeyes/config/lang/fr.json index 924e2fe..dea77ae 100644 --- a/safeeyes/config/lang/fr.json +++ b/safeeyes/config/lang/fr.json @@ -43,8 +43,6 @@ "no_of_short_breaks_between_two_long_breaks": "Nombre de pauses courtes entre deux pauses longues", "postpone": "Reporter", "postpone_duration": "Durée de report (en minutes)", - "pyaudio_not_installed": "Cannot enable audible notifications", - "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Quitter", "save": "Enregistrer", "settings": "Paramètres", diff --git a/safeeyes/config/lang/ge.json b/safeeyes/config/lang/ge.json index 53cf55d..3506ec4 100644 --- a/safeeyes/config/lang/ge.json +++ b/safeeyes/config/lang/ge.json @@ -43,8 +43,6 @@ "no_of_short_breaks_between_two_long_breaks": "მცირე შესვენებების რაოდენობა ორ დიდ შესვენებას შორის", "postpone": "Postpone", "postpone_duration": "Postpone duration (in minutes)", - "pyaudio_not_installed": "Cannot enable audible notifications", - "pyaudio_explanation": "To enable them, install pyaudio", "quit": "გასვლა", "save": "დამახსოვრება", "settings": "პარამეტრები", diff --git a/safeeyes/config/lang/hi.json b/safeeyes/config/lang/hi.json index 2218cba..8bc82a3 100644 --- a/safeeyes/config/lang/hi.json +++ b/safeeyes/config/lang/hi.json @@ -43,8 +43,6 @@ "no_of_short_breaks_between_two_long_breaks": "दो बड़े आराम के बीच कितने छोटे आराम", "postpone": "Postpone", "postpone_duration": "Postpone duration (in minutes)", - "pyaudio_not_installed": "Cannot enable audible notifications", - "pyaudio_explanation": "To enable them, install pyaudio", "quit": "बंद", "save": "रखें", "settings": "सेटिंग्स", diff --git a/safeeyes/config/lang/hu.json b/safeeyes/config/lang/hu.json index 6e6fb63..28407bb 100644 --- a/safeeyes/config/lang/hu.json +++ b/safeeyes/config/lang/hu.json @@ -43,8 +43,6 @@ "no_of_short_breaks_between_two_long_breaks": "Hány rövid szünet legyen a hosszabbak között?", "postpone": "Postpone", "postpone_duration": "Postpone duration (in minutes)", - "pyaudio_not_installed": "Cannot enable audible notifications", - "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Kilépés", "save": "Mentés", "settings": "Beállítások", diff --git a/safeeyes/config/lang/id.json b/safeeyes/config/lang/id.json index 4a51c07..11bf9e2 100644 --- a/safeeyes/config/lang/id.json +++ b/safeeyes/config/lang/id.json @@ -43,8 +43,6 @@ "no_of_short_breaks_between_two_long_breaks": "Jumlah istirahat singkat di antara dua istirahat panjang", "postpone": "Postpone", "postpone_duration": "Postpone duration (in minutes)", - "pyaudio_not_installed": "Cannot enable audible notifications", - "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Keluar", "save": "Simpan", "settings": "Pengaturan", diff --git a/safeeyes/config/lang/mk.json b/safeeyes/config/lang/mk.json index 1fd701e..82702ec 100644 --- a/safeeyes/config/lang/mk.json +++ b/safeeyes/config/lang/mk.json @@ -43,8 +43,6 @@ "no_of_short_breaks_between_two_long_breaks": "Број на кратки паузи помеѓу две долги", "postpone": "Одложи", "postpone_duration": "Траење на одложувањето (Во секунди)", - "pyaudio_not_installed": "Cannot enable audible notifications", - "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Исклучи", "save": "Зачувај", "settings": "Подесувања", diff --git a/safeeyes/config/lang/pl.json b/safeeyes/config/lang/pl.json index 1518109..0667dcb 100644 --- a/safeeyes/config/lang/pl.json +++ b/safeeyes/config/lang/pl.json @@ -43,8 +43,6 @@ "no_of_short_breaks_between_two_long_breaks": "Liczba krótkich przerw między długimi przerwami", "postpone": "Odrocz", "postpone_duration": "Odroczenie przerwy (w minutach)", - "pyaudio_not_installed": "Cannot enable audible notifications", - "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Wyjdź", "save": "Zapisz", "settings": "Ustawienia", diff --git a/safeeyes/config/lang/pt.json b/safeeyes/config/lang/pt.json index 7b38748..c502644 100644 --- a/safeeyes/config/lang/pt.json +++ b/safeeyes/config/lang/pt.json @@ -43,8 +43,6 @@ "no_of_short_breaks_between_two_long_breaks": "Número de pausas curtas entre duas pausas longas", "postpone": "Adiar", "postpone_duration": "Duração do adiamento (em minutos)", - "pyaudio_not_installed": "Cannot enable audible notifications", - "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Sair", "save": "Salvar", "settings": "Configuração", diff --git a/safeeyes/config/lang/ru.json b/safeeyes/config/lang/ru.json index 7f6da0d..33b1aee 100644 --- a/safeeyes/config/lang/ru.json +++ b/safeeyes/config/lang/ru.json @@ -43,8 +43,6 @@ "no_of_short_breaks_between_two_long_breaks": "Количество коротких перерывов между двумя длинными", "postpone": "Отложить", "postpone_duration": "Отложить на время (в минутах)", - "pyaudio_not_installed": "Cannot enable audible notifications", - "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Выйти", "save": "Сохранить", "settings": "Настройки", diff --git a/safeeyes/config/lang/sk.json b/safeeyes/config/lang/sk.json index 22abb01..eb3ae75 100644 --- a/safeeyes/config/lang/sk.json +++ b/safeeyes/config/lang/sk.json @@ -47,8 +47,6 @@ "no_of_short_breaks_between_two_long_breaks": "Počet krátkych prestávok medzi dvomi dlhými prestávkami", "postpone": "Odložiť", "postpone_duration": "O koĺko odložiť (minút)", - "pyaudio_not_installed": "Nieje možné zapnúť zvukové upozornenia", - "pyaudio_explanation": "Ak ich chcete povoliť, nainštalujte pyaudio", "quit": "Koniec", "save": "Uložiť", "settings": "Nastavenia", diff --git a/safeeyes/config/lang/ta.json b/safeeyes/config/lang/ta.json index e56fa3e..527cb5c 100644 --- a/safeeyes/config/lang/ta.json +++ b/safeeyes/config/lang/ta.json @@ -43,8 +43,6 @@ "no_of_short_breaks_between_two_long_breaks": "இரண்டு நீண்ட இடைவேளைகளுக்கிடையிலான குறுகிய இடைவேளைகள்", "postpone": "ஒத்தி வை", "postpone_duration": "இடைவேளையை ஒத்தி வைக்கும் காலம் (நிமிடங்களில்)", - "pyaudio_not_installed": "Cannot enable audible notifications", - "pyaudio_explanation": "To enable them, install pyaudio", "quit": "நிறுத்து", "save": "சேமி", "settings": "அமைப்பு", diff --git a/safeeyes/config/lang/tr.json b/safeeyes/config/lang/tr.json index 8a503b5..ecb803d 100644 --- a/safeeyes/config/lang/tr.json +++ b/safeeyes/config/lang/tr.json @@ -43,8 +43,6 @@ "no_of_short_breaks_between_two_long_breaks": "İki uzun mola arasındaki kısa mola sayısı", "postpone": "Ertele", "postpone_duration": "Ertelme süresi (dakika)", - "pyaudio_not_installed": "Cannot enable audible notifications", - "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Çıkış", "save": "Kaydet", "settings": "Ayarlar", diff --git a/safeeyes/config/lang/vi.json b/safeeyes/config/lang/vi.json index 92f1436..aa67e3c 100644 --- a/safeeyes/config/lang/vi.json +++ b/safeeyes/config/lang/vi.json @@ -48,8 +48,6 @@ "no_of_short_breaks_between_two_long_breaks": "Số lần nghỉ ngơi ngắn giữa hai lần nghỉ ngơi dài", "postpone": "Tạm hoãn", "postpone_duration": "Thời gian tạm hoãn (tính bằng phút)", - "pyaudio_not_installed": "Cannot enable audible notifications", - "pyaudio_explanation": "To enable them, install pyaudio", "quit": "Thoát", "save": "Lưu", "settings": "Cài đặt", diff --git a/setup.py b/setup.py index 1e237b0..ce30fdd 100644 --- a/setup.py +++ b/setup.py @@ -4,10 +4,10 @@ import setuptools requires = [ - 'python-xlib', - 'pyaudio', - 'psutil', - 'babel'] + 'python-xlib', + 'pyaudio', + 'psutil', + 'babel'] here = os.path.abspath(os.path.dirname(__file__)) @@ -15,7 +15,6 @@ here = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(here, 'README.md')) as f: long_description = '\n' + f.read() - def _data_files(path): for root, dirs, files in os.walk(path): if not files: @@ -38,30 +37,18 @@ setuptools.setup( 'glade/*.glade', 'resource/*']}, data_files=[('/usr/share/applications', ['share/applications/safeeyes.desktop']), - ('/usr/share/icons/hicolor/16x16/apps', - ['share/icons/hicolor/16x16/apps/safeeyes.png']), - ('/usr/share/icons/hicolor/24x24/apps', - ['share/icons/hicolor/24x24/apps/safeeyes.png']), - ('/usr/share/icons/hicolor/48x48/apps', - ['share/icons/hicolor/48x48/apps/safeeyes.png']), - ('/usr/share/icons/hicolor/32x32/apps', - ['share/icons/hicolor/32x32/apps/safeeyes.png']), - ('/usr/share/icons/hicolor/64x64/apps', - ['share/icons/hicolor/64x64/apps/safeeyes.png']), - ('/usr/share/icons/hicolor/128x128/apps', - ['share/icons/hicolor/128x128/apps/safeeyes.png']), - ('/usr/share/icons/hicolor/48x48/status', - ['share/icons/hicolor/48x48/status/safeeyes_enabled.png', 'share/icons/hicolor/48x48/status/safeeyes_disabled.png']), - ('/usr/share/icons/hicolor/32x32/status', - ['share/icons/hicolor/32x32/status/safeeyes_enabled.png', 'share/icons/hicolor/32x32/status/safeeyes_disabled.png']), - ('/usr/share/icons/hicolor/24x24/status', ['share/icons/hicolor/24x24/status/safeeyes_enabled.png', - 'share/icons/hicolor/24x24/status/safeeyes_disabled.png', 'share/icons/hicolor/24x24/status/safeeyes_timer.png']), - ('/usr/share/icons/hicolor/16x16/status', ['share/icons/hicolor/16x16/status/safeeyes_enabled.png', - 'share/icons/hicolor/16x16/status/safeeyes_disabled.png', 'share/icons/hicolor/16x16/status/safeeyes_timer.png']) + ('/usr/share/icons/hicolor/16x16/apps', ['share/icons/hicolor/16x16/apps/safeeyes.png']), + ('/usr/share/icons/hicolor/24x24/apps', ['share/icons/hicolor/24x24/apps/safeeyes.png']), + ('/usr/share/icons/hicolor/48x48/apps', ['share/icons/hicolor/48x48/apps/safeeyes.png']), + ('/usr/share/icons/hicolor/32x32/apps', ['share/icons/hicolor/32x32/apps/safeeyes.png']), + ('/usr/share/icons/hicolor/64x64/apps', ['share/icons/hicolor/64x64/apps/safeeyes.png']), + ('/usr/share/icons/hicolor/128x128/apps', ['share/icons/hicolor/128x128/apps/safeeyes.png']), + ('/usr/share/icons/hicolor/48x48/status', ['share/icons/hicolor/48x48/status/safeeyes_enabled.png', 'share/icons/hicolor/48x48/status/safeeyes_disabled.png']), + ('/usr/share/icons/hicolor/32x32/status', ['share/icons/hicolor/32x32/status/safeeyes_enabled.png', 'share/icons/hicolor/32x32/status/safeeyes_disabled.png']), + ('/usr/share/icons/hicolor/24x24/status', ['share/icons/hicolor/24x24/status/safeeyes_enabled.png', 'share/icons/hicolor/24x24/status/safeeyes_disabled.png', 'share/icons/hicolor/24x24/status/safeeyes_timer.png']), + ('/usr/share/icons/hicolor/16x16/status', ['share/icons/hicolor/16x16/status/safeeyes_enabled.png', 'share/icons/hicolor/16x16/status/safeeyes_disabled.png', 'share/icons/hicolor/16x16/status/safeeyes_timer.png']) ], install_requires=requires, - extras_require={ - 'audio': ['pyaudio']}, entry_points={'console_scripts': ['safeeyes = safeeyes.__main__:main']}, keywords='linux utility health eye-strain safe-eyes', classifiers=[