Ubuntu的模糊时钟

很久以前,我有一个时钟设置,可以在面板应用中显示早上、白天、傍晚、夜晚等时间。大致而言,并不是非常具体,可能是在KDE桌面环境下。现在我使用的是Ubuntu Mate,是否有办法在Mate面板中获取这种模糊的时间描述呢?

1如果有帮助的话,这被称为模糊时钟。 - Dmiters
确实有帮助。 :) - j0h
1这是源代码:https://code.google.com/archive/p/fuzzy-clock/ 现在我们需要 @jacobvlijm 将其变成一个应用程序 >:-D - Rinzwind
我开始阅读Mate-University,以便制作面板应用程序。我确信我可以编写类似的东西,但是我不知道如何将其制作成面板应用程序。 - j0h
@Rinzwind……我正在调查这个问题。不确定是在一天还是两天内完成,但肯定会再回复您的:) 我想我会从头开始重新做。 - Jacob Vlijm
为了清楚起见,您希望在面板上具体显示什么内容?是要实际“说出”(发声),还是只是文字上的“早上好”等等? - Jacob Vlijm
早上、白天、晚上、夜晚,这个说法就很完美了。我自己会写的,但是我对于如何使面板应用程序工作一无所知。 - j0h
1这是在KDE中的,我对此非常确定,并且也进行了翻译! - Antek
2个回答

Mate和其他Ubuntu变种的文本/语音时钟

虽然最初的问题是关于Ubuntu Mate的,但幸运的是,从15.10版本开始,指示器也可以在Mate上使用。因此,下面的答案至少适用于Unity、Mate和(经过测试的)Xubuntu。

目前还没有提供更改设置的图形界面(正在努力开发中),但我已经测试了下面的指示器至少20小时,并且(如预期)它能够正常工作,没有出现错误。

选项

该指示器提供以下选项:

  • 显示文本时间

    enter image description here

  • 显示文本的“白天区域”(夜晚,早晨,白天,傍晚)

    enter image description here

  • 显示上午/下午

    enter image description here

  • 同时显示所有这些内容(或任意组合)

    enter image description here

  • 每个小时的四分之一报时(需要espeak

  • 可选地,时间以模糊方式显示;按五分钟取整,例如
    10:43 -> 差15分钟11点

脚本、模块和图标

解决方案包括一个脚本、一个独立的模块和一个图标,您需要将它们存储在同一个目录中。

图标:

enter image description here

右键点击它并将其保存为(确切地)indicator_icon.png 该模块: 这是生成文本时间和所有其他显示信息的模块。复制代码,将其保存为(同样,确切地tcalc.py,与上面的图标一起放在同一个目录中
#!/usr/bin/env python3
import time

# --- set starttime of morning, day, evening, night (whole hrs)
limits = [6, 9, 18, 21]
# ---

periods = ["night", "morning", "day", "evening", "night"]

def __fig(n):
    singles = [
        "midnight", "one", "two", "three", "four", "five", "six",
        "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen",
        "fourteen", "quarter", "sixteen", "seventeen", "eighteen", "nineteen",
        ]
    tens = ["twenty", "half"]
    if n < 20:
        return singles[n]
    else:
        if n%10 == 0:
            return tens[int((n/10)-2)]
        else:
            fst = tens[int(n/10)-2]
            lst = singles[int(str(n)[-1])]
            return fst+"-"+lst

def __fuzzy(currtime):
    minutes = round(currtime[1]/5)*5
    if minutes == 60:
        currtime[1] = 0
        currtime[0] = currtime[0] + 1
    else:
        currtime[1] = minutes
    currtime[0] = 0 if currtime[0] == 24 else currtime[0]
    return currtime

def textualtime(fuzz):
    currtime = [int(n) for n in time.strftime("%H %M %S").split()]
    currtime = __fuzzy(currtime) if fuzz == True else currtime
    speak = True if currtime[1]%15 == 0 else False
    period = periods[len([n for n in limits if currtime[0] >= n])]
    # define a.m. / p.m.
    if currtime[0] >= 12:
        daytime = "p.m."
        if currtime[0] == 12:
            if currtime[1] > 30:
                currtime[0] = currtime[0] - 12
        else:
            currtime[0] = currtime[0] - 12
    else:
        daytime = "a.m."
    # convert time to textual time
    if currtime[1] == 0:
        t = __fig(currtime[0])+" o'clock" if currtime[0] != 0 else __fig(currtime[0])
    elif currtime[1] > 30:
        t = __fig((60 - currtime[1]))+" to "+__fig(currtime[0]+1)
    else:
        t = __fig(currtime[1])+" past "+__fig(currtime[0])
    return [t, period, daytime, currtime[2], speak]

脚本:

这是实际的指示器。复制代码,将其保存为moderntimes.py,与图标和上述模块放在同一个目录下

#!/usr/bin/env python3
import os
import signal
import subprocess
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, AppIndicator3, GObject
import time
from threading import Thread
import tcalc

# --- define what to show:
# showtime = textual time, daytime = a.m./p.m. period = "night"/"morning"/day"/"evening"
# speak = speak out time every quarter, fuzzy = round time on 5 minutes
showtime = True; daytime = False; period = True; speak = True; fuzzy = True

class Indicator():
    def __init__(self):
        self.app = 'about_time'
        path = os.path.dirname(os.path.abspath(__file__))
        self.indicator = AppIndicator3.Indicator.new(
            self.app, os.path.abspath(path+"/indicator_icon.png"),
            AppIndicator3.IndicatorCategory.OTHER)
        self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)       
        self.indicator.set_menu(self.create_menu())

        self.update = Thread(target=self.get_time)
        self.update.setDaemon(True)
        self.update.start()

    def get_time(self):
        # the first loop is 0 seconds, the next loop is 60 seconds,
        # in phase with computer clock
        loop = 0; timestring1 = ""
        while True:
            time.sleep(loop)
            tdata = tcalc.textualtime(fuzzy)
            timestring2 = tdata[0]
            loop = (60 - tdata[3])+1
            mention = (" | ").join([tdata[item[1]] for item in [
                [showtime, 0], [period, 1], [daytime, 2]
                ]if item[0] == True])
            if all([
                tdata[4] == True,
                speak == True,
                timestring2 != timestring1,
                ]):
                subprocess.Popen(["espeak", '"'+timestring2+'"', "-s", "130"])
            # [4] edited
            GObject.idle_add(
                self.indicator.set_label,
                mention, self.app,
                priority=GObject.PRIORITY_DEFAULT
                )
            timestring1 = timestring2

    def create_menu(self):
        menu = Gtk.Menu()
        item_quit = Gtk.MenuItem('Quit')
        item_quit.connect('activate', self.stop)
        menu.append(item_quit)
        menu.show_all()
        return menu

    def stop(self, source):
        Gtk.main_quit()

Indicator()
GObject.threads_init()
signal.signal(signal.SIGINT, signal.SIG_DFL)
Gtk.main()

如何使用
  1. 脚本需要 espeak

    sudo apt-get install espeak
    
  2. 将上述三个文件复制到同一个目录中,确保文件名与 脚本、模块和图标 中指定的名称完全一致。

  3. 脚本 的开头(moderntimes.py),定义应该显示哪些信息以及如何显示。只需在以下行中设置为 TrueFalse

    # --- define what to show:
    # time = textual time, daytime = a.m./p.m. period = "night"/"morning"/day"/"evening"
    # speak = speak out time every quarter, fuzzy = round time on 5 minutes
    showtime = True; daytime = False; period = True; speak = False; fuzzy = True
    
  4. 模块 的开头,您可以更改开始 早晨白天晚上夜晚 的小时数,在以下行中:

    # --- set starttime of morning, day, evening, night (whole hrs)
    limits = [6, 9, 18, 21]
    # ---
    

    暂时不要修改脚本中的其他内容 :)

  5. Ubuntu Mate 用户 需要在系统上启用指示器:选择 System > Preferences > Look and feel > Mate tweak > Interface > "Enable indicators"

    enter image description here

  6. 使用以下命令运行指示器:

    python3 /path/to/moderntimes.py
    

从启动应用程序中运行它

请记住,如果您从启动应用程序中运行命令,在许多情况下,您需要添加一个小的延迟,特别是(在其他情况下)在指示器上:

/bin/bash -c "sleep 15 && python3 /path/to/moderntimes.py"

注释

毫无疑问,脚本在接下来的几天内会多次更改/更新。我特别想要反馈的一件事是将数字时间转换为文字时间的“风格”。目前的做法如下:
- 整点,例如: 六点钟
- 不到整点后30分钟,例如: 十一点二十分
- 整点后30分钟,例如: 五点半
- 超过30分钟,例如: 五点差二十分
- 提到15分钟时使用“quarter”,例如: 六点一刻
- 例外情况是午夜,不称为“zero”,而是称为“midnight”,例如: 午夜过一刻
由于第一次检查循环后,脚本会自动与计算机时钟同步,因此脚本的电量非常低。因此,脚本每分钟只检查时间/编辑显示的时间一次,并在其余时间休眠。

编辑

截至今天(2016年4月9日),已经提供了一个经过改进的版本的ppa。要从ppa安装:

sudo apt-add-repository ppa:vlijm/abouttime
sudo apt-get update
sudo apt-get install abouttime

这个版本中的时间段与上面的脚本版本相比有所改变,现在是:
morning 6:00-12:00
afternoon 12:00-18:00
evening 18:00-24:00
night 24:00-6:00

...而且指示器在白天有更改图标的选项:
早上/下午/晚上/夜晚输入图像描述 输入图像描述 输入图像描述 输入图像描述

如前所述,此版本已在Mate(来自原始问题)、UnityXubuntu上进行了测试。

enter image description here


1我会说:模糊意味着你可能不准确。所以15:12到15:23左右就是3点15分。我建议只使用:5/10/15/30分钟过/到整点。这不是白叫“模糊”。 - Rinzwind
又一个令人赞叹的回答。希望这能够被整合到你的PPA中.... :) - Parto
@Parto 哇,再次感谢 :) 我一定会为这个创建一个ppa :) - Jacob Vlijm

如果你使用Kubuntu(Plasma桌面Ubuntu发行版),你就有一个内置的小部件叫做“模糊时钟”——它至少从14.04版本开始存在,或者说至少从Plasma 4发布以来就有了,并且在Kubuntu 16.04中仍然存在于Plasma 5中。
模糊时钟可以设置为最多五分钟的“准确度”,就像读取一个模拟时钟一样(比如,“四点十分”),但它还有三个更“模糊”的设置,其中一个会显示“下午”,另一个只会显示“周末!”(在一个星期天的下午——我猜明天它会显示“星期一”)。
我不知道模糊时钟是否在其他Ubuntu版本中可用——我在我的系统上看到它在xfce(在Xubuntu中)中,但操作系统是作为Kubuntu安装的,所以我不确定模糊时钟是否也是xfce和KDE/Plasma的本地功能,也不确定它是否在Unity或Mate中可用。