zapret-kvn/xray_fluent/updates/installer/phrases.py

138 lines
11 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Фразы окна обновления: пока идёт замена файлов, пользователю не скучно.
Наборы нарочно большие, а прощальные фразы выбираются случайно: от обновления
к обновлению текст разный. Каждая фраза не длиннее самой длинной из прежних,
чтобы окно не росло в высоту.
"""
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