138 lines
11 KiB
Python
138 lines
11 KiB
Python
"""Фразы окна обновления: пока идёт замена файлов, пользователю не скучно.
|
||
|
||
Наборы нарочно большие, а прощальные фразы выбираются случайно: от обновления
|
||
к обновлению текст разный. Каждая фраза не длиннее самой длинной из прежних,
|
||
чтобы окно не росло в высоту.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import random
|
||
|
||
WAITING = (
|
||
# Роскомнадзор-тян и ТСПУ.
|
||
"Роскомнадзор-тян отвернулась — быстро меняем файлы.",
|
||
"ТСПУ внимательно изучает этот индикатор. Пока ничего не понял.",
|
||
"Замедляем обновление до 128 кбит/с… Шутка, это не наш метод.",
|
||
"Роскомнадзор-тян снова заблокировала сама себя. Ждём, пока разберётся.",
|
||
"Вежливо обходим реестр запрещённых сайтов по широкой дуге.",
|
||
"Ограничения ограничивают. Мы — обновляемся.",
|
||
"ТСПУ-кун считает пакеты. Сбился. Начал заново.",
|
||
"Блокировка — это когда сайт есть, а зайти нельзя. Обновление — наоборот.",
|
||
"Роскомнадзор-тян пишет: «сервис деградирует». Сервис отвечает: «сама такая».",
|
||
"Откручиваем гайки там, где другие их закручивают.",
|
||
"Режем скуку на мелкие пакеты, чтобы DPI её не узнал.",
|
||
"DPI заглянул в наши файлы. Ему стало неловко, и он ушёл.",
|
||
"Роскомнадзор-тян ищет кнопку «заблокировать обновление». Кнопки нет.",
|
||
"Белые списки, чёрные списки… У нас один список — список изменений.",
|
||
"Сообщаем ТСПУ, что здесь только котики. Он верит.",
|
||
"Замедление видео вдохновило нас сделать обновление быстрым.",
|
||
"Роскомнадзор-тян устала и прилегла. Самое время.",
|
||
"Каждое обновление — минус одна нервная клетка у ТСПУ.",
|
||
"Перекладываем байты на цыпочках, чтобы не разбудить блокировку.",
|
||
"«Ресурс недоступен на территории…» — а вот и доступен.",
|
||
"Роскомнадзор-тян нажала «Запретить». Мы нажали «Обновить». Мы быстрее.",
|
||
"Учим пакеты проходить мимо ТСПУ с невозмутимым видом.",
|
||
"Суверенный интернет подождёт: тут важное обновление.",
|
||
"Ограничение скорости на это окно не распространяется.",
|
||
"Роскомнадзор-тян составляет новый реестр. Нас в нём опять забыли.",
|
||
"ТСПУ попросил передавать помедленнее — он записывает.",
|
||
"Роскомнадзор-тян пьёт чай и смотрит в другую сторону.",
|
||
"ТСПУ-кун ушёл на обед. Обед затянулся.",
|
||
"Роскомнадзор-тян переименовала блокировку в «временные неудобства».",
|
||
"ТСПУ увидел зашифрованный пакет и сделал вид, что так и было.",
|
||
"Роскомнадзор-тян пытается заблокировать слово «обновление». Безуспешно.",
|
||
"DPI смотрит на пакеты и видит только скучную погоду.",
|
||
"ТСПУ-кун записал наш адрес на бумажке. Бумажку унёс ветер.",
|
||
"Роскомнадзор-тян объявила, что всё работает штатно. Мы согласны.",
|
||
"Пакеты переоделись в обычный HTTPS. ТСПУ не узнаёт их в лицо.",
|
||
"Роскомнадзор-тян заблокировала будильник и проспала обновление.",
|
||
"ТСПУ-кун снова путает обновление с котиками. Не поправляем.",
|
||
# Серверы, ключи и маршруты.
|
||
"Xray потягивается после долгой смены и уступает место новой версии.",
|
||
"sing-box собирает чемодан с маршрутами. Ничего не забыл.",
|
||
"Подписки на месте, серверы на месте, кофе тоже на месте.",
|
||
"Маршруты аккуратно сложены, ни один пакет не потерялся.",
|
||
"Ключи от серверов лежат там же, где и лежали. Мы проверили.",
|
||
"Настройки не трогаем: они ваши, а не наши.",
|
||
"Перекладываем новые файлы, старые настройки остаются дома.",
|
||
"Туннель на время ремонта закрыт. Объезд не понадобится.",
|
||
"Шифруем скуку. Расшифровать её не сможет никто.",
|
||
"Серверы шлют привет и ждут, когда вы вернётесь.",
|
||
"Пинг до хорошего настроения — ноль миллисекунд.",
|
||
"Прокладываем свежий кабель между старой версией и новой.",
|
||
"Таблица маршрутов ровная, как по линейке.",
|
||
"Пакеты ждут в очереди и обсуждают новые возможности.",
|
||
"Сервер в Нидерландах машет рукой. Скоро снова будем на связи.",
|
||
"Ни один ключ не пострадал при обновлении.",
|
||
"Проверяем, что все серверы на своих местах. Все.",
|
||
# Просто настроение.
|
||
"Меняем колёса прямо на ходу. Аккуратно, без тряски.",
|
||
"Новая версия уже стоит в прихожей и снимает ботинки.",
|
||
"Старая версия сдаёт смену и желает удачи.",
|
||
"Раскладываем свежие файлы по полочкам.",
|
||
"Подкручиваем винтики, смазываем шестерёнки.",
|
||
"Где-то в недрах диска тихо щёлкают файлы.",
|
||
"Если прислушаться, слышно, как переезжают байты.",
|
||
"Ставим чайник. Обновление закончится раньше, чем он закипит.",
|
||
"Новая версия умылась, причесалась и почти готова.",
|
||
"Проветриваем папку с программой. Пахнет свежими файлами.",
|
||
"Старые файлы уходят на пенсию с почётом.",
|
||
"Байты переезжают без суеты, каждый на своё место.",
|
||
"Протираем пыль с кнопок, чтобы нажимались ещё приятнее.",
|
||
"Собираем новую версию, как конструктор, — без лишних деталей.",
|
||
"Все файлы построились по росту и ждут команды.",
|
||
"Новая версия разминается перед первым запуском.",
|
||
"Если что-то пойдёт не так, вернём всё как было. Но всё идёт так.",
|
||
"Кот прошёл по клавиатуре, но обновление этого даже не заметило.",
|
||
"Это окно скоро исчезнет, а программа откроется сама.",
|
||
)
|
||
|
||
DONE = (
|
||
"Готово. Роскомнадзор-тян ничего не заметила.",
|
||
"Готово. ТСПУ-кун до сих пор пересчитывает пакеты.",
|
||
"Готово. Новая версия уже на месте и ждёт вас.",
|
||
"Готово. Все настройки и серверы на своих местах.",
|
||
"Готово. Обновились быстрее, чем Роскомнадзор-тян моргнула.",
|
||
"Готово. Байты разложены, винтики закручены.",
|
||
"Готово. DPI так и не понял, что тут было.",
|
||
"Готово. Старая версия ушла на заслуженный отдых.",
|
||
"Готово. Можно снова гулять по интернету.",
|
||
"Готово. Чайник так и не успел закипеть.",
|
||
)
|
||
|
||
FAILED = (
|
||
"В этот раз Роскомнадзор-тян оказалась проворнее. Вернули всё как было.",
|
||
"Не получилось обновиться. Вернули прежнюю версию, она работает.",
|
||
"Что-то пошло не так. Старая версия на месте, ничего не сломалось.",
|
||
"Обновление споткнулось. Откатили всё назад, можно попробовать позже.",
|
||
"ТСПУ-кун в этот раз оказался внимательнее. Вернули всё как было.",
|
||
"Файлы не захотели переезжать. Оставили всё как было.",
|
||
"Новая версия не поместилась в чемодан. Вернули старую.",
|
||
"Обновиться не вышло, но прежняя версия цела и работает.",
|
||
)
|
||
|
||
|
||
def farewell(succeeded: bool, *, rng: random.Random | None = None) -> str:
|
||
"""Прощальная фраза: каждый раз своя, чтобы конец обновления не приедался."""
|
||
return (rng or random).choice(DONE if succeeded else FAILED)
|
||
|
||
|
||
class PhraseDeck:
|
||
"""Фразы в случайном порядке без повторов, пока колода не кончится."""
|
||
|
||
def __init__(self, phrases: tuple[str, ...] = WAITING, *, rng: random.Random | None = None):
|
||
self._phrases = phrases
|
||
self._rng = rng or random.Random()
|
||
self._queue: list[str] = []
|
||
self._last = ""
|
||
|
||
def next(self) -> str:
|
||
if not self._queue:
|
||
self._queue = list(self._phrases)
|
||
self._rng.shuffle(self._queue)
|
||
# Новая колода не начинается с фразы, которой кончилась прошлая.
|
||
if len(self._queue) > 1 and self._queue[-1] == self._last:
|
||
self._queue.insert(0, self._queue.pop())
|
||
self._last = self._queue.pop()
|
||
return self._last
|