├── .envrc ├── icon ├── osm-revert.gif ├── osm-revert.xcf └── favicon_package_v0.16.zip ├── .env.example ├── web ├── static │ ├── img │ │ ├── favicon │ │ │ ├── 256.png │ │ │ ├── 256.webp │ │ │ ├── 480.png │ │ │ └── 480.webp │ │ └── brands │ │ │ └── openstreetmap.webp │ ├── css │ │ └── style.css │ └── js │ │ └── authorized.js ├── templates │ ├── index.jinja2 │ ├── _base.jinja2 │ └── authorized.jinja2 └── main.py ├── osm_revert ├── diff_entry.py ├── context_logger.py ├── utils.py ├── config.py ├── dmp_utils.py ├── proxy_state.py ├── osm.py ├── main.py ├── invert.py ├── overpass.py └── diff_match_patch.py ├── .vscode └── launch.json ├── README.md ├── biome.json ├── pyproject.toml ├── shell.nix ├── .gitignore └── LICENSE /.envrc: -------------------------------------------------------------------------------- 1 | # shellcheck disable=SC2148 2 | 3 | use nix 4 | -------------------------------------------------------------------------------- /icon/osm-revert.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zaczero/osm-revert/HEAD/icon/osm-revert.gif -------------------------------------------------------------------------------- /icon/osm-revert.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zaczero/osm-revert/HEAD/icon/osm-revert.xcf -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # if running standalone: 2 | OSM_TOKEN= 3 | # if running web: 4 | OSM_CLIENT= 5 | OSM_SECRET= 6 | -------------------------------------------------------------------------------- /icon/favicon_package_v0.16.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zaczero/osm-revert/HEAD/icon/favicon_package_v0.16.zip -------------------------------------------------------------------------------- /web/static/img/favicon/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zaczero/osm-revert/HEAD/web/static/img/favicon/256.png -------------------------------------------------------------------------------- /web/static/img/favicon/256.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zaczero/osm-revert/HEAD/web/static/img/favicon/256.webp -------------------------------------------------------------------------------- /web/static/img/favicon/480.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zaczero/osm-revert/HEAD/web/static/img/favicon/480.png -------------------------------------------------------------------------------- /web/static/img/favicon/480.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zaczero/osm-revert/HEAD/web/static/img/favicon/480.webp -------------------------------------------------------------------------------- /web/static/img/brands/openstreetmap.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zaczero/osm-revert/HEAD/web/static/img/brands/openstreetmap.webp -------------------------------------------------------------------------------- /osm_revert/diff_entry.py: -------------------------------------------------------------------------------- 1 | from typing import NamedTuple 2 | 3 | 4 | class DiffEntry(NamedTuple): 5 | timestamp: int 6 | element_id: str 7 | element_old: dict 8 | element_new: dict 9 | element_current: dict 10 | -------------------------------------------------------------------------------- /web/static/css/style.css: -------------------------------------------------------------------------------- 1 | abbr { 2 | color: #777; 3 | cursor: help; 4 | vertical-align: super; 5 | font-size: .8em; 6 | } 7 | 8 | button img { 9 | position: relative; 10 | top: -0.05em; 11 | } 12 | 13 | .header img { 14 | position: relative; 15 | top: -0.05em; 16 | } 17 | 18 | .required::after { 19 | content: '*'; 20 | color: #e00; 21 | font-weight: bold; 22 | } 23 | 24 | .char-counter { 25 | display: none; 26 | font-size: .8em; 27 | margin-top: .25em; 28 | text-align: end; 29 | } 30 | -------------------------------------------------------------------------------- /osm_revert/context_logger.py: -------------------------------------------------------------------------------- 1 | from asyncio import Queue 2 | from contextlib import contextmanager 3 | from contextvars import ContextVar 4 | 5 | _log_queue: ContextVar[Queue[str]] = ContextVar('log_queue') 6 | 7 | 8 | @contextmanager 9 | def context_logger(): 10 | queue: Queue[str] = Queue() 11 | token = _log_queue.set(queue) 12 | try: 13 | yield queue 14 | finally: 15 | _log_queue.reset(token) 16 | queue.shutdown() 17 | 18 | 19 | def context_print(msg: str) -> None: 20 | queue = _log_queue.get() 21 | if queue is not None: 22 | queue.put_nowait(msg) 23 | else: 24 | print(msg) 25 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "console": "integratedTerminal", 5 | "justMyCode": true, 6 | "name": "Python: main.py", 7 | "program": "${workspaceFolder}/osm_revert/main.py", 8 | "request": "launch", 9 | "type": "debugpy" 10 | }, 11 | { 12 | "args": [ 13 | "--reload", 14 | "web.main:app" 15 | ], 16 | "jinja": true, 17 | "justMyCode": true, 18 | "module": "uvicorn", 19 | "name": "Python: FastAPI", 20 | "request": "launch", 21 | "type": "debugpy" 22 | } 23 | ], 24 | "version": "0.2.0" 25 | } 26 | -------------------------------------------------------------------------------- /web/templates/index.jinja2: -------------------------------------------------------------------------------- 1 | {% extends '_base.jinja2' %} 2 | {% block head %} 3 | 7 | 8 | {% endblock %} 9 | {% block body %} 10 | 11 |