mirror of
https://github.com/kuhyx/steam-backlog-enforcer.git
synced 2026-11-11 18:33:49 +01:00
kuhy 2026-11-11: itch.io unblocked, only it. A named TOTAL_BLOCK_EXEMPT_DOMAINS drops itch from the hosts section and its IPs from iptables (the exception wins on shared Cloudflare IPs). New root command total-block-refresh applies the list to a live block: hosts first, then per-rule iptables deletes, no flush. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WzxdWWzuCEg1m87jpKyRrw
67 lines
2.7 KiB
Python
67 lines
2.7 KiB
Python
"""Why a command may not run right now: the lock rules, side-effect free.
|
|
|
|
The pure half of the gate in :mod:`steam_backlog_enforcer.main._gate`: the
|
|
not-configured check, then the total gaming block, then the manual pick lock
|
|
— the order :func:`steam_backlog_enforcer.main.main` always used. It lives
|
|
outside ``main`` so the web server, which ``main`` itself loads (``main`` →
|
|
``misc`` → ``_web_server``), can ask it at import time without a cycle.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING, Final
|
|
|
|
from steam_backlog_enforcer._actions import is_manual_pick_locked
|
|
from steam_backlog_enforcer._allowed_games import active_manual_picks
|
|
from steam_backlog_enforcer._command_locks import (
|
|
_MANUAL_LOCK_EXEMPT_COMMANDS,
|
|
_TOTAL_BLOCK_EXEMPT_COMMANDS,
|
|
)
|
|
from steam_backlog_enforcer._remaining import fmt_remaining
|
|
from steam_backlog_enforcer._total_block import (
|
|
get_total_block_status,
|
|
is_total_block_active,
|
|
)
|
|
|
|
if TYPE_CHECKING:
|
|
from steam_backlog_enforcer.config import Config, State
|
|
|
|
# Usable before an API key exists: setup creates one, add-exception never
|
|
# talks to Steam, and serve hosts the web Setup page that asks for the key
|
|
# (refusing it left a fresh install with no way into the UI's setup).
|
|
UNCONFIGURED_OK: Final = frozenset(
|
|
{"setup", "add-exception", "serve", "total-block-refresh"}
|
|
)
|
|
NOT_CONFIGURED_MSG: Final = "Not configured. Run 'setup' first."
|
|
|
|
|
|
def lock_reason(command: str, config: Config, state: State | None) -> str | None:
|
|
"""Say why *command* may not run right now, without printing anything.
|
|
|
|
Args:
|
|
command: Canonical command name (never raw argv).
|
|
config: Loaded configuration.
|
|
state: Loaded state; ``None`` skips the manual-pick check, for callers
|
|
that have no state yet.
|
|
|
|
Returns:
|
|
A one-line reason, or ``None`` when the command may run.
|
|
"""
|
|
if command not in UNCONFIGURED_OK and not config.steam_api_key:
|
|
return NOT_CONFIGURED_MSG
|
|
if is_total_block_active() and command not in _TOTAL_BLOCK_EXEMPT_COMMANDS:
|
|
left = fmt_remaining(get_total_block_status().days_remaining * 86400)
|
|
allowed = ", ".join(sorted(_TOTAL_BLOCK_EXEMPT_COMMANDS))
|
|
return f"Total gaming block active ({left} left). Allowed: {allowed}."
|
|
if (
|
|
state is not None
|
|
and is_manual_pick_locked(state)
|
|
and command not in _MANUAL_LOCK_EXEMPT_COMMANDS
|
|
):
|
|
names = ", ".join(str(p["game_name"]) for p in active_manual_picks(state))
|
|
return (
|
|
f"Manual pick lock active ({names}): earn a new achievement first. "
|
|
f"Allowed: {', '.join(sorted(_MANUAL_LOCK_EXEMPT_COMMANDS))}."
|
|
)
|
|
return None
|