Compare commits

..

236 Commits

Author SHA1 Message Date
8510d49015 [+] improve logging 2025-05-14 17:21:24 +03:00
277f03594c [+] release updated cli_bootstrap 2025-04-30 15:27:01 +03:00
7f5c9f4fdb [+] improve cli_bootstrap 2025-04-30 15:22:58 +03:00
e5af828867 [+] improve toml compatibility for python 3.10 2025-04-30 10:43:11 +03:00
1faa511d15 [+] update configs 2025-04-30 09:47:30 +03:00
5190d23f09 [+] fix pyright wrapper 2025-04-29 14:12:11 +03:00
908f0cbd20 [+] add pythonpath to pyright 2025-04-29 14:01:49 +03:00
548a8bcb7a [+] release merged version 2025-04-26 14:42:03 +03:00
56c2eb1671 [m] 27-fix-http-server
1. update http-server
2025-04-26 14:40:16 +03:00
2fef63a253 [+] update auto host, http-server 2025-04-21 18:07:42 +03:00
dc39583cc6 [+] add auto addr search for public, http-server 2025-04-21 17:45:53 +03:00
a912e1b6bf [+] update http_server
1. remove ping dependency;
2025-04-19 18:10:07 +03:00
fdcd67aae6 [+] implement interfaces_index 2025-04-18 16:38:36 +03:00
799280f074 [+] add interfaces_index 2025-04-18 16:30:10 +03:00
202bf85f55 [+] partially wrap ip addr 2025-04-17 12:11:18 +03:00
7ad8e4a781 [+] fix ruff execution in cli 2025-04-14 17:32:25 +03:00
8d43813c37 [+] add linters 2025-04-12 16:22:21 +03:00
ae4fcb16f2 [+] fix ninja tests 2025-04-08 16:42:47 +03:00
7fa2a8a83c [+] update platform
1. update udev for air 2012;
  2. update commands for air 2012;
2025-04-04 12:40:09 +03:00
fa732867c3 [+] tune power management for air 2018 2025-04-01 12:40:53 +03:00
61584fedac [+] fix intel_pstate cpufreq 2025-03-31 17:35:08 +03:00
42ce6ffbff [+] update pr34
1. update m.py;
  2. add intel_pstate profile for cpufreq;
  3. build 0.1.5.0;
2025-03-31 17:15:53 +03:00
385e82bab8 [+] add dotfiles for platform macbook air 2018 2025-03-31 17:04:57 +03:00
ccb0fb09c9 [+] ad platform dotfiles 2025-03-31 17:04:56 +03:00
6d184edec8 [+] update systemd 2025-03-25 14:52:31 +03:00
6374849014 [+] migrate to systemd 2025-03-20 19:20:55 +03:00
3d023047b4 [+] update cpanel
1. fix logging;
  2. refactor into a class;
2025-03-20 19:07:34 +03:00
43c711cb2c [+] add make
1. add venv_compile;
  2. add venv;
  3. add mypy;
  4. update d1/cpanel.py
    to aggregate .ssh/known_hosts files;
  5. add systemd service for a gateway;
2025-03-20 19:03:05 +03:00
dff3782834 [+] integrate with podman 2025-03-20 17:02:18 +03:00
b399c5546c [+] update pr34
1. update katerc;
  2. add mime.types to few some source code
    as plain text in firefox;
  3. update .whl release for pr34;
  4. update commands_typed/typing.py;
2025-03-18 10:02:27 +03:00
c1e598b3ab [+] update nginx multiplexing 2025-03-15 13:40:38 +03:00
7442368b03 [+] update gateway
1. add systemd units deployment recipie;
  2. add certbot periodic task;
  3. update nginx_config.py
    to user ssl_preread_server_name
    instead of protocol, since it seems
    to be broken;
2025-03-15 12:06:52 +03:00
4cf720ee17 [+] add .whl 2025-03-13 19:35:11 +03:00
93f023dda3 [+] fix percentage 2025-03-13 19:32:17 +03:00
e06a1f4007 [+] add env for meson_setup 2025-03-13 12:04:54 +03:00
9ac87fb3df [+] update cli_bootstrap
1. generate requirements with hashes;
2025-03-12 19:16:28 +03:00
c8b6d96b01 [+] add .lock generation, fix mypy 2025-03-12 11:02:20 +03:00
cc0acd6f13 [+] add .whl 2025-03-11 14:19:42 +03:00
acf1850d70 [+] add env for ninja 2025-03-11 14:14:13 +03:00
9e117048dc [+] add parse_args 2025-03-08 18:39:35 +03:00
723c5b6677 [+] pack .whl release 2025-03-04 18:49:12 +03:00
aaf8b12549 [+] check invalid password 2025-03-04 18:39:48 +03:00
06e79d0679 [+] fix secret_check 2025-03-04 18:38:52 +03:00
ff786e3ce6 [+] update pr34
1. add dotfiles deploy via .tar.xz;
  2. update .sway/config;
  3. update test_crypto.py;
2025-03-04 15:44:20 +03:00
add9d858d8 [+] improve crypto 2025-03-03 18:00:51 +03:00
731c507b95 [+] add tests for pr34 2025-03-03 17:57:14 +03:00
62063a1448 [+] update .p43
1. partially improve crypto;
  2. fix m.py;
2025-03-03 12:53:58 +03:00
1fb4e4efc5 [+] update pr34
1. partially add crypto logic;
  2. fetch updated commands from laptop;
  3. update Makefile;
2025-03-03 09:51:26 +03:00
b12395621d [+] update desktop-services 2025-02-22 18:54:10 +03:00
905241a068 [+] update cli 2025-02-18 18:29:48 +03:00
01aab0517a [+] improve pip_resolve
1. add -r flag
    that can parse complicated
    requirements
    and format into a temp file
    for uv pip compile;
2025-01-24 21:47:43 +03:00
6ddfc7d2d7 [+] update dotfiles
1. add kate editor config;
2025-01-24 21:25:13 +03:00
3245d6d7e5 [+] add uv_pip_freeze
1. uv_pip_compile
    just a raw wrapper
    around uv pip compile --generate-hashes;
  2. uv_pip_freeze
    does compile of frozen dependencies
    with generated hashes along the way;
2025-01-24 21:15:28 +03:00
a529db106a [+] fix mypy errors 2025-01-24 21:06:26 +03:00
57f74df865 [+] fix some mypy errors 2025-01-24 18:27:51 +03:00
528d9b1ce5 [+] integrate uv pip compile 2025-01-23 12:17:07 +03:00
ebbd1a2b5b [+] raise to 0.1.4.9 2025-01-18 21:22:56 +03:00
62cfbf36cb [+] fix --hash format 2025-01-18 21:13:26 +03:00
d643e8f97b [+] improve pip_resolve
1. do not download anything;
  2. provide hashes per dependency;
  3. test that works on numpy
2025-01-18 20:56:03 +03:00
9b5fff93c0 [+] add pip_resolve
1. add freezing packages based on pip resolver;
  1.1. the command
    should resolve final packages with versions,
    and provide constraints with file hashes;
    to act alike go mod tool;
2025-01-18 19:34:46 +03:00
ff22d9311b [+] update
1. fix python3.13 regression
    with class property;
  2. update books dependency;
2025-01-18 12:43:28 +03:00
759ce361e3 [+] fix .gitmodules 2025-01-12 18:23:47 +03:00
136b5709b0 [+] refactor book1
1. move book1 into a private repo;
2025-01-12 18:20:19 +03:00
584b4b652f [+] add submodule books 2025-01-12 11:02:29 +03:00
7d1d887692 [+] update keybindigs 2025-01-02 10:42:58 +03:00
212c8c8086 [+] improve deploy:wheel command 2025-01-01 02:19:40 +03:00
6599115a68 [+] 0.1.4.7, improve os module
1. add runtime initialization;
    works for .so files;
    linux platform only at the moment;
2024-12-30 15:03:45 +03:00
22f5f0fba3 [+] raise 0.1.4.1 2024-12-29 14:44:07 +03:00
c9382162de [+] update cli logic
1. add pip_sync method;
  1.1. rely on -f flag
    of pip to use a custom cache dir;
2024-12-29 14:36:30 +03:00
0cee9beaea [+] improve mypy step while deploy:wheel 2024-12-22 21:07:05 +03:00
93437359a8 [+] fix mypy errors 2024-12-22 21:02:35 +03:00
9c8b554acc [+] update pr34
1. update dependencies handling
    during venv creation;
  2. update cli and cli_boostrap modules;
2024-12-22 20:45:46 +03:00
adc3fd0205 [+] fix mypy errors 2024-12-22 19:18:06 +03:00
48ef23aa88 [+] update vscode dot files 2024-12-22 18:38:29 +03:00
1626974759 [+] update packaging
1. update cli and cli_bootstrap;
  1.1. use /meson and /pyproject
    build dirs to fix collision
    for install step;
2024-12-22 18:33:06 +03:00
ea63c67280 [+] update cli module; 2024-12-22 12:06:07 +03:00
34c65f7ba5 [+] update commands
1. add basic cli.py module;
  2. add stubs for debugpy;
2024-12-22 10:31:31 +03:00
dedff2aee5 [+] update repo 2024-12-12 17:03:33 +03:00
cb69309307 [+] update repo
1. add asyncio.handle_task_result;
  2. improve pass_ssh_osx;
  3. update vpn dependency;
2024-12-10 20:28:00 +03:00
0a50c26d1d [+] add qrcode mode for pass ssh osx 2024-12-05 09:03:22 +03:00
a6cdf03523 [+] fix exit status for commands
1. fix intercept_output when the process has died
    before select poll has been started;
2024-12-04 20:28:20 +03:00
eb457950d3 [+] add launch.json 2024-12-04 19:04:06 +03:00
4afe4048d9 [+] update debugging
1. disable telemtry in ms-python;
  1.1. TODO, use a forked version of the plugin;
  2. add debug module into pr34;
  3. enable show strack frame for all .py files;
2024-12-04 19:01:30 +03:00
74cc54ae85 [~] update vpn 2024-12-03 19:07:43 +03:00
fd0dbb0c4a [+] update vpn dependency 2024-12-03 09:25:42 +03:00
d0b696206c [r] update versions of pip packages 2024-12-03 09:21:45 +03:00
92966ca86d [~] Refactor 2024-12-03 09:17:16 +03:00
d38022b5a6 [+] update packaging 2024-12-01 18:49:12 +03:00
796fb51ad9 [~] Refactor 2024-12-01 09:04:58 +03:00
b32b058083 [~] Refactor 2024-12-01 08:49:34 +03:00
d3d5e3bcfb [~] Refactor 2024-11-30 18:59:22 +03:00
64706907ca [~] Refactor 2024-11-29 21:17:34 +03:00
8656b3b985 [~] Refactor 2024-11-28 12:24:38 +03:00
1cfc6c52f3 [~] Refactor 2024-11-25 16:56:28 +03:00
62f4d9f948 [~] Refactor 2024-11-25 12:41:06 +03:00
5c69e922a7 [~] Refactor 2024-11-24 22:47:42 +03:00
27af208437 [~] Refactor 2024-11-24 22:35:54 +03:00
fadd95cef3 [~] Refactor 2024-11-24 19:54:24 +03:00
bd9878335a [~] add host_deps command 2024-11-24 19:47:36 +03:00
cadec5376a [~] Refactor 2024-11-24 19:34:24 +03:00
0ef9268f48 [~] Refactor 2024-11-24 02:28:19 +03:00
60929176ef [~] Refactor 2024-11-24 00:26:23 +03:00
0d9e225a76 [~] Refactor 2024-11-23 23:56:23 +03:00
3321e4c165 [~] Refactor 2024-11-23 23:51:06 +03:00
dffcb96358 [~] Refactor 2024-11-22 23:13:18 +03:00
fc18a91f63 [~] Refactor 2024-11-22 23:11:57 +03:00
34c3ed74eb [~] Refactor 2024-11-22 23:08:18 +03:00
2522ed4ac4 [~] Refactor 2024-11-22 22:51:31 +03:00
6d1c845d74 [~] Refactor 2024-11-22 21:24:07 +03:00
83b1177f85 [~] Refactor 2024-11-21 10:17:37 +03:00
9620bb2b25 [~] Refactort 2024-11-15 20:57:06 +03:00
f9f18df737 [~] Refactor 2024-11-15 20:47:41 +03:00
14b499637b [~] Refactor 2024-11-15 20:47:41 +03:00
40350d128a [~] Refactor 2024-11-15 20:47:40 +03:00
1eecc616f5 [~] Refactor 2024-11-15 20:47:40 +03:00
c4944ede7f [~] Refactor 2024-11-15 20:47:40 +03:00
43985cd5b0 [~] Refactor 2024-11-15 20:47:40 +03:00
ed347e1d21 [~] Refactor 2024-11-15 20:47:40 +03:00
32579007e4 [~] Refactor 2024-11-15 20:47:40 +03:00
82a7c62ca8 [~] Refactor 2024-11-15 20:47:40 +03:00
de05d2cd05 [~] Refactor 2024-11-15 20:47:40 +03:00
723ad56ca9 [~] Refactor 2024-11-15 20:47:40 +03:00
eb310ceef7 [~] Refactor 2024-11-15 20:47:40 +03:00
81bf066e82 [~] Refactor 2024-11-15 20:47:40 +03:00
560e748867 [~] Refactor 2024-11-02 12:26:03 +03:00
48ce6c87a6 [~] Refactor 2024-09-30 23:29:37 +03:00
58a1e5f1be [~] Refactor 2024-09-30 22:27:35 +03:00
62b809bd3c [~] Refactor 2024-09-30 22:26:50 +03:00
6b7bef9c07 [~] Refactor 2024-09-22 17:43:24 +03:00
16a075b19c [~] Refactor 2024-09-18 00:00:51 +03:00
92fe90b042 [~] Refactor 2024-09-08 21:52:10 +03:00
a7f5be4c8e [~] Refactor 2024-08-24 12:42:13 +03:00
392faf5526 [~] Refactor 2024-08-24 12:40:15 +03:00
fd6378a643 [~] Refactor 2024-08-24 12:26:16 +03:00
32ee4316f1 [~] Refactor 2024-08-17 11:25:08 +03:00
1140a46799 [~] Refactor 2024-08-17 11:21:05 +03:00
1ad4fab099 [~] Refactor 2024-08-17 11:18:09 +03:00
edea7a4fab [~] Refactor 2024-08-17 11:13:14 +03:00
e5cb3bbb53 [~] Refactor 2024-08-17 11:04:36 +03:00
f4f214d75b [~] Refactor 2024-08-17 11:01:39 +03:00
27be8c3104 [~] Refactor 2024-08-17 10:46:51 +03:00
c95503fa76 [~] Refactor 2024-08-17 10:46:18 +03:00
ce77de626c [~] Refactor 2024-08-17 10:44:30 +03:00
f2b8862683 [~] Refactor 2024-08-17 10:22:22 +03:00
8dbedd9c28 [~] Refactor 2024-08-17 10:04:32 +03:00
a9393dbff2 [~] Refactor 2024-08-17 10:02:25 +03:00
4ed4dbcbdb [~] Refactor 2024-08-17 09:47:31 +03:00
d0177e7255 [~] Refactor 2024-08-17 09:43:40 +03:00
10be7dc897 [~] Refactor 2024-08-17 09:26:59 +03:00
d7d4260053 [~] Refactor 2024-08-17 09:23:03 +03:00
d4ef7d5ba4 [~] Refactor 2024-08-17 09:16:35 +03:00
b5343c1375 [~] Refactor 2024-08-17 09:10:16 +03:00
a9e8d8a505 [~] Refactor 2024-08-17 09:07:49 +03:00
de292518a5 [~] Refactor 2024-08-17 09:05:15 +03:00
3e9708d442 [~] Refactor 2024-08-17 08:53:54 +03:00
9ad2030f36 [~] Refactor 2024-08-17 01:15:07 +03:00
aa8d84614c [~] Refactor 2024-08-17 01:08:58 +03:00
13f0899b90 [~] Refactor 2024-08-17 00:50:24 +03:00
2385012e35 [~] Refactor 2024-08-17 00:38:20 +03:00
2b3305ab56 [~] Refactor 2024-08-17 00:37:29 +03:00
a67d765569 [~] Refactor 2024-08-17 00:29:20 +03:00
3163641646 [~] Refactor 2024-08-16 17:43:29 +03:00
d06a7655d7 [~] Refactor 2024-08-16 17:24:14 +03:00
ac7515f49d [~] Refactor 2024-08-14 23:49:04 +03:00
d3718cf271 [~] Refactor 2024-08-14 23:45:17 +03:00
45d0be60f9 [~] Refactor 2024-08-14 23:35:01 +03:00
03164b8e34 [~] Refactor 2024-08-14 23:32:53 +03:00
bd89fff408 [~] Refactor 2024-08-14 23:29:10 +03:00
7444095e03 [~] Refactor 2024-08-14 23:17:43 +03:00
1018ad3266 [~] Refactor 2024-08-12 23:19:21 +03:00
d6f5817c78 [~] Refactor 2024-08-12 23:16:10 +03:00
1e55e7baac [~] Refactor 2024-08-12 23:13:56 +03:00
b9297f6863 [~] Refactor 2024-08-12 23:02:41 +03:00
ae897835b2 [~] Refactor 2024-08-12 23:01:51 +03:00
633e1c6424 [~] Refactor 2024-08-12 22:59:56 +03:00
d782fbfbf2 [~] Refactor 2024-08-12 21:35:42 +03:00
aead4c165d [~] Refactor 2024-08-12 21:33:40 +03:00
d50f17eb76 [~] Refactor 2024-08-12 21:31:08 +03:00
f656d94fa3 [~] Refactor 2024-08-12 03:02:30 +03:00
b6192902ff [~] Refactor 2024-08-12 02:56:40 +03:00
d5c616806a [~] Refactor 2024-08-12 02:54:11 +03:00
184340db4f [~] Refactor 2024-08-12 02:45:33 +03:00
58071843be [~] Refactor 2024-08-12 02:44:10 +03:00
b93ee0b7e4 [~] Refactor 2024-08-12 02:42:12 +03:00
71c793cbae [~] Refactor 2024-08-12 02:29:33 +03:00
5c271c518f [~] Refactor 2024-08-12 02:28:10 +03:00
4909d474b1 [~] Refactor 2024-08-12 02:27:11 +03:00
430b517ce7 [~] Refactor 2024-08-12 02:24:25 +03:00
11a3c59961 [~] Refactor 2024-08-12 02:22:28 +03:00
c16f389324 [~] Refactor 2024-08-12 02:20:46 +03:00
4758032a35 [~] Refactor 2024-08-12 02:18:47 +03:00
c1b7bb71b3 [~] Refactor 2024-08-12 02:11:26 +03:00
8ec95247f9 [~] Refactor 2024-08-12 02:08:54 +03:00
b3156b5093 [~] Refactor 2024-08-12 01:09:24 +03:00
f93b604c51 [~] Refactor 2024-08-12 00:39:06 +03:00
437e073411 [~] Refactor 2024-08-12 00:35:31 +03:00
99bc0d5ab1 [~] Refactor 2024-08-12 00:25:08 +03:00
42bfe00ee5 [~] Refactor 2024-08-12 00:23:40 +03:00
45626d85d4 [~] Refactor 2024-08-12 00:12:58 +03:00
cf849b1009 [~] Refactor 2024-08-12 00:09:51 +03:00
c867c7d828 [~] Refactor 2024-08-12 00:07:23 +03:00
0d7c0d9d09 [~] Refactor 2024-08-12 00:03:35 +03:00
9725a1493c [~] Refactor 2024-08-11 23:59:45 +03:00
15611baed2 [~] Refactor 2024-08-11 23:53:12 +03:00
010b426b03 [~] Refactor 2024-08-11 23:50:50 +03:00
826aec8f3f [~] Refactor 2024-08-11 23:37:47 +03:00
4b93c33d66 [~] Refactor 2024-08-11 23:31:41 +03:00
495e901a23 [~] Refactor 2024-08-11 23:25:02 +03:00
29053ceb5d [~] Refactor 2024-08-11 23:23:57 +03:00
1411dc60e5 [~] Refactor 2024-08-11 23:22:43 +03:00
12c55aa0e8 [~] Refactor 2024-08-11 23:20:45 +03:00
508c55bd68 [~] Refactor 2024-08-11 00:38:49 +03:00
c57b449f69 [~] Refactor 2024-08-11 00:34:39 +03:00
45945c0894 [~] Refactor 2024-08-11 00:30:25 +03:00
fb8b741ca0 [~] Refactor 2024-08-11 00:29:14 +03:00
e6038b7060 [~] Refactor 2024-08-11 00:25:15 +03:00
e1aa8edd42 [~] Refactor 2024-08-11 00:14:10 +03:00
39fa0f23ea [~] Refactor 2024-08-11 00:10:20 +03:00
852c15635f [~] Refactor 2024-08-11 00:00:08 +03:00
b1339cad6b [~] Refactor 2024-08-10 23:55:35 +03:00
01a09989ef [~] Refactor 2024-08-10 23:52:53 +03:00
f2926b6f2b [~] Refactor 2024-08-10 22:07:39 +03:00
e60308a28d [~] Refactor 2024-08-10 21:54:29 +03:00
b8b2443c2a [~] Refactor 2024-08-10 21:52:41 +03:00
3f49dd337f [~] Refactor 2024-08-10 21:51:10 +03:00
331e11d728 [~] Refactor 2024-08-10 21:49:26 +03:00
3b2dd8045e [~] Refactor 2024-08-10 21:37:33 +03:00
bbcf3fb16d [~] Refactor 2024-08-10 21:33:29 +03:00
25c9f86ef0 [~] Refactor 2024-08-10 21:32:28 +03:00
16cfa6c481 [~] Refactor 2024-08-10 21:30:58 +03:00
04f8dca7e6 [~] Refactor 2024-08-10 21:19:59 +03:00
a7993b8a82 [~] Refactor 2024-08-10 21:18:59 +03:00
c00d06368f [~] Refactor 2024-08-10 21:18:34 +03:00
b4836b6514 [~] Refactor 2024-08-10 21:16:52 +03:00
11cd349a7e [~] Refactor 2024-08-10 21:11:45 +03:00
34ae744866 [~] Refactor 2024-08-10 21:09:55 +03:00
135 changed files with 22065 additions and 6878 deletions

2
.gitattributes vendored Normal file

@ -0,0 +1,2 @@
releases/tar/** filter=lfs diff=lfs merge=lfs -text
releases/whl/** filter=lfs diff=lfs merge=lfs -text

12
.gitignore vendored

@ -3,3 +3,15 @@ __pycache__
d2/book1/books d2/book1/books
.DS_Store .DS_Store
.vim .vim
*.so
.mypy_cache
.ruff_cache
.tmuxp
*.egg-info
*.whl
*.tar.gz
.vscode/*
!.vscode/launch.json
python/build
.*.kate-swp
!releases/whl/*.whl

6
.gitmodules vendored

@ -16,3 +16,9 @@
[submodule "deps/melianmiko-mb7-apps"] [submodule "deps/melianmiko-mb7-apps"]
path = deps/melianmiko-mb7-apps path = deps/melianmiko-mb7-apps
url = https://notabug.org/melianmiko/mb7_apps url = https://notabug.org/melianmiko/mb7_apps
[submodule "deps/com.github.aiortc.aiortc"]
path = deps/com.github.aiortc.aiortc
url = https://gitea.fxreader.online/nartes/com.github.aiortc.aiortc
[submodule "deps/online.fxreader.nartes.books"]
path = deps/online.fxreader.nartes.books
url = https://gitea.fxreader.online/nartes/books.git

18
.mypy.ini Normal file

@ -0,0 +1,18 @@
[mypy]
mypy_path =
mypy-stubs,
deps/com.github.aiortc.aiortc/src,
mypy-stubs/marisa-trie-types,
mypy-stubs/types-debugpy,
python
exclude =
python/tmp,
python/build
plugins =
numpy.typing.mypy_plugin,
pydantic.mypy
explicit_package_bases = true
namespace_packages = true

49
.vscode/launch.json vendored Normal file

@ -0,0 +1,49 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
/*
{
"name": "Python Debugger: Module",
"type": "debugpy",
"request": "launch",
"module": "online_fxreader.vpn.vpn",
},
{
"name": "Python Debugger: Current File with Arguments",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"args": [
"${command:pickArgs}"
]
},
*/
{
"name": "Python Debugger: Remote Attach",
"type": "debugpy",
"request": "attach",
"connect": {
"host": "127.0.0.1",
"port": 4444
},
"pathMappings": [
/*
{
"localRoot": "${workspaceFolder}/deps/com.github.aiortc.aiortc/src/",
//"remoteRoot": "."
"remoteRoot": "~/.local/bin/env3/lib/python3.12/site-packages/",
},
{
"localRoot": "${workspaceFolder}/deps/com.github.aiortc.aiortc/",
//"remoteRoot": "."
"remoteRoot": "~/.local/bin/env3/lib/python3.12/site-packages/",
}
*/
]
}
]
}

141
Makefile Normal file

@ -0,0 +1,141 @@
.PHONY: python_clean_online_fxreader_vpn
host_deps:
./m.py host_deps
python_lint:
./m.py mypy -- -f vscode 2>&1 | less
python_tests:
./m.py tests
#python_clean_online_fxreader_vpn:
# rm -fr \
# deps/com.github.aiortc.aiortc/src/online_fxreader/vpn/dist;
PYTHON_PROJECTS ?= \
deps/com.github.aiortc.aiortc/ \
deps/com.github.aiortc.aiortc/src/online_fxreader/vpn/ \
python
INSTALL_ROOT ?= ~/.local/bin
#python_clean: python_clean_online_fxreader_vpn
python_clean_env:
rm -fr \
$(INSTALL_ROOT)/env3;
python_put_env:
[[ -d $(INSTALL_ROOT)/env3 ]] || (\
uv venv --system-site-packages --seed $(INSTALL_ROOT)/env3 && \
$(INSTALL_ROOT)/env3/bin/python3 -m pip install --force-reinstall uv \
);
python_clean_dist:
for o in $(PYTHON_PROJECTS); do \
[[ -d $$o/dist ]] || continue; \
echo $$o/dist; \
rm -fr $$o/dist; \
done
python_clean: python_clean_dist python_clean_env
UV_ARGS ?= --offline
python_put_dist:
for f in \
$(PYTHON_PROJECTS); do \
[[ -d $$f/dist ]] && continue; \
echo $$f; \
python3 -m build -n $$f; \
$(INSTALL_ROOT)/env3/bin/python3 -m uv pip install $(UV_ARGS) $$f/dist/*.whl; \
done
ln -sf $(INSTALL_ROOT)/env3/bin/online-fxreader-pr34-commands $(INSTALL_ROOT)/commands
PYTHON_PROJECTS_NAMES ?= online.fxreader.pr34
python_whl:
for f in $(PYTHON_PROJECTS_NAMES); do \
./m.py deploy:wheel -o releases/whl -p $$f; \
done
python_put: python_put_dist python_put_env
dotfiles_put:
mkdir -p $(INSTALL_ROOT)
cp dotfiles/.local/bin/gnome-shortcuts-macbook-air $(INSTALL_ROOT)/
mkdir -p ~/.sway
cp dotfiles/.sway/config ~/.sway/config
cp dotfiles/.zshenv ~/.zshenv
cp dotfiles/.zshrc ~/.zshrc
cp dotfiles/.vimrc ~/.vimrc
cp dotfiles/.tmux.conf ~/.tmux.conf
cp dotfiles/.py3.vimrc ~/.py3.vimrc
cp dotfiles/.py3.vimrc ~/.py3.vimrc
cp dotfiles/.gitconfig ~/.gitconfig
cp -rp \
dotfiles/.ipython/profile_default/ipython_config.py \
~/.ipython/profile_default/ipython_config.py
D1=Code\ -\ OSS; \
for p in \
"dotfiles/.config/$$D1/User/keybindings.json" \
"dotfiles/.config/$$D1/User/settings.json"; do \
commands install -f -p "dotfiles/.config/$$D1" -s "$$p" -t ~/.config/"$$D1"; \
done
#commands install -f -p dotfiles -s dotfiles/ -t ~/.config/
PLATFORM ?= macbook_air_2012
PLATFORM_TMP ?= tmp/platform_dotfiles/$(PLATFORM)
dotfiles_put_platform:
@echo to be installed
find platform_dotfiles/$(PLATFORM);
echo remove $(PLATFORM_TMP)'?'; read; sudo rm -fr $(PLATFORM_TMP)
sudo mkdir -p $(PLATFORM_TMP)
sudo cp -rp -T platform_dotfiles/$(PLATFORM)/ $(PLATFORM_TMP)
sudo chown -R root:root $(PLATFORM_TMP)
sudo cp -rp -T $(PLATFORM_TMP) /
sudo udevadm control --reload
sudo systemctl daemon-reload
dotfiles_fetch:
commands install -f -p ~ -s ~/.config/katerc -t dotfiles
commands install -f -p ~ -s ~/.mime.types -t dotfiles
commands install -f -p ~ -s ~/.config/rofi/config.rasi -t dotfiles
commands install -f -p ~ -s ~/.config/Code\ -\ OSS/User/keybindings.json -t dotfiles
commands install -f -p ~ -s ~/.config/Code\ -\ OSS/User/settings.json -t dotfiles
DOTFILES_VERSION ?= 0.1
dotfiles_deploy:
mkdir -p releases/tar
tar -cvf - \
dotfiles \
| xz --compress -9 --stdout > \
releases/tar/dotfiles-$(DOTFILES_VERSION).tar.xz
systemd:
/usr/bin/env python3 d1/systemd.py
for d in tmp/d1; do \
(\
cd $$d; \
for i in *.service *.timer; do \
sudo ln -s -f $$PWD/$$i /etc/systemd/system/$$i; \
done; \
); \
done
sudo systemctl daemon-reload
venv:
uv venv
uv pip install -p .venv \
-r requirements.txt
venv_compile:
uv pip compile --generate-hashes \
requirements.in > requirements.txt
MYPY_SOURCES ?= \
d1/cpanel.py
mypy:
. .venv/bin/activate && \
mypy --strict --follow-imports silent \
$(MYPY_SOURCES)

19
d1/certbot.py Normal file

@ -0,0 +1,19 @@
#!/usr/bin/env python3
import subprocess
import time
import logging
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
while True:
subprocess.check_call([
'docker', 'compose', 'exec', 'ssl-app', 'certbot', 'renew',
])
subprocess.check_call([
'docker', 'compose', 'exec', 'ssl-app', 'nginx', '-s', 'reload',
])
break

@ -1,4 +1,5 @@
import subprocess import subprocess
import os
import requests import requests
import sys import sys
import io import io
@ -10,103 +11,131 @@ import logging
import json import json
import time import time
with io.open( logger = logging.getLogger(__name__)
'tmp/d1/cpanel.json', 'r'
) as f:
t3 = json.load(f)
t2 = copy.deepcopy(t3)
for k in t2:
v = t2[k]
v['task'] = lambda : subprocess.Popen(
v['task_cmd'],
stdin=subprocess.DEVNULL,
)
def stop_task(task): class Launcher:
task.terminate() def run(self):
try: logging.basicConfig(level=logging.INFO)
task.wait(1)
except:
task.kill()
t1 = dict() with io.open(
'tmp/d1/cpanel.json', 'r'
) as f:
t3 = json.load(f)
shutdown = False t2 = copy.deepcopy(t3)
ssh_known_hosts : list[str] = []
while True:
try:
for k, v in t2.items(): for k, v in t2.items():
if not k in t1: if 'ssh_known_hosts' in v:
logging.info(json.dumps(dict( ssh_known_hosts.append(v['ssh_known_hosts'])
task=k,
status='starting',
)))
t1[k] = v['task']()
logging.info(json.dumps(dict(
task=k,
status='started',
)))
continue
o = t1[k] if len(ssh_known_hosts) > 0:
subprocess.check_call(
r'''
mkdir -p ~/.ssh && \
cat $SSH_KNOWN_HOSTS > ~/.ssh/known_hosts
''', env=dict(list(os.environ.items())) | dict(
SSH_KNOWN_HOSTS=' '.join(ssh_known_hosts),
),
shell=True
)
not_alive = None for k in t2:
v = t2[k]
v['task'] = lambda : subprocess.Popen(
v['task_cmd'],
stdin=subprocess.DEVNULL,
)
def stop_task(task: subprocess.Popen[bytes]) -> None:
task.terminate()
try: try:
not_alive = not ( task.wait(1)
requests.get(v['url'], timeout=0.5).status_code
== 200
)
except: except:
logging.error(json.dumps(dict( task.kill()
error=traceback.format_exc(),
time_iso=datetime.datetime.now().isoformat(),
)))
not_alive = True
if not_alive: t1 = dict()
logging.error(json.dumps(
dict(
args=o.args,
k=k,
#o=pprint.pformat(o.__dict__),
status='not_alive',
time_iso=datetime.datetime.now().isoformat(),
)
))
#stop_task(o) shutdown = False
#del t1[k]
continue
if not o.poll() is None: while True:
logging.error(json.dumps( try:
dict( for k, v in t2.items():
#o=pprint.pformat(o.__dict__), if not k in t1:
args=o.args, logging.info(json.dumps(dict(
k=k, task=k,
return_code=o.poll(), status='starting',
status='crashed', )))
time_iso=datetime.datetime.now().isoformat(), t1[k] = v['task']()
) logging.info(json.dumps(dict(
)) task=k,
del t1[k] status='started',
continue )))
continue
if shutdown: o = t1[k]
break
print('\r%s tasks %d' % ( not_alive = None
datetime.datetime.now().isoformat(),
len(t1),
), end='')
sys.stdout.flush()
except KeyboardInterrupt:
print('\nshutting down')
break
finally:
time.sleep(5 * 60)
for o in t1: try:
stop_task(o) not_alive = not (
requests.get(v['url'], timeout=0.5).status_code
== 200
)
except:
logging.error(json.dumps(dict(
error=traceback.format_exc(),
time_iso=datetime.datetime.now().isoformat(),
)))
not_alive = True
if not_alive:
logging.error(json.dumps(
dict(
args=o.args,
k=k,
#o=pprint.pformat(o.__dict__),
status='not_alive',
time_iso=datetime.datetime.now().isoformat(),
)
))
#stop_task(o)
#del t1[k]
continue
if not o.poll() is None:
logging.error(json.dumps(
dict(
#o=pprint.pformat(o.__dict__),
args=o.args,
k=k,
return_code=o.poll(),
status='crashed',
time_iso=datetime.datetime.now().isoformat(),
)
))
del t1[k]
continue
if shutdown:
break
print('\r%s tasks %d' % (
datetime.datetime.now().isoformat(),
len(t1),
), end='')
sys.stdout.flush()
except KeyboardInterrupt:
print('\nshutting down')
break
finally:
time.sleep(5 * 60)
for o in t1:
stop_task(o)
if __name__ == '__main__':
Launcher().run()

@ -1,15 +0,0 @@
#!/bin/sh
mkdir -p ~/.local/bin
cp dotfiles/.local/bin/commands ~/.local/bin/commands
mkdir -p ~/.sway
cp dotfiles/.sway/config ~/.sway/config
cp dotfiles/.zshenv ~/.zshenv
cp dotfiles/.zshrc ~/.zshrc
cp dotfiles/.vimrc ~/.vimrc
cp dotfiles/.py3.vimrc ~/.py3.vimrc
cp dotfiles/.py3.vimrc ~/.py3.vimrc
cp dotfiles/.gitconfig ~/.gitconfig
cp -rp \
dotfiles/.ipython/profile_default/ipython_config.py \
~/.ipython/profile_default/ipython_config.py

@ -0,0 +1,11 @@
[Unit]
Description=fxreader.online-certbot
[Service]
Type=oneshot
ExecStart=/usr/bin/python3 d1/certbot.py
WorkingDirectory={{PROJECT_ROOT}}
#Restart=always
#[Install]
#WantedBy=multi-user.target

@ -0,0 +1,9 @@
[Unit]
Description=fxreader.online-certbot-timer
[Timer]
OnUnitActiveSec=1d
OnBootSec=1m
[Install]
WantedBy=timers.target

@ -0,0 +1,16 @@
[Unit]
Description=fxreader.online-service
Requires=docker.service
After=docker.service
[Service]
#Type=oneshot
ExecStart=/usr/bin/docker compose up --force-recreate --remove-orphans
ExecStop=/usr/bin/docker compose down
WorkingDirectory={{PROJECT_ROOT}}
StandardOutput=null
StandardError=null
Restart=always
[Install]
WantedBy=multi-user.target

@ -43,9 +43,23 @@ def forward(
else: else:
server_name = 'default_server' server_name = 'default_server'
if not server_name in sections: if (
not server_name in sections
):
sections[server_name] = [] sections[server_name] = []
if 'client_max_body_size' in entry:
client_max_body_size = entry['client_max_body_size']
else:
client_max_body_size = '50M'
assert isinstance(client_max_body_size, str)
sections[server_name].append(
r'''
client_max_body_size %s;
''' % client_max_body_size
)
location_get = lambda location_body, location_path2, prefix=None,: ( location_get = lambda location_body, location_path2, prefix=None,: (
r''' r'''
@ -138,7 +152,7 @@ server {
server_name {server_name}; server_name {server_name};
listen 80 {default_server}; listen 80 {default_server};
client_max_body_size 50M; #client_max_body_size 50M;
{sections_config} {sections_config}
} }
@ -199,6 +213,80 @@ def ssl(input_json, output_conf):
servers = [] servers = []
if 'stream_server' in ssl_nginx:
upstream_servers = []
server_names = []
if 'by_server_name' in ssl_nginx['stream_server']:
for k, v in ssl_nginx['stream_server']['by_server_name'].items():
upstream_servers.append(
'upstream %s { server %s; }' % (
v['upstream_name'],
v['url'],
)
)
server_names.append(
'"%s" %s;' % (
v['server_name'], v['upstream_name'],
)
)
if 'ssh' in ssl_nginx['stream_server']:
ssh_section = 'upstream ssh { server {ssh}; }'.replace(
'{ssh}',
ssl_nginx['stream_server']['ssh'],
)
else:
ssh_section = ''
ssl_port = 444
stream_server = r'''
stream {
upstream web {
server 127.0.0.1:444;
}
{upstream_servers}
{ssh_section}
map $ssl_preread_protocol $upstream_protocol {
default ssh;
"TLSv1.2" $upstream_server_name;
"TLSv1.3" $upstream_server_name;
}
map $ssl_preread_server_name $upstream_server_name {
default web;
{server_names}
}
# SSH and SSL on the same port
server {
listen 443;
ssl_preread on;
proxy_pass $upstream_protocol;
}
}
'''.replace(
'{upstream_servers}', ''.join([
' ' + o + '\n'
for o in upstream_servers
]),
).replace(
'{ssh_section}', ssh_section,
).replace(
'{server_names}', ''.join([
' ' + o + '\n'
for o in server_names
]),
)
else:
stream_server = ''
ssl_port = 443
if 'default_server' in ssl_nginx: if 'default_server' in ssl_nginx:
server = ssl_nginx['default_server'] server = ssl_nginx['default_server']
@ -211,7 +299,7 @@ server {
set $t1 $http_x_forwarded_for; set $t1 $http_x_forwarded_for;
} }
listen 443 ssl default_server; listen {ssl_port} ssl default_server;
server_name _; server_name _;
client_max_body_size {client_max_body_size}; client_max_body_size {client_max_body_size};
@ -227,6 +315,8 @@ server {
'{client_max_body_size}', server['client_max_body_size'], '{client_max_body_size}', server['client_max_body_size'],
).replace( ).replace(
'{domain_key}', server['domain_key'], '{domain_key}', server['domain_key'],
).replace(
'{ssl_port}', '%d' % ssl_port,
) )
) )
@ -264,7 +354,7 @@ server {
set $t1 $http_x_forwarded_for; set $t1 $http_x_forwarded_for;
} }
listen 443 ssl; listen {ssl_port} ssl;
server_name {server_names}; server_name {server_names};
client_max_body_size {client_max_body_size}; client_max_body_size {client_max_body_size};
@ -291,20 +381,27 @@ server {
'{client_max_body_size}', server['client_max_body_size'], '{client_max_body_size}', server['client_max_body_size'],
).replace( ).replace(
'{domain_key}', server['domain_key'], '{domain_key}', server['domain_key'],
).replace(
'{ssl_port}', '%d' % ssl_port,
) )
) )
with io.open( with io.open(
output_conf, output_conf,
'w' 'w'
) as f: ) as f:
f.write( f.write(
r''' r'''
load_module "modules/ngx_stream_module.so";
events { events {
multi_accept on; multi_accept on;
worker_connections 64; worker_connections 64;
} }
{stream_server}
http { http {
log_format main log_format main
'[$time_local][$remote_addr:$remote_port, $http_x_forwarded_for, $t1, $http_host]' '[$time_local][$remote_addr:$remote_port, $http_x_forwarded_for, $t1, $http_host]'
@ -325,7 +422,9 @@ http {
'' close; '' close;
} }
} }
'''.replace('{servers}', '\n'.join(servers)) '''\
.replace('{servers}', '\n'.join(servers)) \
.replace('{stream_server}', stream_server)
) )

41
d1/systemd.py Normal file

@ -0,0 +1,41 @@
#!/usr/bin/env python3
import os
import pathlib
import io
import glob
import subprocess
import logging
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
cache_path = pathlib.Path.cwd() / 'tmp'
project_root = pathlib.Path.cwd()
logger.info(dict(project_root=project_root, cache_path=cache_path,))
for service in [
pathlib.Path(o) for o in sum([
glob.glob('d1/*.service'),
glob.glob('d1/*.timer')
], [])
]:
os.makedirs(str((cache_path / service).parent), exist_ok=True)
with io.open(str(service), 'r') as f:
with io.open(
str(cache_path / service), 'w'
) as f2:
f2.write(
f.read().replace(
'{{PROJECT_ROOT}}',
str(project_root),
)
)
logger.info(dict(
service=str(service),
msg='updated',
))

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

@ -1,77 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<script
src="https://code.jquery.com/jquery-3.6.0.slim.min.js"
integrity="sha256-u7e5khyithlIdTpu22PHhENmPcRdFiHRjhAuHcs05RI="
crossorigin="anonymous"
></script>
<title>Speech synthesiser</title>
<script>
window.context = {};
window.context.books = [];
</script>
<script src="NoSleep.min.js"></script>
<script src="script.js"></script>
<script src="book.js"></script>
<link rel="stylesheet" href="style.css">
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class=voice-settings>
<h1>Speech synthesiser</h1>
<p>Enter some text in the input below and press return or the "play" button to hear it. change voices using the dropdown menu.</p>
<form>
<input type="text" class="txt">
<div>
<label for="rate">Rate</label><input type="range" min="0.5" max="2" value="1" step="0.1" id="rate">
<div class="rate-value">1</div>
<div class="clearfix"></div>
</div>
<div>
<label for="pitch">Pitch</label><input type="range" min="0" max="2" value="1" step="0.1" id="pitch">
<div class="pitch-value">1</div>
<div class="clearfix"></div>
</div>
<select class=voice-select>
</select>
<div class="controls">
<button id="play" type="submit">Play</button>
</div>
</form>
</div>
<div class=screen>
<div class=widget>
<select name=book>
<!--<option value=0>Death of a Hear</option>-->
</select>
<br/>
<span>Current Sentence: </span>
<input type=input name=current-sentence></input>
<span>Total Sentences: </span>
<input type=input name=total-sentences disabled>
</input>
<br/>
<input type=button name=add-book value="Add Book">
<input type=button name=read-aloud value="Read Aloud">
<input type=button name=debug value="Debug">
</input>
<br/>
</div>
<pre class=status>
</pre>
</div>
</body>
</html>

@ -1,508 +0,0 @@
$(window).on('load', () => {
var synth = window.speechSynthesis;
var inputForm = document.querySelector('form');
var inputTxt = document.querySelector('.txt');
var voiceSelect = document.querySelector('select');
var pitch = document.querySelector('#pitch');
var pitchValue = document.querySelector('.pitch-value');
var rate = document.querySelector('#rate');
var rateValue = document.querySelector('.rate-value');
var voices = [];
context.nosleep_timer = null;
context.ui = {
voice_settings_div: $('.voice-settings'),
voice_select: $('.voice-select'),
status_pre: $('.status'),
books_select: $('.screen .widget select[name=book]'),
current_sentence_input:
$('.screen .widget input[name=current-sentence]'),
total_sentences_input:
$('.screen .widget input[name=total-sentences]'),
read_aloud:
$('.screen .widget input[name=read-aloud]'),
add_book:
$('.screen .widget input[name=add-book]'),
debug:
$('.screen .widget input[name=debug]'),
};
context.update_books = () => {
context.ui.books_select.empty();
window.context.books.map(
(o, i) => $('<option>').attr('value', '' + i).text(o.slice(0, 10))
).forEach((o) => context.ui.books_select.append(o))
}
context.update_books();
context.sentences = null;
context.pending_stop = false;
context.current_book = null;
context.nosleep = new NoSleep();
context.is_debug = false;
context.log = {
error: [],
info: [],
};
context.callbacks = {
log_error: (msg) => {
if (context.is_debug)
{
console.error(msg);
context.log.error.push(msg);
}
},
enable_no_sleep: () => {
if (context.nosleep_timer != null)
{
context.callbacks.log_error('running already');
}
context.nosleep_timer = setInterval(
() => {
location.hash = 'nosleep' + Math.random();
context.callbacks.update_status();
/*
if ('vibrate' in window.navigator)
{
window.navigator.vibrate(200);
}
*/
}, 1000
);
},
get_state: () => {
let t1 = localStorage['state'];
if (t1)
{
return JSON.parse(t1);
}
else
{
return {};
}
},
get_cookie: (key) => {
/*
return document.cookie.split('; ').map(
(o) => o.split('=')
).reduce(
(b, a) => {
if (a.length == 2) {b[a[0]] = a[1]};
return b
},
{}
)[key];
*/
let t1 = localStorage['state'];
if (t1 != undefined)
{
let t2 = JSON.parse(t1);
return t2[key];
}
else
{
return undefined;
}
},
set_cookie: (key, value) => {
let state = context.callbacks.get_state('state');
state[key] = value;
//document.cookie = `${key}=${value};`;
localStorage['state'] = JSON.stringify(state);
context.callbacks.update_status();
},
disable_no_sleep: () => {
if (context.nosleep_timer == null)
{
context.callbacks.log_error('nothing is running');
}
clearInterval(context.nosleep_timer);
location.hash = '';
context.nosleep_timer = null;
synth.cancel();
},
continuous_reading: async() => {
if (context.is_reading)
{
context.pending_stop = true;
return;
}
context.is_reading = true;
context.nosleep.enable();
context.callbacks.enable_no_sleep();
context.ui.voice_settings_div.addClass('hidden');
context.ui.current_sentence_input.attr(
'disabled',
'disabled'
);
while (
context.callbacks.get_cookie('sentence_id') < context.sentences.length &&
!context.pending_stop
)
{
let sentence =
context.sentences[context.callbacks.get_cookie('sentence_id')];
//context.callbacks.log_error('start');
try {
await context.read_aloud(
context.sentences[
context.callbacks.get_cookie('sentence_id')
]
);
} catch (e) {
context.callbacks.log_error(e);
}
//context.callbacks.log_error('finished');
if (!context.pending_stop)
{
context.callbacks.set_cookie(
'sentence_id',
context.callbacks.get_cookie('sentence_id') + 1
);
}
}
context.pending_stop = false;
context.ui.current_sentence_input.removeAttr('disabled');
context.nosleep.disable();
context.ui.voice_settings_div.removeClass('hidden');
context.callbacks.disable_no_sleep();
context.is_reading = false;
},
update_status: () => {
let data = {};
data.state = context.callbacks.get_state();
if (
context.callbacks.get_cookie('sentence_id') != null &&
context.sentences != null &&
context.callbacks.get_cookie('sentence_id') < context.sentences.length
)
{
data.sentence = context.sentences[context.callbacks.get_cookie('sentence_id')];
}
data.pending_stop = context.pending_stop;
data.is_reading = context.is_reading;
data.log = context.log;
context.ui.current_sentence_input.val(
context.callbacks.get_cookie('sentence_id')
);
data.timestamp = (new Date());
data.version = 'v0.1.7';
data.speech_synthesis = {
paused: synth.paused,
pending: synth.pending,
speaking: synth.speaking,
};
/*
if (!synth.speaking && context.is_reading)
{
synth.cancel();
}
*/
context.ui.status_pre.text(
JSON.stringify(
data,
null,
4,
)
);
},
ui_read_aloud_on_click: async() => {
let book_id = parseInt(context.ui.books_select.val());
if (context.current_book != book_id)
{
context.current_book = book_id;
context.sentences =
context.books[
context.current_book
].replaceAll(/([\.\?\!])\s+/g,'$1\n')
.split('\n');
context.ui.total_sentences_input.val(
context.sentences.length,
);
{
let state = context.callbacks.get_state();
}
}
if (
context.ui.current_sentence_input.val() != ''
)
{
try{
let sentence_id = parseInt(
context.ui.current_sentence_input.val()
);
if (
sentence_id >= 0 &&
sentence_id < context.sentences.length
)
{
context.callbacks.set_cookie(
'sentence_id',
sentence_id
);
}
} catch (e) {
context.callbacks.log_error(e);
}
}
if (context.is_reading && !context.pending_stop)
{
context.pending_stop = true;
}
else
{
context.callbacks.continuous_reading();
}
},
populateVoiceList: () => {
voices = synth.getVoices().sort(function (a, b) {
const aname = a.name.toUpperCase(), bname = b.name.toUpperCase();
if ( aname < bname ) return -1;
else if ( aname == bname ) return 0;
else return +1;
});
//var selectedIndex = voiceSelect.selectedIndex < 0 ? 0 : voiceSelect.selectedIndex;
voiceSelect.innerHTML = '';
for(i = 0; i < voices.length ; i++) {
var option = document.createElement('option');
option.textContent = voices[i].name + ' (' + voices[i].lang + ')';
if(voices[i].default) {
option.textContent += ' -- DEFAULT';
}
{
let voice = context.callbacks.get_cookie('voice');
if (voice && option.textContent == voice)
{
$(option).attr('selected', 'selected');
}
}
option.setAttribute('data-lang', voices[i].lang);
option.setAttribute('data-name', voices[i].name);
voiceSelect.appendChild(option);
}
//voiceSelect.selectedIndex = selectedIndex;
},
init: () => {
let state = context.callbacks.get_state();
context.ui.voice_select.val(state.voice);
if (!state.book_id)
{
context.callbacks.set_cookie(
'book_id',
0,
);
}
if (!state.sentence_id)
{
context.callbacks.set_cookie(
'sentence_id',
0,
);
}
if (state.book_id)
{
context.ui.books_select.find(
'>option',
).eq(state.book_id).attr('selected', 'selected');
}
if (state.sentence_id)
{
context.ui.current_sentence_input.val(
state.sentence_id,
);
}
},
};
context.callbacks.populateVoiceList();
if (speechSynthesis.onvoiceschanged !== undefined) {
speechSynthesis.onvoiceschanged = context.callbacks.populateVoiceList;
}
context.callbacks.init();
context.ui.add_book.on(
'click',
async () => {
alert('fuck');
let book = await (
(await fetch(
'books/' + prompt('enter book file', '1.txt')
)).text()
);
//let book = prompt('enter text', '');
//let title = prompt('enter title', '');
//window.context.books.push(title + '\n' + book);
window.context.books.push(book);
window.context.update_books();
},
);
context.ui.read_aloud.on(
'click',
context.callbacks.ui_read_aloud_on_click,
);
context.ui.voice_select.on(
'change',
() => {
context.callbacks.set_cookie(
'voice',
context.ui.voice_select.val()
);
}
);
context.ui.debug.on(
'click',
() => {
if (context.is_debug)
{
context.is_debug = false;
}
else
{
context.is_debug = true;
}
context.callbacks.update_status();
}
);
context.read_aloud = async (raw_line) => {
line = raw_line.trim();
if (line.length == 0)
{
return;
}
let sleep_detect = null;
let exit = () => {
if (sleep_detect != null)
{
clearInterval(sleep_detect);
}
}
return new Promise((response, reject) => {
if (synth.speaking) {
context.callbacks.log_error('speechSynthesis.speaking');
if (reject != undefined)
{
reject('error');
}
return;
}
let utterThis = new SpeechSynthesisUtterance(line);
utterThis.onend = function (event) {
exit();
context.callbacks.log_error(
'SpeechSynthesisUtterance.onend ' + event.error
);
if (response != undefined)
{
response('done ' + event.error);
}
}
utterThis.onpause = function (event) {
exit();
context.callbacks.log_error('SpeechSynthesisUtterance.onpause');
if (reject != undefined)
{
reject('paused ' + event.error);
}
}
utterThis.onerror = function (event) {
exit();
context.callbacks.log_error(
'SpeechSynthesisUtterance.onerror ' + event.error
);
if (reject != undefined)
{
reject('error ' + event.error);
}
}
let selectedOption = voiceSelect.selectedOptions[0].getAttribute('data-name');
for(i = 0; i < voices.length ; i++) {
if(voices[i].name === selectedOption) {
utterThis.voice = voices[i];
break;
}
}
//window.alert('fuck3');
utterThis.pitch = pitch.value;
utterThis.rate = rate.value;
synth.speak(utterThis);
let silence_count = 0;
sleep_detect = setInterval(
() => {
if (!synth.speaking)
{
context.callbacks.log_error(
'silence count is ' + silence_count
)
++silence_count;
}
if (silence_count == 3 || context.pending_stop)
{
exit();
if (context.pending_stop)
{
synth.cancel();
reject('pending stop');
}
else
{
context.callbacks.log_error('phone is sleeping, retry');
response('utterance is not present');
}
/*
context.read_aloud(
line
).then(response).catch(reject);
*/
}
},
100,
);
});
}
function speak(){
let line = inputTxt.value;
if (line !== '') {
context.read_aloud(line);
}
}
inputForm.onsubmit = function(event) {
event.preventDefault();
speak();
inputTxt.blur();
}
pitch.onchange = function() {
pitchValue.textContent = pitch.value;
}
rate.onchange = function() {
rateValue.textContent = rate.value;
}
voiceSelect.onchange = function(){
speak();
}
});

@ -1,84 +0,0 @@
body, html {
margin: 0;
}
html {
height: 100%;
}
body {
height: 90%;
max-width: 800px;
margin: 0 auto;
}
h1, p {
font-family: sans-serif;
text-align: center;
padding: 20px;
}
.txt, select, form > div {
display: block;
margin: 0 auto;
font-family: sans-serif;
font-size: 16px;
padding: 5px;
}
.txt {
width: 80%;
}
select {
width: 83%;
}
form > div {
width: 81%;
}
.txt, form > div {
margin-bottom: 10px;
overflow: auto;
}
.clearfix {
clear: both;
}
label {
float: left;
width: 10%;
line-height: 1.5;
}
.rate-value, .pitch-value {
float: right;
width: 5%;
line-height: 1.5;
}
#rate, #pitch {
float: right;
width: 81%;
}
.controls {
text-align: center;
margin-top: 10px;
}
.controls button {
padding: 10px;
}
.hidden
{
display: none !important;
}
pre {
word-break: break-all;
white-space: pre-wrap;
}

1
deps/com.github.aiortc.aiortc vendored Submodule

@ -0,0 +1 @@
Subproject commit adef10a8c41f5c550622879370a40f8a9e545574

10
deps/greasyfork/.editorconfig vendored Normal file

@ -0,0 +1,10 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
[*.{js,json,yml}]
charset = utf-8
indent_style = space
indent_size = 2

6
deps/greasyfork/.gitattributes vendored Normal file

@ -0,0 +1,6 @@
/.yarn/** linguist-vendored
/.yarn/releases/* binary
/.yarn/plugins/**/* binary
/.pnp.* binary linguist-generated
/dist/** filter=lfs diff=lfs merge=lfs -text

15
deps/greasyfork/.gitignore vendored Normal file

@ -0,0 +1,15 @@
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
!dist
build
# Swap the comments on the following lines if you wish to use zero-installs
# In that case, don't forget to run `yarn config set enableGlobalCache false`!
# Documentation here: https://yarnpkg.com/features/caching#zero-installs
#!.yarn/cache
.pnp.*

1
deps/greasyfork/README.md vendored Normal file

@ -0,0 +1 @@
# greasyfork

9486
deps/greasyfork/dist/linkedin.user.js vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

32
deps/greasyfork/package.json vendored Normal file

@ -0,0 +1,32 @@
{
"name": "greasyfork",
"packageManager": "yarn@4.4.0",
"dependencies": {
"@babel/core": "latest",
"@babel/runtime": "latest",
"@gera2ld/plaid-rollup": "latest",
"@violentmonkey/dom": "latest",
"@violentmonkey/ui": "latest",
"jquery": "latest",
"solid-js": "latest",
"typescript": "latest",
"vite": "latest"
},
"devDependencies": {
"@babel/plugin-transform-react-jsx": "latest",
"@babel/plugin-transform-runtime": "latest",
"@rollup/plugin-typescript": "latest",
"@types/babel__core": "latest",
"@types/babel__plugin-transform-runtime": "latest",
"@types/jquery": "latest",
"@violentmonkey/types": "latest",
"cross-env": "latest",
"postcss": "latest",
"prettier": "latest",
"rollup": "latest",
"rollup-plugin-postcss": "latest",
"rollup-plugin-userscript": "latest",
"tslib": "latest",
"unocss": "latest"
}
}

48
deps/greasyfork/rollup.config.mjs vendored Normal file

@ -0,0 +1,48 @@
import { defineExternal, definePlugins } from '@gera2ld/plaid-rollup';
import { defineConfig } from 'rollup';
import userscript from 'rollup-plugin-userscript';
import typescript from '@rollup/plugin-typescript';
import pkg from './package.json' with { type: 'json' };
export default defineConfig(
Object.entries({
'linkedin': 'src/linkedin/index.ts',
}).map(([name, entry]) => ({
input: entry,
plugins: [
...definePlugins({
esm: true,
minimize: false,
postcss: {
inject: false,
minimize: true,
},
extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'],
}),
userscript((meta) => meta.replace('process.env.AUTHOR', pkg.author)),
typescript({ sourceMap: true, inlineSources: true }),
],
external: defineExternal([
'@violentmonkey/ui',
//'@violentmonkey/dom',
'solid-js',
'solid-js/web',
]),
output: {
sourcemap: true,
sourcemapBaseUrl: 'https://gitea.fxreader.online/fxreader.online/freelance-project-34-marketing-blog/media/branch/master/deps/greasyfork/dist/',
format: 'iife',
file: `dist/${name}.user.js`,
globals: {
// Note:
// - VM.solid is just a third-party UMD bundle for solid-js since there is no official one
// - If you don't want to use it, just remove `solid-js` related packages from `external`, `globals` and the `meta.js` file.
'solid-js': 'VM.solid',
'solid-js/web': 'VM.solid.web',
//'@violentmonkey/dom': 'VM',
'@violentmonkey/ui': 'VM',
},
indent: false,
},
})),
);

636
deps/greasyfork/src/linkedin/index.ts vendored Normal file

@ -0,0 +1,636 @@
// ==UserScript==
// @name data extraction linkedin
// @namespace Violentmonkey Scripts
// @match https://www.linkedin.com/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_getValues
// @grant GM_setValues
// @grant GM_listValues
// @grant GM_deleteValue
// @grant GM_deleteValues
// @grant GM_addStyle
// @grant GM_addElement
// @version 0.1
// @author Siarhei Siniak
// @license Unlicense
// @description 10/08/2024, 8:44:59 PM
// @run-at document-body
// @inject-into content
// @noframes
// ==/UserScript==
/*
Use this extension to disalbe CSP for linkedin
https://addons.mozilla.org/en-US/firefox/addon/header-editor/
https://github.com/FirefoxBar/HeaderEditor
https://github.com/violentmonkey/violentmonkey/issues/1335
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src
{
"request": [],
"sendHeader": [],
"receiveHeader": [
{
"enable": true,
"name": "disable CSP for linkedin",
"ruleType": "modifyReceiveHeader",
"matchType": "domain",
"pattern": "www.linkedin.com",
"exclude": "",
"group": "Ungrouped",
"isFunction": false,
"action": {
"name": "content-security-policy",
"value": ""
}
}
],
"receiveBody": []
}
*/
import $ from "jquery";
import * as VM from "@violentmonkey/dom";
interface Entry {
header: string
teaser?: string
};
interface State {
search: string
};
class Linkedin {
data : Map<string, any>;
is_fullscreen: boolean = false;
ui : {
root: any | null
entries: any | null
search: any | null
state: any | null
};
state : State;
old_state: State | null = null;
constructor() {
this.data = new Map();
this.ui = {
root: null,
entries: null,
search: null,
state: null,
};
this.state = {
search: '',
};
}
clean_page() {
if (location.href.search('empty_body=true') != -1)
{
this.is_fullscreen = true;
$('head').empty();
$('body').empty();
$('body').addClass('no-border');
}
}
async data_load() {
let self = this;
const keys = await GM_listValues();
let loaded = 0;
for (let o of keys)
{
if (!o.startsWith('data-'))
{
return;
}
self.data.set(
o.slice(5,),
await GM_getValue(o)
);
loaded += 1;
}
console.log({action: 'loaded', total: loaded});
}
string_reduce (text: string) {
return text.replaceAll(/\s+/gi, ' ').trim();
}
parse_header() {
let self = this;
return [
$(
'.scaffold-finite-scroll__content > div > .relative .update-components-header'
).map((i, o) => ({
header: o.innerText
})),
$(
'.scaffold-finite-scroll__content > div > .relative .update-components-actor'
).map((i, o) => {
let header = $(o);
let teaser = $(o).parents('.relative')
.parent().find('.feed-shared-update-v2__description-wrapper');
return {
header: self.string_reduce(header.text()),
teaser: self.string_reduce(teaser.text()),
};
})
]
}
async data_add (entry: Entry) {
let self = this;
if (self.data.has(entry.header))
{
return false;
}
self.data.set(entry.header, {
entry: entry,
ts: (new Date()).valueOf(),
});
await GM_setValue(
'data-' + entry.header,
self.data.get(entry.header)
)
console.log('saved ' + entry.header);
console.log(self.data.get(entry.header));
return true;
}
async document_on_changed () {
let self = this;
let state_changed = false;
if (
JSON.stringify(self.state_get()) != JSON.stringify(self.state)
)
{
state_changed = true;
self.old_state = self.state;
self.state = self.state_get();
}
let current_data = self.parse_header();
let changed = false;
for (let o of current_data[0])
{
let current_changed = await self.data_add(o);
if (current_changed)
{
changed = current_changed;
}
}
for (let o of current_data[1])
{
let current_changed = await self.data_add(o);
if (current_changed)
{
changed = current_changed;
}
}
if (
changed || (
state_changed ||
self.ui.entries === null && self.data.size > 0
)
)
{
self.display();
}
}
listener_add() {
let self = this;
return VM.observe(
document.body,
() => {
self.document_on_changed();
}
);
}
display_init() {
let self = this;
self.ui.root = $(`<div class=online-fxreader-linkedin>`);
$(document.body).append(self.ui.root);
if (self.is_fullscreen)
{
self.ui.root.addClass('fullscreen');
}
$('head').append($('<style>').html(`
div.online-fxreader-linkedin {
height: 10em;
overflow: hidden;
z-index: 9999;
position: fixed;
top: 5em;
background: yellow;
margin-left: 1em;
word-wrap: anywhere;
white-space: break-spaces;
margin-right: 1em;
width: calc(100% - 2em);
}
.d-none {
display: none !important;
}
.online-fxreader-linkedin.tray-active .search,
.online-fxreader-linkedin.tray-active .entries
{
display: none;
}
.online-fxreader-linkedin .tray
{
cursor: pointer;
position: absolute;
right: 0px;
z-index: 9999;
}
.online-fxreader-linkedin.tray-active
{
right: 1em;
width: 3em;
height: 3em !important;
}
.online-fxreader-linkedin .search
{
display: flex;
position: sticky;
top: 0px;
background-color: #eee;
}
.online-fxreader-linkedin .search input
{
width: 60em;
}
.online-fxreader-linkedin .entries
{
overflow: scroll;
height: 100%;
}
.online-fxreader-linkedin .entry.even
{
background-color: #eee;
}
.online-fxreader-linkedin .entry.odd
{
background-color: #ddd;
}
.online-fxreader-linkedin .search,
.online-fxreader-linkedin .search input
{
height: 2em;
line-height: 2em;
box-sizing: border-box;
}
.no-border {
padding: unset;
margin: unset;
}
.online-fxreader-linkedin:hover,
.online-fxreader-linkedin.fullscreen
{
height: 80vh;
}
`));
GM_addElement('script', {
"textContent": `
class Linkedin {
constructor() {
let self = this;
this.has_callbacks = false;
this.ui = {
root: () => {
return document.getElementsByClassName('online-fxreader-linkedin')[0];
},
};
self.ui.search = () => {
let search = self.ui.root().getElementsByClassName('search')[0];
let search_input = search.getElementsByTagName('input')[0];
return search_input;
};
self.ui.tray = () => {
// let search = self.ui.root().getElementsByClassName('search')[0];
let tray = self.ui.root().getElementsByClassName('tray')[0];
return tray;
};
self.ui.state = () => {
let state = self.ui.root().getElementsByClassName('state')[0];
return state;
};
}
add_callbacks() {
let self = this;
self.ui.tray().addEventListener(
'click', function(e) {
let o = e.currentTarget;
let cl = o.classList;
let r = self.ui.root();
if (cl.contains('active'))
{
cl.remove('active');
r.classList.add('tray-active');
}
else
{
cl.add('active');
r.classList.remove('tray-active');
}
}
);
}
blah(class_name) {
if (!this.has_callbacks)
{
this.add_callbacks();
this.has_callbacks = true;
}
console.log('blah');
Array.from(
document.getElementsByClassName(class_name)
).forEach((o) => o.remove());
}
state_update(partial) {
let self = this;
let ui_state = self.ui.state();
let old_state = JSON.parse(ui_state.innerText);
ui_state.innerText = JSON.stringify(
{
...old_state,
...partial
}
);
}
search_on_change() {
let self = this;
let search = self.ui.search();
self.state_update(
{
search: search.value
}
);
}
};
const online_fxreader_linkedin = new Linkedin();
console.log('started');
`
});
}
state_get() {
let self = this;
if (self.ui.state && self.ui.state.text() !== '')
{
return JSON.parse(self.ui.state.text());
}
else
{
return {};
}
}
state_set(partial: any) {
let self = this;
self.ui.state.text(
{
...self.state_get(),
...partial
}
);
}
display() {
let self = this;
let sorted_entries = Array.from(self.data.entries()).sort(
(a, b) => a[1].ts - b[1].ts
);
// self.ui.root.empty();
if (self.ui.search === null)
{
self.ui.root.append(
$('<div>').addClass('tray').text('SHOW/HIDE')
);
let search = $('<div>').addClass('search').append(
$('<input>').val(self.state.search)
).attr(
'onkeyup',
`online_fxreader_linkedin.search_on_change()`,
);
search.append(
$('<div>').addClass('total')
);
self.ui.root.append(search);
self.ui.search = search;
}
if (self.ui.state === null)
{
self.ui.state = $('<div>').addClass('state d-none').text(
JSON.stringify(self.state)
);
self.ui.root.append(self.ui.state);
}
else
{
}
//state_set(old_state);
let entries = null;
if (self.ui.entries === null)
{
entries = $('<div>').addClass('entries');
self.ui.root.append(entries);
self.ui.entries = entries
}
else
{
entries = self.ui.entries;
entries.empty();
}
let keywords = (self.state?.search || '').split(/\s+/).map((o) => {
let action = '';
let word = '';
if (o.length > 0)
{
if (o[0] == '+')
{
action = 'include';
word = o.slice(1,);
}
else if (o[0] == '-')
{
action = 'exclude';
word = o.slice(1,);
}
else
{
action = 'include';
word = o;
}
}
return {
action,
word,
};
}).filter((o) => o.action !== '' && o.word !== '');
let filtered_entries = sorted_entries.filter((o) => {
let match = true;
let text = JSON.stringify(o);
for (let k of keywords)
{
if (k.action == 'include')
{
if (text.search(k.word) == -1)
{
match = false;
}
}
else if (k.action == 'exclude')
{
if (text.search(k.word) != -1)
{
match = false;
}
}
if (!match)
{
break;
}
}
return match;
})
self.ui.search.find('.total').text(
filtered_entries.length
);
let i = 0;
for (let o of filtered_entries.reverse())
{
let raw = JSON.stringify(o[1]);
let ts = (new Date(o[1].ts));
let entry = $('<div>').addClass('entry');
if (i % 2 == 0)
{
entry.addClass('even');
}
else
{
entry.addClass('odd');
}
entry.append(
$('<div>').addClass('ts').text(
ts.toISOString(),
)
);
entry.append(
$('<div>').addClass('header').text(
o[1].entry.header
)
);
entry.append(
$('<div>').addClass('teaser').text(
o[1].entry.teaser
)
);
// entry.append($('<pre>').text(raw));
entries.append(entry);
++i;
}
GM_addElement('script', {
"class": 'bridge',
"textContent": `
online_fxreader_linkedin.blah('bridge');
`
});
}
}
const l = new Linkedin();
(async () => {
l.clean_page();
await l.data_load();
const disconnect = l.listener_add();
l.display_init();
})();

1
deps/greasyfork/src/types/vm.d.ts vendored Normal file

@ -0,0 +1 @@
import '@violentmonkey/types';

115
deps/greasyfork/tsconfig.json vendored Normal file

@ -0,0 +1,115 @@
{
"include": ["src"],
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "esnext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
"lib": [
"DOM",
"ES6",
"DOM.Iterable",
"ScriptHost",
"ESNext"
], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "esnext", /* Specify what module code is generated. */
// "rootDir": "./", /* Specify the root folder within your source files. */
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
// "resolveJsonModule": true, /* Enable importing .json files. */
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
"sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
"outDir": "build/", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
// "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}

4844
deps/greasyfork/yarn.lock vendored Normal file

File diff suppressed because it is too large Load Diff

1
deps/online.fxreader.nartes.books vendored Submodule

@ -0,0 +1 @@
Subproject commit 3c691ef68d8899edf328d5b06135c0d3b02e7940

@ -7,7 +7,7 @@ services:
volumes: volumes:
- ./d1/:/app/d1/:ro - ./d1/:/app/d1/:ro
- ./tmp/cache/:/app/tmp/cache/:ro - ./tmp/cache/:/app/tmp/cache/:ro
restart: always restart: on-failure
ssl-app: ssl-app:
build: build:
context: . context: .
@ -16,36 +16,40 @@ services:
- ./d1/:/app/d1/:ro - ./d1/:/app/d1/:ro
- ./tmp/d1/:/app/tmp/d1/:ro - ./tmp/d1/:/app/tmp/d1/:ro
- ./tmp/d1/letsencrypt:/etc/letsencrypt:rw - ./tmp/d1/letsencrypt:/etc/letsencrypt:rw
restart: always restart: on-failure
cpanel: cpanel:
build: build:
context: . context: .
dockerfile: ./docker/cpanel/Dockerfile dockerfile: ./docker/cpanel/Dockerfile
links: #links:
- app # - app
volumes: volumes:
- ./d1/:/app/d1:ro - ./d1/:/app/d1:ro
- ./tmp/d1/:/app/tmp/d1/:ro - ./tmp/d1/:/app/tmp/d1/:ro
restart: always restart: on-failure
dynu: dynu:
build: build:
context: . context: .
dockerfile: ./docker/dynu/Dockerfile dockerfile: ./docker/dynu/Dockerfile
profiles:
- broken
volumes: volumes:
- ./d1/dynu_update.py:/app/d1/dynu_update.py:ro - ./d1/dynu_update.py:/app/d1/dynu_update.py:ro
- ./tmp/cache/dynu.auth.json:/app/tmp/cache/dynu.auth.json:ro - ./tmp/cache/dynu.auth.json:/app/tmp/cache/dynu.auth.json:ro
restart: always restart: on-failure
links: # links:
- ngrok # - ngrok
ngrok: ngrok:
image: wernight/ngrok image: wernight/ngrok
links: #links:
- app # - app
profiles:
- broken
command: ['ngrok', 'http', 'app:80'] command: ['ngrok', 'http', 'app:80']
volumes: volumes:
- ./tmp/cache/ngrok.yml:/home/ngrok/.ngrok2/ngrok.yml:ro - ./tmp/cache/ngrok.yml:/home/ngrok/.ngrok2/ngrok.yml:ro
restart: always restart: on-failure
#forward: #forward:
# build: # build:
# context: . # context: .

@ -4,7 +4,7 @@ RUN apk add python3
RUN apk add tini RUN apk add tini
RUN apk add bash curl RUN apk add bash curl
RUN apk add py3-pip RUN apk add py3-pip
RUN pip3 install requests RUN pip3 install --break-system-packages requests
WORKDIR /app WORKDIR /app

15
docker/js/Dockerfile Normal file

@ -0,0 +1,15 @@
FROM node as base
ENV DEBIAN_FRONTEND noninteractive
RUN \
apt-get update -yy && \
apt-get install \
tini zsh less tree \
-yy
RUN chsh -s /usr/bin/zsh
WORKDIR /app/deps/greasyfork
ENTRYPOINT ["tini", "--"]
CMD ["bash", "/app/docker/js/init.sh"]
# CMD ["sleep", "999999999999999999"]

@ -0,0 +1,17 @@
version: '3.7'
services:
js:
build:
context: .
dockerfile: ./docker/js/Dockerfile
volumes:
- ./deps/greasyfork:/app/deps/greasyfork:rw
- ./tmp/cache/js/root-cache:/root/.cache:rw
- ./tmp/cache/js/root-yarn:/root/.yarn:rw
- ./docker/js:/app/docker/js:ro
- ./tmp/cache/js:/app/tmp/cache/js:rw
deploy:
resources:
limits:
cpus: 1.5
memory: 1G

7
docker/js/init.sh Normal file

@ -0,0 +1,7 @@
corepack enable
corepack install
# yarn init -2
ln -sf /app/docker/js/.zshrc ~/.zshrc
ln -sf /app/tmp/cache/js/.histfile ~/.histfile
export EDITOR=vim
exec /usr/bin/zsh -l

@ -7,6 +7,7 @@ RUN apk add nginx
RUN apk add tini RUN apk add tini
#RUN pip3 install requests certbot #RUN pip3 install requests certbot
RUN apk add certbot RUN apk add certbot
RUN apk add nginx-mod-stream
WORKDIR /app WORKDIR /app

@ -1,29 +0,0 @@
FROM python:latest
RUN pip3 install ipython jupyter
RUN apt-get update -yy && apt-get install -yy zsh htop mc git
RUN pip3 install jupyterlab-vim
RUN pip3 install pyktok yt-dlp playwright==1.44.0 TikTokApi
RUN pip3 install numpy pandas browser_cookie3 ipdb asgiref
RUN python3 -m playwright install-deps
RUN python3 -m playwright install
RUN pip3 install tqdm
RUN apt-get install -yy ffmpeg
RUN pip3 install celery redis
RUN pip3 install dataclasses-json
RUN pip3 install rpdb
RUN apt-get install -yy netcat-traditional
RUN apt-get install -yy vim
RUN apt-get install -yy tini
RUN apt-get install -yy wkhtmltopdf graphviz
RUN pip3 install pandoc
RUN apt-get install -yy pandoc
RUN apt-get install -yy texlive-xetex texlive-fonts-recommended texlive-plain-generic
RUN pip3 install 'nbconvert[webpdf]'
RUN pip3 install pickleshare
RUN pip3 install networkx
WORKDIR /app
ENTRYPOINT ["tini", "--", "bash", "docker/tiktok/entry.sh"]
CMD ["zsh", "-l"]

@ -1,59 +0,0 @@
PROJECT_ROOT ?= ${PWD}
export PROJECT_ROOT
PORT ?= 8888
TOKEN ?= $(shell pwgen -n 20 1)
c:
cd ${PROJECT_ROOT} && \
sudo docker-compose \
-f docker/tiktok/docker-compose.yml $(ARGS)
build:
$(MAKE) c ARGS="pull"
$(MAKE) c ARGS="build --pull"
celery-up:
$(MAKE) c ARGS="up -d redis celery"
celery-stop:
$(MAKE) c ARGS="stop redis celery"
celery-cmd:
$(MAKE) c ARGS="exec celery celery -A python.tasks.tiktok.celery ${ARGS}"
deploy:
cd ${PROJECT_ROOT} && tar -cvf ${PROJECT_ROOT}/tmp/cache/tiktok/repo.tar \
docker/tiktok \
python/tasks/tiktok \
tmp/cache/tiktok/notebooks/tiktok.ipynb \
tmp/cache/tiktok/notebooks/*.pdf \
.dockerignore \
.gitignore
logs:
$(MAKE) c ARGS="logs --tail=100 -f"
celery-restart:
$(MAKE) c ARGS="restart celery"
run:
cd ${PROJECT_ROOT} && \
sudo docker-compose \
-f docker/tiktok/docker-compose.yml \
run \
--use-aliases \
--rm tiktok
jupyter:
cd ${PROJECT_ROOT} && \
sudo docker-compose \
-f docker/tiktok/docker-compose.yml \
run \
-p 127.0.0.1:${PORT}:8888 \
--rm tiktok \
jupyter-lab \
--allow-root \
--ip=0.0.0.0 \
--NotebookApp.token=${TOKEN}

@ -1,28 +0,0 @@
version: '3.7'
services:
redis:
image: redis:latest
volumes:
- ../../tmp/cache/tiktok/redis/data:/data:rw
tiktok: &tiktok
links:
- redis
build:
context: ../../
dockerfile: ./docker/tiktok/Dockerfile
volumes:
- ./../../docker/tiktok:/app/docker/tiktok:ro
- ./../../tmp/cache/tiktok:/app/tmp/cache/tiktok:rw
- ./../../python/tasks/tiktok:/app/python/tasks/tiktok:ro
celery:
build:
context: ../../
dockerfile: ./docker/tiktok/Dockerfile
depends_on:
- redis
volumes:
- ./../../docker/tiktok:/app/docker/tiktok:ro
- ./../../tmp/cache/tiktok:/app/tmp/cache/tiktok:rw
- ./../../python/tasks/tiktok:/app/python/tasks/tiktok:ro
command:
- celery -A python.tasks.tiktok.celery worker -c 2

@ -1,10 +0,0 @@
ln -sf $PWD/docker/tiktok/.zshrc ~
mkdir -p tmp/cache/tiktok/zsh
mkdir -p tmp/cache/tiktok/ipython
mkdir -p tmp/cache/tiktok/jupyter
ln -sf $PWD/tmp/cache/tiktok/zsh/histfile ~/.histfile
ln -sf $PWD/tmp/cache/tiktok/jupyter ~/.jupyter
ln -sf $PWD/tmp/cache/tiktok/ipython ~/.ipython
ipython3 profile create
ln -sf $PWD/docker/tiktok/ipython_config.py ~/.ipython/profile_default/
exec $@

@ -1,72 +0,0 @@
c.InteractiveShellApp.exec_lines = [
'%autoreload 2',
r'''
def ipython_update_shortcuts():
import IPython
import prompt_toolkit.filters
import prompt_toolkit.document
import functools
import tempfile
import io
import subprocess
def ipython_edit_in_vim(*args, pt_app):
content = pt_app.app.current_buffer.document.text
lines_count = lambda text: len(text.splitlines())
with tempfile.NamedTemporaryFile(
suffix='.py',
mode='w',
) as f:
with io.open(f.name, 'w') as f2:
f2.write(content)
f2.flush()
result = subprocess.call([
'vim',
'+%d' % lines_count(content),
f.name,
])
if result != 0:
return
f.seek(0, io.SEEK_SET)
with io.open(f.name, 'r') as f2:
new_content = f2.read()
pt_app.app.current_buffer.document = \
prompt_toolkit.document.Document(
new_content,
cursor_position=len(new_content.rstrip()),
)
t1 = IPython.get_ipython()
t2 = t1.pt_app
t3 = [o for o in t2.key_bindings.bindings if 'f2' in repr(o.keys).lower()]
assert len(t3) == 1
t4 = t3[0]
t2.key_bindings.remove(t4.handler)
t2.key_bindings.add(
'\\', 'e', filter=~prompt_toolkit.filters.vi_insert_mode,
)(
functools.partial(
ipython_edit_in_vim,
pt_app=t2,
)
#t4.handler
)
''',
'ipython_update_shortcuts()',
]
c.IPCompleter.use_jedi = False
c.InteractiveShellApp.extensions = ['autoreload']
c.InteractiveShell.history_length = 100 * 1000 * 1000
c.InteractiveShell.history_load_length = 100 * 1000 * 1000
#c.InteractiveShell.enable_history_search = False
#c.InteractiveShell.autosuggestions_provider = None
c.InteractiveShell.pdb = True
c.TerminalInteractiveShell.editing_mode = 'vi'
c.TerminalInteractiveShell.modal_cursor = False
c.TerminalInteractiveShell.emacs_bindings_in_vi_insert_mode = False

@ -0,0 +1,156 @@
// Place your key bindings in this file to override the defaults
[
{
"key": "alt+z",
"command": "-editor.action.toggleWordWrap"
},
{
"key": "alt+z",
"command": "-workbench.action.terminal.sizeToContentWidth",
"when": "terminalFocus && terminalHasBeenCreated && terminalIsOpen || terminalFocus && terminalIsOpen && terminalProcessSupported"
},
{
"key": "alt+r",
"command": "workbench.action.toggleMaximizeEditorGroup",
"when": "editorPartMaximizedEditorGroup || editorPartMultipleEditorGroups"
},
{
"key": "ctrl+k ctrl+m",
"command": "-workbench.action.toggleMaximizeEditorGroup",
"when": "editorPartMaximizedEditorGroup || editorPartMultipleEditorGroups"
},
{
"key": "alt+r",
"command": "workbench.action.toggleMaximizedPanel",
"when": "!editorTextFocus"
},
{
"key": "ctrl+p",
"command": "-extension.vim_ctrl+p",
"when": "editorTextFocus && vim.active && vim.use<C-p> && !inDebugRepl || vim.active && vim.use<C-p> && !inDebugRepl && vim.mode == 'CommandlineInProgress' || vim.active && vim.use<C-p> && !inDebugRepl && vim.mode == 'SearchInProgressMode'"
},
{
"key": "alt+t",
"command": "workbench.action.terminal.toggleTerminal",
"when": "terminal.active"
},
{
"key": "ctrl+`",
"command": "-workbench.action.terminal.toggleTerminal",
"when": "terminal.active"
},
{
"key": "ctrl+e",
"command": "-workbench.action.quickOpen"
},
{
"key": "ctrl+n",
"command": "-extension.vim_ctrl+n",
"when": "editorTextFocus && vim.active && vim.use<C-n> && !inDebugRepl || vim.active && vim.use<C-n> && !inDebugRepl && vim.mode == 'CommandlineInProgress' || vim.active && vim.use<C-n> && !inDebugRepl && vim.mode == 'SearchInProgressMode'"
},
{
"key": "ctrl+t",
"command": "-extension.vim_ctrl+t",
"when": "editorTextFocus && vim.active && vim.use<C-t> && !inDebugRepl"
},
{
"key": "ctrl+f",
"command": "-extension.vim_ctrl+f",
"when": "editorTextFocus && vim.active && vim.use<C-f> && !inDebugRepl && vim.mode != 'Insert'"
},
{
"key": "ctrl+f",
"command": "-actions.find",
"when": "editorFocus || editorIsOpen"
},
{
"key": "ctrl+f",
"command": "workbench.action.findInFiles"
},
{
"key": "ctrl+shift+f",
"command": "-workbench.action.findInFiles"
},
{
"key": "ctrl+g",
"command": "-workbench.action.gotoLine"
},
{
"key": "ctrl+g",
"command": "-workbench.action.terminal.goToRecentDirectory",
"when": "terminalFocus && terminalHasBeenCreated || terminalFocus && terminalProcessSupported"
},
{
"key": "alt+r",
"command": "-toggleSearchRegex",
"when": "searchViewletFocus"
},
{
"key": "alt+r",
"command": "-toggleFindRegex",
"when": "editorFocus"
},
{
"key": "alt+r",
"command": "-workbench.action.terminal.toggleFindRegex",
"when": "terminalFindVisible && terminalHasBeenCreated || terminalFindVisible && terminalProcessSupported"
},
{
"key": "alt+r",
"command": "-toggleSearchEditorRegex",
"when": "inSearchEditor && searchInputBoxFocus"
},
{
"key": "ctrl+/",
"command": "-editor.action.accessibleViewAcceptInlineCompletion",
"when": "accessibleViewIsShown && accessibleViewCurrentProviderId == 'inlineCompletions'"
},
{
"key": "ctrl+k ctrl+/",
"command": "-editor.foldAllBlockComments",
"when": "editorTextFocus && foldingEnabled"
},
{
"key": "ctrl+/",
"command": "-toggleExplainMode",
"when": "suggestWidgetVisible"
},
{
"key": "ctrl+/",
"command": "-workbench.action.chat.attachContext",
"when": "inChatInput && chatLocation == 'editing-session' || inChatInput && chatLocation == 'editor' || inChatInput && chatLocation == 'notebook' || inChatInput && chatLocation == 'panel' || inChatInput && chatLocation == 'terminal'"
},
{
"key": "ctrl+/",
"command": "-workbench.action.terminal.sendSequence",
"when": "terminalFocus"
},
{
"key": "shift+alt+l",
"command": "workbench.action.editorLayoutTwoRowsRight"
},
{
"key": "ctrl+b",
"command": "-extension.vim_ctrl+b",
"when": "editorTextFocus && vim.active && vim.use<C-b> && !inDebugRepl && vim.mode != 'Insert'"
},
{
"key": "ctrl+w",
"command": "-workbench.action.closeActiveEditor"
},
{
"key": "ctrl+w",
"command": "-workbench.action.closeGroup",
"when": "activeEditorGroupEmpty && multipleEditorGroups"
},
{
"key": "ctrl+w",
"command": "-extension.vim_ctrl+w",
"when": "editorTextFocus && vim.active && vim.use<C-w> && !inDebugRepl"
},
{
"key": "ctrl+w",
"command": "workbench.action.closeActiveEditor",
"when": "editorTextFocus"
}
]

@ -0,0 +1,151 @@
{
"editor.wordWrap": "on",
"editor.minimap.autohide": true,
"editor.minimap.maxColumn": 80,
"editor.minimap.size": "fit",
"python.experiments.enabled": false,
"debugpy.debugJustMyCode": false,
"python.REPL.enableREPLSmartSend": false,
"python.terminal.activateEnvironment": false,
"python.testing.autoTestDiscoverOnSaveEnabled": false,
"python.languageServer": "None",
"typescript.surveys.enabled": false,
"typescript.suggestionActions.enabled": false,
"typescript.tsserver.enableRegionDiagnostics": false,
"typescript.tsserver.maxTsServerMemory": 0.05,
"typescript.tsserver.useSyntaxServer": "never",
"typescript.tsserver.web.typeAcquisition.enabled": false,
"typescript.validate.enable": false,
"typescript.workspaceSymbols.excludeLibrarySymbols": false,
"typescript.check.npmIsInstalled": false,
"typescript.tsserver.web.projectWideIntellisense.enabled": false,
"python.REPL.provideVariables": false,
"git.openRepositoryInParentFolders": "never",
"workbench.enableExperiments": false,
"workbench.cloudChanges.continueOn": "off",
"workbench.cloudChanges.autoResume": "off",
"extensions.autoCheckUpdates": false,
"update.mode": "none",
"workbench.settings.enableNaturalLanguageSearch": false,
"update.showReleaseNotes": false,
"extensions.autoUpdate": false,
"telemetry.telemetryLevel": "off",
"json.schemaDownload.enable": false,
"npm.fetchOnlinePackageInfo": false,
"window.experimentalControlOverlay": false,
"window.commandCenter": false,
"window.confirmBeforeClose": "always",
"window.dialogStyle": "custom",
"window.titleBarStyle": "custom",
"window.customTitleBarVisibility": "windowed",
"window.enableMenuBarMnemonics": false,
"window.menuBarVisibility": "compact",
"issueReporter.experimental.auxWindow": false,
"workbench.colorTheme": "Monokai",
"workbench.preferredDarkColorTheme": "Monokai",
"workbench.preferredHighContrastColorTheme": "Monokai",
"workbench.preferredHighContrastLightColorTheme": "Monokai",
"workbench.preferredLightColorTheme": "Monokai",
"mesonbuild.downloadLanguageServer": false,
// "vim.easymotion": true,
// "vim.incsearch": true,
"vim.useSystemClipboard": true,
// "vim.useCtrlKeys": true,
"vim.hlsearch": true,
// "vim.insertModeKeyBindings": [
// {
// "before": ["j", "j"],
// "after": ["<Esc>"]
// }
// ],
"vim.normalModeKeyBindingsNonRecursive": [
{
"before": ["<leader>", "w"],
"after": ["<C-w>"],
// "after": ["d", "d"]
},
// {
// "before": ["<C-n>"],
// "commands": [":nohl"]
// },
// {
// "before": ["K"],
// "commands": ["lineBreakInsert"],
// "silent": true
// }
],
"vim.leader": "\\",
// "vim.handleKeys": {
// "<C-a>": false,
// "<C-f>": false
// },
"extensions.experimental.affinity": {
"vscodevim.vim": 1
},
"diffEditor.experimental.showMoves": true,
"diffEditor.hideUnchangedRegions.enabled": true,
"python.locator": "native",
"python.testing.promptToConfigure": false,
"typescript.format.enable": false,
"typescript.format.indentSwitchCase": false,
"typescript.preferences.renameMatchingJsxTags": false,
"typescript.autoClosingTags": false,
"typescript.format.insertSpaceAfterCommaDelimiter": false,
"typescript.format.insertSpaceAfterKeywordsInControlFlowStatements": false,
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": false,
"docker.enableDockerComposeLanguageService": false,
"go.useLanguageServer": false,
"search.maxResults": 128,
"search.ripgrep.maxThreads": 1,
"search.searchEditor.defaultNumberOfContextLines": 7,
"search.searchOnType": false,
"task.allowAutomaticTasks": "off",
"task.autoDetect": "off",
"task.quickOpen.detail": false,
"task.reconnection": false,
"javascript.autoClosingTags": false,
"javascript.format.enable": false,
"javascript.format.insertSpaceAfterCommaDelimiter": false,
"javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
"javascript.format.insertSpaceAfterKeywordsInControlFlowStatements": false,
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": false,
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": false,
"javascript.format.insertSpaceAfterSemicolonInForStatements": false,
"javascript.format.insertSpaceBeforeAndAfterBinaryOperators": false,
"javascript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": false,
"javascript.inlayHints.variableTypes.suppressWhenTypeMatchesName": false,
"javascript.preferences.renameMatchingJsxTags": false,
"javascript.preferences.useAliasesForRenames": false,
"javascript.suggest.autoImports": false,
"javascript.suggest.classMemberSnippets.enabled": false,
"javascript.suggest.completeJSDocs": false,
"javascript.suggest.enabled": false,
"javascript.suggest.includeAutomaticOptionalChainCompletions": false,
"javascript.suggest.includeCompletionsForImportStatements": false,
"javascript.suggest.jsdoc.generateReturns": false,
"javascript.suggest.names": false,
"javascript.suggest.paths": false,
"javascript.suggestionActions.enabled": false,
"javascript.updateImportsOnFileMove.enabled": "never",
"javascript.validate.enable": false,
"js/ts.implicitProjectConfig.strictFunctionTypes": false,
"js/ts.implicitProjectConfig.strictNullChecks": false,
"typescript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": false,
"typescript.format.insertSpaceAfterSemicolonInForStatements": false,
"typescript.format.insertSpaceBeforeAndAfterBinaryOperators": false,
"typescript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": false,
"typescript.inlayHints.variableTypes.suppressWhenTypeMatchesName": false,
"typescript.preferences.useAliasesForRenames": false,
"typescript.reportStyleChecksAsWarnings": false,
"typescript.suggest.autoImports": false,
"typescript.suggest.classMemberSnippets.enabled": false,
"typescript.suggest.completeJSDocs": false,
"typescript.suggest.enabled": false,
"typescript.suggest.includeAutomaticOptionalChainCompletions": false,
"typescript.suggest.includeCompletionsForImportStatements": false,
"typescript.suggest.jsdoc.generateReturns": false,
"typescript.suggest.objectLiteralMethodSnippets.enabled": false,
"typescript.suggest.paths": false,
"typescript.tsc.autoDetect": "off",
}

283
dotfiles/.config/katerc Normal file

@ -0,0 +1,283 @@
[BuildConfig]
AllowedCommandLines=
AutoSwitchToOutput=true
BlockedCommandLines=
UseDiagnosticsOutput=true
[CTags]
GlobalCommand=ctags -R --c++-types=+px --extra=+q --excmd=pattern --exclude=Makefile --exclude=.
GlobalNumTargets=0
[General]
Allow Tab Scrolling=true
Auto Hide Tabs=false
Close After Last=false
Close documents with window=true
Cycle To First Tab=true
Days Meta Infos=30
Diagnostics Limit=12000
Diff Show Style=0
Elide Tab Text=false
Enable Context ToolView=false
Expand Tabs=false
Icon size for left and right sidebar buttons=32
Last Session=calibre
Modified Notification=false
Mouse back button action=0
Mouse forward button action=0
Open New Tab To The Right Of Current=true
Output History Limit=100
Output With Date=false
Quickopen Filter Mode=0
Quickopen List Mode=true
Recent File List Entry Count=10
Restore Window Configuration=true
SDI Mode=false
Save Meta Infos=false
Session Manager Sort Column=0
Session Manager Sort Order=1
Show Full Path in Title=true
Show Menu Bar=true
Show Status Bar=true
Show Symbol In Navigation Bar=true
Show Tab Bar=true
Show Tabs Close Button=true
Show Url Nav Bar=false
Show output view for message type=1
Show text for left and right sidebar=false
Show welcome view for new window=true
Startup Session=manual
Stash new unsaved files=true
Stash unsaved file changes=true
Sync section size with tab positions=false
Tab Double Click New Document=true
Tab Middle Click Close Document=true
Tabbar Tab Limit=0
[KDE]
widgetStyle=Fusion
[KTextEditor Document]
Allow End of Line Detection=true
Auto Detect Indent=true
Auto Reload If State Is In Version Control=true
Auto Save=false
Auto Save Interval=0
Auto Save On Focus Out=false
BOM=false
Backup Local=false
Backup Prefix=
Backup Remote=false
Backup Suffix=~
Camel Cursor=true
Encoding=UTF-8
End of Line=0
Indent On Backspace=true
Indent On Tab=true
Indent On Text Paste=true
Indentation Mode=normal
Indentation Width=2
Keep Extra Spaces=false
Line Length Limit=10000
Newline at End of File=true
On-The-Fly Spellcheck=false
Overwrite Mode=false
PageUp/PageDown Moves Cursor=false
Remove Spaces=1
ReplaceTabsDyn=false
Show Spaces=2
Show Tabs=true
Smart Home=true
Swap Directory=
Swap File Mode=1
Swap Sync Interval=15
Tab Handling=2
Tab Width=2
Trailing Marker Size=1
Use Editor Config=true
Word Wrap=false
Word Wrap Column=80
[KTextEditor Renderer]
Animate Bracket Matching=false
Auto Color Theme Selection=false
Color Theme=Monokai2
Line Height Multiplier=1
Show Indentation Lines=false
Show Whole Bracket Expression=false
Text Font=Terminus,18,-1,5,400,0,0,0,0,0,0,0,0,0,0,1
Text Font Features=
Word Wrap Marker=true
[KTextEditor View]
Allow Mark Menu=true
Auto Brackets=true
Auto Center Lines=0
Auto Completion=true
Auto Completion Preselect First Entry=true
Backspace Remove Composed Characters=false
Bookmark Menu Sorting=0
Bracket Match Preview=true
Chars To Enclose Selection=<>(){}[]'"
Cycle Through Bookmarks=true
Default Mark Type=1
Dynamic Word Wrap=true
Dynamic Word Wrap Align Indent=80
Dynamic Word Wrap At Static Marker=false
Dynamic Word Wrap Indicators=1
Dynamic Wrap not at word boundaries=false
Enable Accessibility=true
Enable Tab completion=false
Enter To Insert Completion=true
Fold First Line=false
Folding Bar=true
Folding Preview=true
Icon Bar=false
Input Mode=1
Keyword Completion=true
Line Modification=true
Line Numbers=true
Max Clipboard History Entries=20
Maximum Search History Size=100
Mouse Paste At Cursor Position=false
Multiple Cursor Modifier=134217728
Persistent Selection=false
Scroll Bar Marks=false
Scroll Bar Mini Map All=true
Scroll Bar Mini Map Width=60
Scroll Bar MiniMap=false
Scroll Bar Preview=true
Scroll Past End=false
Search/Replace Flags=140
Shoe Line Ending Type in Statusbar=false
Show Documentation With Completion=true
Show File Encoding=true
Show Folding Icons On Hover Only=true
Show Line Count=true
Show Scrollbars=0
Show Statusbar Dictionary=true
Show Statusbar Highlighting Mode=true
Show Statusbar Input Mode=true
Show Statusbar Line Column=true
Show Statusbar Tab Settings=true
Show Word Count=true
Smart Copy Cut=true
Statusbar Line Column Compact Mode=true
Text Drag And Drop=true
User Sets Of Chars To Enclose Selection=
Vi Input Mode Steal Keys=false
Vi Relative Line Numbers=false
Word Completion=true
Word Completion Minimal Word Length=3
Word Completion Remove Tail=true
[Konsole]
AutoSyncronizeMode=0
KonsoleEscKeyBehaviour=false
KonsoleEscKeyExceptions=vi,vim,nvim,git
RemoveExtension=false
RunPrefix=
SetEditor=false
[MainWindow]
1366x768 screen: Height=733
1366x768 screen: Width=1362
2 screens: Height=727
2 screens: Width=679
2048x1080 screen: Window-Maximized=true
ToolBarsMovable=Disabled
[PluginSymbolViewer]
ExpandTree=false
SortSymbols=false
TreeView=false
ViewTypes=false
[Printing][HeaderFooter]
FooterBackground=211,211,211
FooterBackgroundEnabled=false
FooterEnabled=true
FooterForeground=0,0,0
FooterFormatCenter=
FooterFormatLeft=
FooterFormatRight=%U
HeaderBackground=211,211,211
HeaderBackgroundEnabled=false
HeaderEnabled=true
HeaderFooterFont=monospace,10,-1,5,400,0,0,0,1,0,0,0,0,0,0,1
HeaderForeground=0,0,0
HeaderFormatCenter=%f
HeaderFormatLeft=%y
HeaderFormatRight=%p
[Printing][Layout]
BackgroundColorEnabled=false
BoxColor=invalid
BoxEnabled=false
BoxMargin=6
BoxWidth=1
ColorScheme=Printing
Font=monospace,10,-1,5,400,0,0,0,1,0,0,0,0,0,0,1
[Printing][Text]
DontPrintFoldedCode=true
Legend=false
LineNumbers=false
[Shortcut Schemes]
Current Scheme=Default
[Shortcuts]
kate_mdi_focus_toolview_kate_private_plugin_katekonsoleplugin=;\s
kate_mdi_sidebar_visibility=;\s
kate_mdi_toolview_kate_private_plugin_katekonsoleplugin=;\s
kate_mdi_toolview_kateproject=Ctrl+B
kate_mdi_toolview_kateprojectinfo=Alt+T
[debugplugin]
DAPConfiguration=
[filetree]
editShade=183,220,246
listMode=false
middleClickToClose=false
shadingEnabled=true
showCloseButton=false
showFullPathOnRoots=false
showToolbar=true
sortRole=0
viewShade=211,190,222
[lspclient]
AllowedServerCommandLines=/usr/bin/clangd -log=error --background-index --limit-results=500 --completion-style=bundled,/usr/bin/pylsp --check-parent-process
AutoHover=true
AutoImport=true
BlockedServerCommandLines=/usr/bin/python -m esbonio
CompletionDocumentation=true
CompletionParens=true
Diagnostics=true
FormatOnSave=false
HighlightGoto=true
IncrementalSync=true
InlayHints=false
Messages=true
ReferencesDeclaration=true
SemanticHighlighting=true
ServerConfiguration=
SignatureHelp=true
SymbolDetails=false
SymbolExpand=true
SymbolSort=false
SymbolTree=true
TypeFormatting=false
[project]
autoCMake=false
autorepository=git
gitStatusDoubleClick=3
gitStatusSingleClick=0
index=false
indexDirectory=
multiProjectCompletion=false
multiProjectGoto=false
restoreProjectsForSessions=false

@ -0,0 +1,157 @@
configuration {
/* modes: "window,drun,run,ssh";*/
/* font: "mono 12";*/
/* location: 0;*/
/* yoffset: 0;*/
/* xoffset: 0;*/
/* fixed-num-lines: true;*/
/* show-icons: false;*/
/* preview-cmd: ;*/
/* terminal: "rofi-sensible-terminal";*/
/* ssh-client: "ssh";*/
/* ssh-command: "{terminal} -e {ssh-client} {host} [-p {port}]";*/
/* run-command: "{cmd}";*/
/* run-list-command: "";*/
/* run-shell-command: "{terminal} -e {cmd}";*/
/* window-command: "wmctrl -i -R {window}";*/
/* window-match-fields: "all";*/
/* icon-theme: ;*/
/* drun-match-fields: "name,generic,exec,categories,keywords";*/
/* drun-categories: ;*/
/* drun-show-actions: false;*/
/* drun-display-format: "{name} [<span weight='light' size='small'><i>({generic})</i></span>]";*/
/* drun-url-launcher: "xdg-open";*/
/* disable-history: false;*/
/* ignored-prefixes: "";*/
/* sort: false;*/
/* sorting-method: "normal";*/
/* case-sensitive: false;*/
/* cycle: true;*/
/* sidebar-mode: false;*/
/* hover-select: false;*/
/* eh: 1;*/
/* auto-select: false;*/
/* parse-hosts: false;*/
/* parse-known-hosts: true;*/
/* combi-modes: "window,run";*/
/* matching: "normal";*/
/* tokenize: true;*/
/* m: "-5";*/
/* filter: ;*/
/* dpi: -1;*/
/* threads: 0;*/
/* scroll-method: 0;*/
/* window-format: "{w} {c} {t}";*/
/* click-to-exit: true;*/
/* global-kb: false;*/
max-history-size: 1000;
/* combi-hide-mode-prefix: false;*/
/* combi-display-format: "{mode} {text}";*/
/* matching-negate-char: '-' /* unsupported */;*/
/* cache-dir: ;*/
/* window-thumbnail: false;*/
/* drun-use-desktop-cache: false;*/
/* drun-reload-desktop-cache: false;*/
/* normalize-match: false;*/
/* steal-focus: false;*/
/* application-fallback-icon: ;*/
/* refilter-timeout-limit: 300;*/
/* xserver-i300-workaround: false;*/
/* completer-mode: "filebrowser";*/
/* pid: "/run/user/1000/rofi.pid";*/
/* display-window: ;*/
/* display-run: ;*/
/* display-ssh: ;*/
/* display-drun: ;*/
/* display-combi: ;*/
/* display-keys: ;*/
/* display-filebrowser: ;*/
/* display-recursivebrowser: ;*/
/* kb-primary-paste: "Control+V,Shift+Insert";*/
/* kb-secondary-paste: "Control+v,Insert";*/
/* kb-secondary-copy: "Control+c";*/
/* kb-clear-line: "Control+w";*/
/* kb-move-front: "Control+a";*/
/* kb-move-end: "Control+e";*/
/* kb-move-word-back: "Alt+b,Control+Left";*/
/* kb-move-word-forward: "Alt+f,Control+Right";*/
/* kb-move-char-back: "Left,Control+b";*/
/* kb-move-char-forward: "Right,Control+f";*/
/* kb-remove-word-back: "Control+Alt+h,Control+BackSpace";*/
/* kb-remove-word-forward: "Control+Alt+d";*/
/* kb-remove-char-forward: "Delete,Control+d";*/
/* kb-remove-char-back: "BackSpace,Shift+BackSpace,Control+h";*/
/* kb-remove-to-eol: "Control+k";*/
/* kb-remove-to-sol: "Control+u";*/
/* kb-accept-entry: "Control+j,Control+m,Return,KP_Enter";*/
/* kb-accept-custom: "Control+Return";*/
/* kb-accept-custom-alt: "Control+Shift+Return";*/
/* kb-accept-alt: "Shift+Return";*/
/* kb-delete-entry: "Shift+Delete";*/
/* kb-mode-next: "Shift+Right,Control+Tab";*/
/* kb-mode-previous: "Shift+Left,Control+ISO_Left_Tab";*/
/* kb-mode-complete: "Control+l";*/
/* kb-row-left: "Control+Page_Up";*/
/* kb-row-right: "Control+Page_Down";*/
/* kb-row-up: "Up,Control+p";*/
/* kb-row-down: "Down,Control+n";*/
/* kb-row-tab: "";*/
/* kb-element-next: "Tab";*/
/* kb-element-prev: "ISO_Left_Tab";*/
/* kb-page-prev: "Page_Up";*/
/* kb-page-next: "Page_Down";*/
/* kb-row-first: "Home,KP_Home";*/
/* kb-row-last: "End,KP_End";*/
/* kb-row-select: "Control+space";*/
/* kb-screenshot: "Alt+S";*/
/* kb-ellipsize: "Alt+period";*/
/* kb-toggle-case-sensitivity: "grave,dead_grave";*/
/* kb-toggle-sort: "Alt+grave";*/
/* kb-cancel: "Escape,Control+g,Control+bracketleft";*/
/* kb-custom-1: "Alt+1";*/
/* kb-custom-2: "Alt+2";*/
/* kb-custom-3: "Alt+3";*/
/* kb-custom-4: "Alt+4";*/
/* kb-custom-5: "Alt+5";*/
/* kb-custom-6: "Alt+6";*/
/* kb-custom-7: "Alt+7";*/
/* kb-custom-8: "Alt+8";*/
/* kb-custom-9: "Alt+9";*/
/* kb-custom-10: "Alt+0";*/
/* kb-custom-11: "Alt+exclam";*/
/* kb-custom-12: "Alt+at";*/
/* kb-custom-13: "Alt+numbersign";*/
/* kb-custom-14: "Alt+dollar";*/
/* kb-custom-15: "Alt+percent";*/
/* kb-custom-16: "Alt+dead_circumflex";*/
/* kb-custom-17: "Alt+ampersand";*/
/* kb-custom-18: "Alt+asterisk";*/
/* kb-custom-19: "Alt+parenleft";*/
/* kb-select-1: "Super+1";*/
/* kb-select-2: "Super+2";*/
/* kb-select-3: "Super+3";*/
/* kb-select-4: "Super+4";*/
/* kb-select-5: "Super+5";*/
/* kb-select-6: "Super+6";*/
/* kb-select-7: "Super+7";*/
/* kb-select-8: "Super+8";*/
/* kb-select-9: "Super+9";*/
/* kb-select-10: "Super+0";*/
/* kb-entry-history-up: "Control+Up";*/
/* kb-entry-history-down: "Control+Down";*/
/* ml-row-left: "ScrollLeft";*/
/* ml-row-right: "ScrollRight";*/
/* ml-row-up: "ScrollUp";*/
/* ml-row-down: "ScrollDown";*/
/* me-select-entry: "MousePrimary";*/
/* me-accept-entry: "MouseDPrimary";*/
/* me-accept-custom: "Control+MouseDPrimary";*/
timeout {
action: "kb-cancel";
delay: 0;
}
filebrowser {
directories-first: true;
sorting-method: "name";
}
}

@ -3,3 +3,5 @@
name = Siarhei Siniak name = Siarhei Siniak
[core] [core]
pager = less -x2 pager = less -x2
[fetch]
fsckObjects = true

@ -0,0 +1,13 @@
#!/usr/bin/bash
commands gnome-shortcuts \
-a \
'powersave' \
'commands desktop-services --cpufreq-action powersave' \
'<Shift><Alt>1'
commands gnome-shortcuts \
-a \
'performance' \
'commands desktop-services --cpufreq-action performance' \
'<Shift><Alt>2'

2
dotfiles/.mime.types Normal file

@ -0,0 +1,2 @@
# https://terminalroot.com/how-to-open-markdown-files-with-md-extension-in-firefox/
text/plain txt asc text pm el c h cc hh cxx hxx f90 conf log yaml yml

@ -1,4 +1,3 @@
# #
# Copy this to ~/.config/sway/config and edit it to your liking. # Copy this to ~/.config/sway/config and edit it to your liking.
# #
@ -20,21 +19,10 @@ set $term weston-terminal
# on the original workspace that the command was run on. # on the original workspace that the command was run on.
#for_window [app_id="^launcher$"] floating enable, sticky enable, resize set 30 ppt 60 ppt, border pixel 10 #for_window [app_id="^launcher$"] floating enable, sticky enable, resize set 30 ppt 60 ppt, border pixel 10
#set $menu exec $term --class=launcher -e /usr/bin/sway-launcher-desktop #set $menu exec $term --class=launcher -e /usr/bin/sway-launcher-desktop
set $dmenu_path /usr/bin/bemenu-run #set $dmenu_path /usr/bin/bemenu-run
set $dmenu_path rofi -modes run -show run
set $menu $dmenu_path | xargs swaymsg exec -- set $menu $dmenu_path | xargs swaymsg exec --
### Output configuration
#
# Default wallpaper (more resolutions are available in /usr/share/backgrounds/sway/)
#output * bg /usr/share/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill
#
# Example configuration:
#
# output HDMI-A-1 resolution 1920x1080 position 1920,0
#
# You can get the names of your outputs by running: swaymsg -t get_outputs
output HDMI-A-1 resolution 1920x1080 position 0,0
output eDP-1 resolution 1366x748 position 277,1080
### Idle configuration ### Idle configuration
# #
@ -62,18 +50,27 @@ output eDP-1 resolution 1366x748 position 277,1080
# #
# You can get the names of your inputs by running: swaymsg -t get_inputs # You can get the names of your inputs by running: swaymsg -t get_inputs
# Read `man 5 sway-input` for more information about this section. # Read `man 5 sway-input` for more information about this section.
input type:pointer {
# tap enabled
natural_scroll enabled
}
input type:touchpad { input type:touchpad {
tap enabled tap enabled
natural_scroll enabled natural_scroll enabled
# natural_scroll disabled
} }
bindgesture swipe:4:left workspace next bindgesture swipe:4:left workspace next
bindgesture swipe:4:right workspace prev bindgesture swipe:4:right workspace prev
for_window [shell="xwayland"] title_format "[XWayland] %title"
#set $lock_cmd \
# loginctl list-sessions | \
# tail '-n' +2 | head -n -2 | awk '{print $1}' | \
# xargs loginctl lock-session
set $lock_cmd \ set $lock_cmd \
loginctl list-sessions | \ zsh -c "commands loginctl --action lock-session"
tail '-n' +2 | head -n -2 | awk '{print $1}' | \
xargs loginctl lock-session
bindgesture swipe:4:up exec $lock_cmd bindgesture swipe:4:up exec $lock_cmd
@ -82,35 +79,48 @@ bindgesture swipe:4:up exec $lock_cmd
# #
# Basics: # Basics:
# #
bindsym $mod+Shift+l exec $lock_cmd bindsym Shift+$mod+l exec $lock_cmd
bindsym XF86KbdBrightnessDown \ bindsym --locked Shift+mod1+1 \
exec commands \ exec ~/.local/bin/commands \
desktop-services \ desktop-services \
--backlight-decrease \ --cpufreq-action performance
--backlight-type keyboard
bindsym XF86KbdBrightnessUp \ bindsym --locked Shift+mod1+2 \
exec commands \ exec ~/.local/bin/commands \
desktop-services \ desktop-services \
--backlight-increase \ --cpufreq-action powersave
--backlight-type keyboard
bindsym XF86MonBrightnessDown \ bindsym --locked XF86MonBrightnessDown \
exec commands \ exec ~/.local/bin/commands \
desktop-services \ desktop-services \
--backlight-decrease \ --backlight-decrease \
--backlight-type output --backlight-type output
bindsym XF86MonBrightnessUp \ bindsym --locked XF86MonBrightnessUp \
exec commands \ exec ~/.local/bin/commands \
desktop-services \ desktop-services \
--backlight-increase \ --backlight-increase \
--backlight-type output --backlight-type output
bindsym XF86AudioPlay exec bash -c "commands media-play-pause" bindsym --locked XF86KbdBrightnessDown \
bindsym XF86AudioNext exec bash -c "commands media-next" exec ~/.local/bin/commands \
bindsym XF86AudioPrev exec bash -c "commands media-prev" desktop-services \
--backlight-decrease \
--backlight-type keyboard
bindsym --locked XF86KbdBrightnessUp \
exec ~/.local/bin/commands \
desktop-services \
--backlight-increase \
--backlight-type keyboard
bindsym --locked XF86AudioPlay exec zsh -c "commands media-play-pause"
bindsym --locked XF86AudioRaiseVolume exec zsh -c "commands media-raise-volume"
bindsym --locked XF86AudioLowerVolume exec zsh -c "commands media-lower-volume"
bindsym --locked XF86AudioMute exec zsh -c "commands media-toggle-volume"
bindsym --locked XF86AudioNext exec zsh -c "commands media-next"
bindsym --locked XF86AudioPrev exec zsh -c "commands media-prev"
# Start a terminal # Start a terminal
@ -133,11 +143,19 @@ floating_modifier $mod normal
bindsym $mod+Shift+c reload bindsym $mod+Shift+c reload
# Exit sway (logs you out of your Wayland session) # Exit sway (logs you out of your Wayland session)
bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit' bindsym $mod+Shift+e \
exec swaynag -t warning \
-m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' \
-b 'Yes, exit sway' \
'swaymsg exit'
# #
# Moving around: # Moving around:
# #
# Move your focus around # Move your focus around
bindsym Shift+mod1+tab focus prev
bindsym mod1+tab focus next
#bindsym mod1+tab focus mode_toggle
bindsym $mod+$left focus left bindsym $mod+$left focus left
bindsym $mod+$down focus down bindsym $mod+$down focus down
bindsym $mod+$up focus up bindsym $mod+$up focus up
@ -201,6 +219,7 @@ bindsym $mod+v splitv
#bindsym $mod+s layout stacking #bindsym $mod+s layout stacking
#bindsym $mod+w layout tabbed #bindsym $mod+w layout tabbed
#bindsym $mod+e layout toggle split #bindsym $mod+e layout toggle split
bindsym $mod+e layout toggle all
# Make the current focus fullscreen # Make the current focus fullscreen
bindsym $mod+f fullscreen bindsym $mod+f fullscreen
@ -212,7 +231,8 @@ bindsym $mod+p floating toggle
## Swap focus between the tiling area and the floating area ## Swap focus between the tiling area and the floating area
#bindsym $mod+space focus mode_toggle #bindsym $mod+space focus mode_toggle
bindsym --release Print exec bash -c "commands wl-screenshot" bindsym --release Print exec zsh -c "commands wl-screenshot"
bindsym --release $mod+s exec zsh -c "commands wl-screenshot"
# Move focus to the parent container # Move focus to the parent container
#bindsym $mod+a focus parent #bindsym $mod+a focus parent
@ -253,6 +273,40 @@ mode "resize" {
} }
bindsym $mod+r mode "resize" bindsym $mod+r mode "resize"
set $black #000000
set $red #ff0000
set $green #00ff00
set $blue #0000ff
set $white #ffffff
set $grey #757575
set $pale_green #9df882
set $pale_green2 #6baf54
set $dark_green #1a7000
set $pale_blue #7da9f9
set $dark_blue #005ba6
set $pale_greenblue #2da078
set $pale_greenblue2 #66c473
set $yellow #fffd0d
set $dark_yellow #908f00
set $color1 #18ff00
set $color2 #000000
set $color3 #ff00ff
set $color4 #ff0000
set $color5 #00000000
set $color6 #00000000
set $color7 #00000000
set $border_focused $pale_green
set $border_unfocused $color2
set $background_focused $pale_greenblue2
set $background_unfocused $grey
set $child_border_focused $white
set $child_border_unfocused $color2
set $bright_text $white
set $dark_text $black
# #
# Status Bar: # Status Bar:
# #
@ -263,7 +317,7 @@ bar {
# When the status_command prints a new line to stdout, swaybar updates. # When the status_command prints a new line to stdout, swaybar updates.
# The default just shows the current date and time. # The default just shows the current date and time.
status_command while true; \ status_command while true; \
do commands status --config ~/.config/commands-status.json; \ do ~/.local/bin/commands status --config ~/.config/commands-status.json; \
sleep 1; \ sleep 1; \
done done
@ -272,27 +326,34 @@ bar {
height 16 height 16
colors { colors {
statusline #565656 statusline $bright_text
background #dfdfdf background $pale_green2
inactive_workspace #dfdfdf #dfdfdf #000000 inactive_workspace $black $white $dark_text
active_workspace #dfdfdf #efefef #000000 active_workspace $black $white $bright_text
focused_workspace #dfdfdf #efefef #000000 focused_workspace $dark_yellow $yellow $dark_text
} }
} }
client.focused #f3f3f3 #dfdfdf #565656 #f3f3f3 #f3f3f3
client.unfocused #f3f3f3 #dfdfdf #565656 #f3f3f3 #f3f3f3 #client.focused #f3f3f3 #dfdfdfdd #565656 #f3f3f3 #f3f3f3
client.focused $border_focused $background_focused $white $white $child_border_focused
client.unfocused $border_unfocused $background_unfocused $white $white $child_border_unfocused
for_window [all] border 1
#font pango:Helvetica Neue 10 #font pango:Helvetica Neue 10
font pango:Terminus 10 font pango:Terminus 12
titlebar_padding 1 4 titlebar_padding 32 1
titlebar_border_thickness 1
title_align center title_align center
#for_window [class=".*"] title_format "<b>%title</b>" #for_window [class=".*"] title_format "<b>%title</b>"
for_window [class="^firefox$"] floating enable for_window [class="^firefox$"] floating enable
for_window [all] opacity set 0.95
input * { input * {
xkb_layout "us,ru" xkb_layout "us,ru"
xkb_options "grp:win_space_toggle" xkb_options "grp:win_space_toggle"
@ -300,3 +361,4 @@ input * {
input type:keyboard xkb_model "pc101" input type:keyboard xkb_model "pc101"
include /etc/sway/config.d/* include /etc/sway/config.d/*
include ~/.sway/config.d/*

@ -0,0 +1,20 @@
### Output configuration
#
# Default wallpaper (more resolutions are available in /usr/share/backgrounds/sway/)
#output * bg /usr/share/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill
#
# Example configuration:
#
# output HDMI-A-1 resolution 1920x1080 position 1920,0
#
# You can get the names of your outputs by running: swaymsg -t get_outputs
#2560 x 1440
output 'Dell Inc. DELL P2418D MY3ND8220WKT' resolution 1920x1080 position 0,0
#output 'Dell Inc. DELL P2418D MY3ND8220WKT' mode resolution 2560x1440 position 0,0
#output HDMI-A-1 resolution 1920x1080 transform 90 position 0,0
output 'LG Electronics LG FHD 403TOAG3C208 ' resolution 1920x1080 transform 90 position 0,0
#output eDP-1 resolution 1366x748 position 277,1080
#output eDP-1 resolution 1366x748 disable power off position 277,1080
output 'Apple Computer Inc Color LCD Unknown' \
resolution 1366x748 enable power on position 277,1080
bindsym --locked $mod+u output 'Apple Computer Inc Color LCD Unknown' toggle

@ -1,2 +1,6 @@
ACTION=="add|change", SUBSYSTEM=="leds", DEVPATH=="/devices/pci0000:00/0000:00:1b.0/hdaudioC0D0/leds/hda::mute", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness" ACTION=="add|change", SUBSYSTEM=="leds", DEVPATH=="/devices/pci0000:00/0000:00:1b.0/hdaudioC0D0/leds/hda::mute", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
ACTION=="add|change", SUBSYSTEM=="leds", DEVPATH=="/devices/platform/applesmc.768/leds/smc::kbd_backlight", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness" ACTION=="add|change", SUBSYSTEM=="leds", DEVPATH=="/devices/platform/applesmc.768/leds/smc::kbd_backlight", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
ACTION=="add|change", DEVPATH=="/devices/platform/applesmc.768", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/fan1_manual /sys$devpath/fan1_output"
ACTION=="add|change", DEVPATH=="/class/backlight/intel_backlight", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
ACTION=="add|change", DEVPATH=="/devices/system/cpu/", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/cpufreq/scaling_governor"
ACTION=="add|change", KERNEL=="cpu[0-9]", SUBSYSTEM=="cpu", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/cpufreq/scaling_governor"

338
m.py Executable file

@ -0,0 +1,338 @@
#!/usr/bin/env python3
import glob
import io
import tempfile
import dataclasses
import pathlib
import sys
import subprocess
import os
import logging
from typing import (Optional, Any,)
from typing_extensions import (
Self, BinaryIO,
)
logger = logging.getLogger(__name__)
def toml_load(f: BinaryIO) -> Any:
try:
import tomllib
return tomllib.load(f)
except:
pass
try:
import tomli
return tomli.load(f)
except:
pass
raise NotImplementedError
@dataclasses.dataclass
class PyProject:
path: pathlib.Path
dependencies: dict[str, list[str]]
early_features: Optional[list[str]] = None
pip_find_links: Optional[list[pathlib.Path]] = None
runtime_libdirs: Optional[list[pathlib.Path]] = None
runtime_preload: Optional[list[pathlib.Path]] = None
requirements: dict[str, pathlib.Path] = dataclasses.field(default_factory=lambda : dict())
def pyproject_load(
d: pathlib.Path,
) -> PyProject:
with io.open(d, 'rb') as f:
content = toml_load(f)
assert isinstance(content, dict)
dependencies : dict[str, list[str]] = dict()
dependencies['default'] = content['project']['dependencies']
if (
'optional-dependencies' in content['project']
):
assert isinstance(
content['project']['optional-dependencies'],
dict
)
for k, v in content['project']['optional-dependencies'].items():
assert isinstance(v, list)
assert isinstance(k, str)
dependencies[k] = v
res = PyProject(
path=d,
dependencies=dependencies,
)
tool_name = 'online.fxreader.pr34'.replace('.', '-')
if (
'tool' in content and
isinstance(
content['tool'], dict
) and
tool_name in content['tool'] and
isinstance(
content['tool'][tool_name],
dict
)
):
if 'early_features' in content['tool'][tool_name]:
res.early_features = content['tool'][tool_name]['early_features']
if 'pip_find_links' in content['tool'][tool_name]:
res.pip_find_links = [
d.parent / pathlib.Path(o)
for o in content['tool'][tool_name]['pip_find_links']
]
if 'runtime_libdirs' in content['tool'][tool_name]:
res.runtime_libdirs = [
d.parent / pathlib.Path(o)
# pathlib.Path(o)
for o in content['tool'][tool_name]['runtime_libdirs']
]
if 'runtime_preload' in content['tool'][tool_name]:
res.runtime_preload = [
d.parent / pathlib.Path(o)
# pathlib.Path(o)
for o in content['tool'][tool_name]['runtime_preload']
]
if 'requirements' in content['tool'][tool_name]:
assert isinstance(content['tool'][tool_name]['requirements'], dict)
res.requirements = {
k : d.parent / pathlib.Path(v)
# pathlib.Path(o)
for k, v in content['tool'][tool_name]['requirements'].items()
}
return res
@dataclasses.dataclass
class BootstrapSettings:
env_path: pathlib.Path
python_path: pathlib.Path
base_dir: pathlib.Path
python_version: Optional[str] = dataclasses.field(
default_factory=lambda : os.environ.get(
'PYTHON_VERSION',
'%d.%d' % (
sys.version_info.major,
sys.version_info.minor,
),
).strip()
)
uv_args: list[str] = dataclasses.field(
default_factory=lambda : os.environ.get(
'UV_ARGS',
'--offline',
).split(),
)
@classmethod
def get(
cls,
base_dir: Optional[pathlib.Path] = None,
) -> Self:
if base_dir is None:
base_dir = pathlib.Path.cwd()
env_path = base_dir / '.venv'
python_path = env_path / 'bin' / 'python3'
return cls(
base_dir=base_dir,
env_path=env_path,
python_path=python_path,
)
def env_bootstrap(
bootstrap_settings: BootstrapSettings,
pyproject: PyProject,
) -> None:
pip_find_links : list[pathlib.Path] = []
if not pyproject.pip_find_links is None:
pip_find_links.extend(pyproject.pip_find_links)
pip_find_links_args = sum([
['-f', str(o),]
for o in pip_find_links
], [])
features : list[str] = []
if pyproject.early_features:
features.extend(pyproject.early_features)
requirements_python_version: Optional[str] = None
if not bootstrap_settings.python_version is None:
requirements_python_version = bootstrap_settings.python_version.replace('.', '_')
requirements_name = '_'.join(sorted(features))
if requirements_python_version:
requirements_name += '_' + requirements_python_version
requirements_path : Optional[pathlib.Path] = None
if requirements_name in pyproject.requirements:
requirements_path = pyproject.requirements[requirements_name]
else:
requirements_path = pyproject.path.parent / 'requirements.txt'
requirements_in : list[str] = []
requirements_in.extend([
'uv', 'pip', 'build', 'setuptools', 'meson-python', 'pybind11'
])
if pyproject.early_features:
early_dependencies = sum([
pyproject.dependencies[o]
for o in pyproject.early_features
], [])
logger.info(dict(
early_dependencies=early_dependencies,
))
requirements_in.extend(early_dependencies)
# if len(early_dependencies) > 0:
# subprocess.check_call([
# bootstrap_settings.python_path,
# '-m',
# 'uv', 'pip', 'install',
# *pip_find_links_args,
# # '-f', str(pathlib.Path(__file__).parent / 'deps' / 'dist'),
# *bootstrap_settings.uv_args,
# *early_dependencies,
# ])
if not requirements_path.exists():
with tempfile.NamedTemporaryFile(
mode='w',
prefix='requirements',
suffix='.in',
) as f:
f.write(
'\n'.join(requirements_in)
)
f.flush()
subprocess.check_call([
'uv',
'pip',
'compile',
'--generate-hashes',
*pip_find_links_args,
# '-p',
# bootstrap_settings.python_path,
*bootstrap_settings.uv_args,
'-o', str(requirements_path),
f.name,
])
uv_python_version: list[str] = []
if not bootstrap_settings.python_version is None:
uv_python_version.extend([
'-p', bootstrap_settings.python_version,
])
subprocess.check_call([
'uv', 'venv',
*uv_python_version,
*pip_find_links_args,
# '--seed',
*bootstrap_settings.uv_args,
str(bootstrap_settings.env_path)
])
subprocess.check_call([
'uv',
'pip',
'install',
*pip_find_links_args,
'-p',
bootstrap_settings.python_path,
'--require-hashes',
*bootstrap_settings.uv_args,
'-r', str(requirements_path),
])
def paths_equal(
a: pathlib.Path | str,
b: pathlib.Path | str
) -> bool:
return (
os.path.abspath(str(a)) ==
os.path.abspath(str(b))
)
def run(
d: Optional[pathlib.Path] = None,
cli_path: Optional[pathlib.Path] = None,
) -> None:
if cli_path is None:
cli_path = pathlib.Path(__file__).parent / 'cli.py'
if d is None:
d = pathlib.Path(__file__).parent / 'pyproject.toml'
bootstrap_settings = BootstrapSettings.get()
pyproject : PyProject = pyproject_load(
d
)
logging.basicConfig(level=logging.INFO)
if not bootstrap_settings.env_path.exists():
env_bootstrap(
bootstrap_settings=bootstrap_settings,
pyproject=pyproject,
)
logger.info([sys.executable, sys.argv, bootstrap_settings.python_path])
if not paths_equal(sys.executable, bootstrap_settings.python_path):
os.execv(
str(bootstrap_settings.python_path),
[
str(bootstrap_settings.python_path),
*sys.argv,
]
)
os.execv(
str(bootstrap_settings.python_path),
[
str(bootstrap_settings.python_path),
str(
cli_path
),
*sys.argv[1:],
]
)
if __name__ == '__main__':
run(
d=pathlib.Path(__file__).parent / 'python' / 'pyproject.toml',
cli_path=pathlib.Path(__file__).parent / 'python' / 'cli.py',
)

@ -0,0 +1,6 @@
import distutils.command
from typing import (Any,)
def _get_build_extension() -> distutils.command.build_ext: ...
def load_dynamic(name: str, path: str) -> Any: ...

@ -0,0 +1,17 @@
import setuptools.extension
from typing import (Iterable,)
def cythonize(
module_list: str | Iterable[str]
#module_list,
#exclude=None,
#nthreads=0,
#aliases=None,
#quiet=False,
#force=None,
#language=None,
#exclude_failures=False,
#show_all_warnings=False,
#**options
) -> list[setuptools.extension.Extension]: ...

@ -0,0 +1,7 @@
from typing import (Type, Any, Self)
class NoGIL:
def __enter__(self) -> Self: ...
def __exit__(self, exc_class: Type[Exception], exc: Exception, tb: Any) -> None: ...
nogil : NoGIL = NoGIL()

@ -0,0 +1,14 @@
import setuptools.extension
import pathlib
class build_ext:
extensions : list[setuptools.extension.Extension]
#build_temp : pathlib.Path
#build_lib: pathlib.Path
build_temp: str
build_lib: str
def run(self) -> None:
...
...

@ -0,0 +1,8 @@
from typing import (Iterable,)
class Trie:
def __init__(self, entries: Iterable[str]) -> None: ...
def keys(self, entry: str) -> list[str]: ...
def __contains__(self, entry: str) -> bool: ...

@ -0,0 +1,18 @@
import setuptools.extension
from typing import (Any, Iterable,)
def mypycify(
paths: 'list[str]',
*,
only_compile_paths: 'Iterable[str] | None' = None,
verbose: 'bool' = False,
opt_level: 'str' = '3',
debug_level: 'str' = '1',
strip_asserts: 'bool' = False,
multi_file: 'bool' = False,
separate: 'bool | list[tuple[list[str], str | None]]' = False,
skip_cgen_input: 'Any | None' = None,
target_dir: 'str | None' = None,
include_runtime_files: 'bool | None' = None,
) -> 'list[setuptools.extension.Extension]': ...

@ -0,0 +1,8 @@
from typing import (Self, Any)
class tqdm:
def __enter__(self) -> Self: ...
def __exit__(self, args: Any) -> None: ...
def update(self, delta: int) -> None: ...
def set_description(self, description: str) -> None: ...

@ -0,0 +1,7 @@
def listen(
addr: tuple[str, int],
) -> None: ...
def wait_for_client() -> None: ...
def breakpoint() -> None: ...

@ -0,0 +1,6 @@
[Unit]
Description=udev scripts
[Service]
Type=simple
ExecStart=/usr/local/bin/online-fxreader-pr34-udev --device=%I

@ -0,0 +1,11 @@
ACTION=="add|change", SUBSYSTEM=="leds", DEVPATH=="/devices/pci0000:00/0000:00:1b.0/hdaudioC0D0/leds/hda::mute", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
ACTION=="add|change", SUBSYSTEM=="leds", DEVPATH=="/devices/platform/applesmc.768/leds/smc::kbd_backlight", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
# udevadm info --attribute-walk --path=/sys/devices/platform/applesmc.768/
# udevadm trigger --action=add --verbose --parent-match /devices/platform/applesmc.768/
#ACTION=="add|change", KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", RUN{program}+="ls -allh /sys$devpath/", OPTIONS="log_level=debug"
#ACTION=="add|change", KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", RUN{program}+="/usr/bin/ls -allh /sys$devpath/", OPTIONS="log_level=debug"
ACTION=="add|change", KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", TAG+="systemd", ENV{SYSTEMD_WANTS}="online.fxreader.pr34.udev@$devnode.service", OPTIONS="log_level=debug"
#KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", MODE="0660", TAG+="uaccess", OPTIONS="log_level=debug", OPTIONS+="watch"
ACTION=="add|change", DEVPATH=="/class/backlight/intel_backlight", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
ACTION=="add|change", KERNEL=="cpu0", SUBSYSTEM=="cpu", TAG+="systemd", ENV{SYSTEMD_WANTS}="online.fxreader.pr34.udev@$devnode.service", OPTIONS="log_level=debug"
ACTION=="add|change", KERNEL=="cpu[0-9]", SUBSYSTEM=="cpu", TAG+="systemd", ENV{SYSTEMD_WANTS}="online.fxreader.pr34.udev@$devnode.service", OPTIONS="log_level=debug"

@ -0,0 +1,103 @@
#!/usr/bin/python3
# vi: filetype=python
import re
import sys
import os
import subprocess
import argparse
import logging
from typing import (Any,)
logger = logging.getLogger(__name__)
def run() -> None:
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser()
parser.add_argument(
'--device',
)
options = parser.parse_args()
DEVICES : dict[str, Any] = dict(
applesmc=dict(
devpath='sys/devices/platform/applesmc.768',
node='/sys/devices/platform/applesmc.768/fan1_manual',
cmd=r'''
chown root:fan /sys/devices/platform/applesmc.768/fan1_*
chmod g+w /sys/devices/platform/applesmc.768/fan1_*
''',
),
intel_pstate=dict(
devpath=r'/?sys/devices/system/cpu/cpu0',
node='/sys/devices/system/cpu/intel_pstate/no_turbo',
cmd=r'''
chown root:fan /sys/devices/system/cpu/intel_pstate/no_turbo
chown root:fan /sys/devices/system/cpu/intel_pstate/max_perf_pct
#chown root:fan /sys/devices/system/cpu/intel_pstate/status
chmod g+w /sys/devices/system/cpu/intel_pstate/no_turbo
chmod g+w /sys/devices/system/cpu/intel_pstate/max_perf_pct
#chmod g+w /sys/devices/system/cpu/intel_pstate/status
echo passive > /sys/devices/system/cpu/intel_pstate/status
chown root:fan /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
chown root:fan /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
chmod g+w /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
chmod g+w /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
''',
),
#governor=dict(
# devpath=r'/?sys/devices/system/cpu/cpu(\d+)',
# node=r'/sys/devices/system/cpu/cpu{0}/cpufreq/scaling_governor',
# cmd=r'''
# chown root:fan /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_governor
# chown root:fan /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_max_freq
# chmod g+w /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_governor
# chmod g+w /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_max_freq
# ''',
#),
)
processed : int = 0
logger.info(dict(device=options.device))
for k, v in DEVICES.items():
devpath = re.compile(v['devpath'])
devpath_m = devpath.match(options.device)
if devpath_m is None:
continue
node_2 = v['node'].format(*devpath_m.groups())
# logger.info(dict(devpath_m=devpath_m, node=node_2))
while not os.path.exists(node_2):
#continue
time.sleep(1)
cmd_2 = v['cmd'].format(*devpath_m.groups())
subprocess.check_call(cmd_2, shell=True)
logger.info(dict(
devpath_m=devpath_m,
node_2=node_2,
cmd_2=cmd_2,
msg='processed',
label=k,
))
processed += 1
if processed == 0:
raise NotImplementedError
if __name__ == '__main__':
run()

@ -0,0 +1,6 @@
[Unit]
Description=udev scripts
[Service]
Type=simple
ExecStart=/usr/local/bin/online-fxreader-pr34-udev --device=%I

@ -0,0 +1,26 @@
[Unit]
Description=Disable and Re-Enable Apple BCE Module (and Wi-Fi)
Before=sleep.target
Before=hibernate.target
StopWhenUnneeded=yes
[Service]
User=root
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/online-fxreader-pr34-suspend-fix-t2 disable_apple_bce
#ExecStart=/usr/bin/modprobe -r apple_bce
#ExecStart=/usr/bin/modprobe -r brcmfmac_wcc
#ExecStart=/usr/bin/modprobe -r brcmfmac
#ExecStart=/usr/bin/rmmod -f apple-bce
ExecStop=/usr/local/bin/online-fxreader-pr34-suspend-fix-t2 enable_apple_bce
#ExecStop=/usr/bin/modprobe -r apple_bce
#ExecStop=/usr/bin/modprobe apple-bce
#ExecStop=/usr/bin/modprobe brcmfmac
#ExecStop=/usr/bin/modprobe brcmfmac_wcc
[Install]
WantedBy=sleep.target
WantedBy=hibernate.target

@ -0,0 +1,13 @@
ACTION=="add|change", SUBSYSTEM=="leds", DEVPATH=="/devices/pci0000:00/0000:00:1b.0/hdaudioC0D0/leds/hda::mute", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
ACTION=="add|change", SUBSYSTEM=="leds", DEVPATH=="/devices/platform/applesmc.768/leds/smc::kbd_backlight", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
# udevadm info --attribute-walk --path=/sys/devices/platform/applesmc.768/
# udevadm trigger --action=add --verbose --parent-match /devices/platform/applesmc.768/
#ACTION=="add|change", KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", RUN{program}+="ls -allh /sys$devpath/", OPTIONS="log_level=debug"
#ACTION=="add|change", KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", RUN{program}+="/usr/bin/ls -allh /sys$devpath/", OPTIONS="log_level=debug"
#ACTION=="add|change", KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", TAG+="systemd", ENV{SYSTEMD_WANTS}="online.fxreader.pr34.udev@$devnode.service", OPTIONS="log_level=debug"
ACTION=="add|change", KERNEL=="cpu0", SUBSYSTEM=="cpu", TAG+="systemd", ENV{SYSTEMD_WANTS}="online.fxreader.pr34.udev@$devnode.service", OPTIONS="log_level=debug"
#KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", MODE="0660", TAG+="uaccess", OPTIONS="log_level=debug", OPTIONS+="watch"
ACTION=="add|change", DEVPATH=="/class/backlight/intel_backlight", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
#ACTION=="add|change", DEVPATH=="/devices/system/cpu/", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/cpufreq/scaling_governor"
ACTION=="add|change", KERNEL=="cpu[0-9]", SUBSYSTEM=="cpu", TAG+="systemd", ENV{SYSTEMD_WANTS}="online.fxreader.pr34.udev@$devnode.service", OPTIONS="log_level=debug"

@ -0,0 +1,113 @@
#!/usr/bin/env python3
# vi: set filetype=python
import sys
import time
import argparse
import subprocess
parser = argparse.ArgumentParser()
parser.add_argument('mode', choices=[
'disable_apple_bce',
'enable_apple_bce',
])
options = parser.parse_args()
if options.mode == 'disable_apple_bce':
while True:
ret = subprocess.call([
'systemctl', 'stop', 'iwd',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'modprobe', '-r', 'brcmfmac_wcc',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'modprobe', '-r', 'brcmfmac',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'modprobe', '-r', 'applesmc',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'rmmod', '-f', 'apple-bce',
])
#if ret != 0:
# time.sleep(1)
#else:
# break
break
elif options.mode == 'enable_apple_bce':
while True:
ret = subprocess.call([
'modprobe', 'applesmc',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'modprobe', 'apple-bce',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'modprobe', 'brcmfmac',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'modprobe', 'brcmfmac_wcc',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'systemctl', 'start', 'iwd',
])
if ret != 0:
time.sleep(1)
else:
break
else:
raise NotImplementedError

@ -0,0 +1,103 @@
#!/usr/bin/python3
# vi: filetype=python
import re
import sys
import os
import subprocess
import argparse
import logging
from typing import (Any,)
logger = logging.getLogger(__name__)
def run() -> None:
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser()
parser.add_argument(
'--device',
)
options = parser.parse_args()
DEVICES : dict[str, Any] = dict(
applesmc=dict(
devpath='sys/devices/platform/applesmc.768',
node='/sys/devices/platform/applesmc.768/fan1_manual',
cmd=r'''
chown root:fan /sys/devices/platform/applesmc.768/fan1_*
chmod g+w /sys/devices/platform/applesmc.768/fan1_*
''',
),
intel_pstate=dict(
devpath=r'/?sys/devices/system/cpu/cpu0',
node='/sys/devices/system/cpu/intel_pstate/no_turbo',
cmd=r'''
chown root:fan /sys/devices/system/cpu/intel_pstate/no_turbo
chown root:fan /sys/devices/system/cpu/intel_pstate/max_perf_pct
#chown root:fan /sys/devices/system/cpu/intel_pstate/status
chmod g+w /sys/devices/system/cpu/intel_pstate/no_turbo
chmod g+w /sys/devices/system/cpu/intel_pstate/max_perf_pct
#chmod g+w /sys/devices/system/cpu/intel_pstate/status
echo passive > /sys/devices/system/cpu/intel_pstate/status
chown root:fan /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
chown root:fan /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
chmod g+w /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
chmod g+w /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
''',
),
#governor=dict(
# devpath=r'/?sys/devices/system/cpu/cpu(\d+)',
# node=r'/sys/devices/system/cpu/cpu{0}/cpufreq/scaling_governor',
# cmd=r'''
# chown root:fan /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_governor
# chown root:fan /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_max_freq
# chmod g+w /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_governor
# chmod g+w /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_max_freq
# ''',
#),
)
processed : int = 0
logger.info(dict(device=options.device))
for k, v in DEVICES.items():
devpath = re.compile(v['devpath'])
devpath_m = devpath.match(options.device)
if devpath_m is None:
continue
node_2 = v['node'].format(*devpath_m.groups())
# logger.info(dict(devpath_m=devpath_m, node=node_2))
while not os.path.exists(node_2):
#continue
time.sleep(1)
cmd_2 = v['cmd'].format(*devpath_m.groups())
subprocess.check_call(cmd_2, shell=True)
logger.info(dict(
devpath_m=devpath_m,
node_2=node_2,
cmd_2=cmd_2,
msg='processed',
label=k,
))
processed += 1
if processed == 0:
raise NotImplementedError
if __name__ == '__main__':
run()

254
python/_m.py Normal file

@ -0,0 +1,254 @@
#!/usr/bin/env python3
#vim: set filetype=python
import logging
import json
import enum
import pathlib
import sys
import argparse
#import optparse
import dataclasses
import subprocess
import os
from typing import (
Optional, Any, TypeAlias, Literal, cast, BinaryIO, Generator,
ClassVar, Self,
)
logger = logging.getLogger()
@dataclasses.dataclass
class Settings:
project_root : pathlib.Path = pathlib.Path.cwd()
env_path : pathlib.Path = project_root / 'tmp' / 'env3'
_settings : ClassVar[Optional['Settings']] = None
@classmethod
def settings(cls) -> Self:
if cls._settings is None:
cls._settings = cls()
return cls._settings
def js(argv: list[str]) -> int:
return subprocess.check_call([
'sudo',
'docker-compose',
'--project-directory',
Settings.settings().project_root,
'-f',
Settings.settings().project_root / 'docker' / 'js' / 'docker-compose.yml',
*argv,
])
def env(
argv: Optional[list[str]] = None,
mode: Literal['exec', 'subprocess'] = 'subprocess',
**kwargs: Any,
) -> Optional[subprocess.CompletedProcess[bytes]]:
env_path = Settings.settings().env_path
if not env_path.exists():
subprocess.check_call([
sys.executable, '-m', 'venv',
'--system-site-packages',
str(env_path)
])
subprocess.check_call([
env_path / 'bin' / 'python3',
'-m', 'pip',
'install', '-r', 'requirements.txt',
])
if not argv is None:
python_path = str(env_path / 'bin' / 'python3')
if mode == 'exec':
os.execv(
python_path,
[
python_path,
*argv,
],
)
return None
elif mode == 'subprocess':
return subprocess.run([
python_path,
*argv,
], **kwargs)
else:
raise NotImplementedError
return None
def ruff(argv: list[str]) -> None:
parser = argparse.ArgumentParser()
parser.add_argument(
'-i',
dest='paths',
help='specify paths to check',
default=[],
action='append',
)
parser.add_argument(
'-e',
dest='exclude',
help='rules to ignore',
default=[],
action='append',
)
options, args = parser.parse_known_args(argv)
if len(options.paths) == 0:
options.paths.extend([
'.',
'dotfiles/.local/bin/commands',
])
if len(options.exclude) == 0:
options.exclude.extend([
'E731',
'E713',
'E714',
'E703',
])
res = env([
'-m',
'ruff',
'check',
*args,
'--output-format', 'json',
'--ignore', ','.join(options.exclude),
*options.paths,
], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
assert not res is None
errors = json.loads(res.stdout.decode('utf-8'))
g: dict[str, Any] = dict()
for o in errors:
if not o['filename'] in g:
g[o['filename']] = []
g[o['filename']].append(o)
h = {
k : len(v)
for k, v in g.items()
}
logger.info(json.dumps(errors, indent=4))
logger.info(json.dumps(h, indent=4))
def inside_env() -> bool:
try:
import numpy
return True
except Exception:
return False
#class Commands(enum.StrEnum):
# js = 'js'
# mypy = 'mypy'
# env = 'env'
# ruff = 'ruff'
# m2 = 'm2'
# def mypy(argv: list[str]) -> None:
# import online.fxreader.pr34.commands_typed.mypy as _mypy
# _mypy.run(
# argv,
# )
def host_deps(argv: list[str]) -> None:
if sys.platform in ['linux']:
subprocess.check_call(r'''
exec yay -S $(cat requirements-archlinux.txt)
''', shell=True,)
else:
raise NotImplementedError
Command_args = ['js', 'mypy', 'env', 'ruff', 'm2', 'host_deps',]
Command : TypeAlias = Literal['js', 'mypy', 'env', 'ruff', 'm2', 'host_deps',]
def run(argv: Optional[list[str]] = None) -> None:
logging.basicConfig(
level=logging.INFO,
format=(
'%(levelname)s:%(name)s:%(message)s'
':%(process)d'
':%(asctime)s'
':%(pathname)s:%(funcName)s:%(lineno)s'
),
)
if argv is None:
argv = sys.argv[:]
parser = argparse.ArgumentParser()
parser.add_argument(
'command',
#'_command',
choices=[
o
for o in Command_args
],
#required=True,
)
options, args = parser.parse_known_args(argv[1:])
assert options.command in Command_args
if len(args) > 0 and args[0] == '--':
del args[0]
#options.command = Commands(options._command)
if options.command == 'js':
js(args)
elif options.command == 'host_deps':
host_deps(args)
elif options.command == 'env':
env(args, mode='exec',)
# elif options.command == 'mypy':
# if not inside_env():
# env(
# [
# pathlib.Path(__file__).parent / 'm.py',
# *argv[1:],
# ],
# mode='exec'
# )
# else:
# mypy(args)
elif options.command == 'ruff':
ruff(args)
elif options.command == 'm2':
if not inside_env():
env(['--', '_m.py', 'm2', *args])
return
import python.tasks.cython
python.tasks.cython.mypyc_build(
pathlib.Path('_m.py')
)
else:
raise NotImplementedError
if __name__ == '__main__':
run()

162
python/cli.py Normal file

@ -0,0 +1,162 @@
import sys
import shutil
import glob
import io
import copy
import subprocess
import pathlib
import logging
import enum
import argparse
import dataclasses
from typing import (Optional, override,)
from online.fxreader.pr34.commands_typed.logging import setup as logging_setup
from online.fxreader.pr34.commands_typed import cli as _cli
from online.fxreader.pr34.commands_typed import cli_bootstrap
logging_setup()
logger = logging.getLogger(__name__)
class Command(enum.StrEnum):
mypy = 'mypy'
deploy_wheel = 'deploy:wheel'
tests = 'tests'
@dataclasses.dataclass
class Settings(
_cli.DistSettings,
):
base_dir: pathlib.Path = pathlib.Path(__file__).parent.parent
build_dir: pathlib.Path = base_dir / 'tmp' / 'build'
wheel_dir: pathlib.Path = base_dir / 'deps' / 'dist'
env_path: pathlib.Path = cli_bootstrap.BootstrapSettings.get(base_dir).env_path
python_path: pathlib.Path = cli_bootstrap.BootstrapSettings.get(base_dir).python_path
class CLI(_cli.CLI):
def __init__(self) -> None:
self.settings = Settings()
self._projects: dict[str, _cli.Project] = {
'online.fxreader.pr34': _cli.Project(
source_dir=self.settings.base_dir / 'python',
build_dir=self.settings.base_dir / 'tmp' / 'online' / 'fxreader' / 'pr34' / 'build',
dest_dir=self.settings.base_dir / 'tmp' / 'online' / 'fxreader' / 'pr34' / 'install',
)
}
self._dependencies : dict[str, _cli.Dependency] = dict()
@override
@property
def dist_settings(self) -> _cli.DistSettings:
return self.settings
@override
@property
def projects(self) -> dict[str, _cli.Project]:
return self._projects
def mypy(
self,
argv: list[str],
) -> None:
import online.fxreader.pr34.commands_typed.mypy as _mypy
project = self._projects['online.fxreader.pr34']
_mypy.run(
argv,
settings=_mypy.MypySettings(
paths=[
#Settings.settings().project_root / 'dotfiles/.local/bin/commands',
# project.source_dir / 'm.py',
project.source_dir / '_m.py',
project.source_dir / 'online',
project.source_dir / 'cli.py',
self.settings.base_dir / 'm.py',
# Settings.settings().project_root / 'deps/com.github.aiortc.aiortc/src',
#Settings.settings().project_root / 'm.py',
],
max_errors={
'python/online/fxreader/pr34/commands_typed': 0,
'python/cli.py': 0,
'm.py': 0,
'deps/com.github.aiortc.aiortc/src/online_fxreader': 0,
'deps/com.github.aiortc.aiortc/src/aiortc/contrib/signaling': 0
}
),
)
@override
@property
def dependencies(self) -> dict[str, _cli.Dependency]:
return self._dependencies
def run(self, argv: Optional[list[str]] = None) -> None:
if argv is None:
argv = copy.deepcopy(sys.argv)
parser = argparse.ArgumentParser()
parser.add_argument(
'command',
choices=[
o.value
for o in Command
]
)
parser.add_argument(
'-p', '--project',
choices=[
o
for o in self.projects
]
)
parser.add_argument(
'-o', '--output_dir',
default=None,
help='wheel output dir for deploy:wheel',
)
parser.add_argument(
'-f', '--force',
default=False,
action='store_true',
help='remove install dir, before installing, default = false',
)
options, args = parser.parse_known_args(argv[1:])
options.command = Command(options.command)
if options.command is Command.deploy_wheel:
assert not options.project is None
self.deploy_wheel(
project_name=options.project,
argv=args,
output_dir=options.output_dir,
mypy=True,
)
elif options.command is Command.mypy:
self.mypy(
argv=args,
)
elif options.command is Command.tests:
for k, v in self.projects.items():
subprocess.check_call([
sys.executable,
'-m',
'unittest',
'online.fxreader.pr34.tests.test_crypto',
*args,
], cwd=str(v.source_dir))
else:
raise NotImplementedError
if __name__ == '__main__':
CLI().run()

File diff suppressed because it is too large Load Diff

@ -0,0 +1,27 @@
__all__ = (
'parse_args',
)
import sys
import argparse
from typing import (Optional,)
def parse_args(
parser: argparse.ArgumentParser,
args: Optional[list[str]] = None,
) -> tuple[argparse.Namespace, list[str]]:
if args is None:
args = sys.argv[1:]
argv : list[str] = []
for i, o in enumerate(args):
if o == '--':
argv.extend(args[i + 1:])
del args[i:]
break
return parser.parse_args(args), argv

@ -0,0 +1,14 @@
import logging
import asyncio
from typing import (Any,)
logger = logging.getLogger(__name__)
def handle_task_result(fut: asyncio.Future[Any]) -> None:
try:
fut.result()
logger.debug(dict(fut=fut, msg='done'), stacklevel=2,)
except:
logger.exception('', stacklevel=2,)

@ -0,0 +1,478 @@
import dataclasses
import io
import glob
import os
import pathlib
import logging
import sys
import subprocess
import shutil
import abc
from .os import shutil_which
from typing import (
Optional,
Literal,
Any,
)
logger = logging.getLogger(__name__)
@dataclasses.dataclass
class Project:
source_dir : pathlib.Path
build_dir : pathlib.Path
dest_dir : pathlib.Path
meson_path: Optional[pathlib.Path] = None
@dataclasses.dataclass
class Dependency:
name: str
mode : Literal['pyproject', 'meson', 'meson-python', 'm']
source_path : pathlib.Path
args: Optional[list[str]] = None
@dataclasses.dataclass
class DistSettings:
wheel_dir : pathlib.Path
python_path: pathlib.Path
env_path: pathlib.Path
class CLI(abc.ABC):
@property
@abc.abstractmethod
def dist_settings(self) -> DistSettings:
raise NotImplementedError
@property
@abc.abstractmethod
def projects(self) -> dict[str, Project]:
raise NotImplementedError
@property
@abc.abstractmethod
def dependencies(self) -> dict[str, Dependency]:
raise NotImplementedError
def mypy(
self,
argv: list[str]
) -> None:
from . import mypy as _mypy
_mypy.run(
argv,
)
def ruff(
self,
project_name: str,
argv: list[str],
) -> None:
project = self.projects[project_name]
if len(argv) == 0:
argv = ['check', '.',]
subprocess.check_call([
self.dist_settings.python_path,
'-m',
'ruff',
'--config', str(project.source_dir / 'pyproject.toml'),
*argv,
])
def pyright(
self,
project_name: str,
argv: list[str],
) -> None:
project = self.projects[project_name]
if len(argv) == 0:
argv = ['--threads', '3']
cmd = [
str(self.dist_settings.python_path),
'-m',
'pyright',
'--pythonpath', str(self.dist_settings.python_path),
'-p', str(project.source_dir / 'pyproject.toml'),
*argv,
]
logger.info(cmd)
subprocess.check_call(cmd)
def pip_sync(
self,
project: str,
features: list[str],
) -> None:
from . import cli_bootstrap
pyproject = cli_bootstrap.pyproject_load(
self.projects[project].source_dir / 'pyproject.toml'
)
dependencies = sum([
pyproject.dependencies[o]
for o in features
], [])
pip_find_links : list[pathlib.Path] = []
if not pyproject.pip_find_links is None:
pip_find_links.extend(pyproject.pip_find_links)
logger.info(dict(
dependencies=dependencies,
))
if len(dependencies) > 0:
subprocess.check_call([
self.dist_settings.python_path,
'-m',
'uv', 'pip', 'install',
*sum([
['-f', str(o),]
for o in pip_find_links
], []),
# '-f', str(pathlib.Path(__file__).parent / 'deps' / 'dist'),
'--offline',
*dependencies,
])
def deploy_fetch_dist(
self,
force: bool,
) -> None:
for k, d in self.dependencies.items():
whl_glob = self.dist_settings.wheel_dir / ('*%s*.whl' % d.name.replace('.', '_'))
if len(glob.glob(
str(whl_glob)
)) == 0 or force:
if d.source_path.exists():
def whl_files_get() -> list[dict[str, Any]]:
return [
dict(
path=o,
stat=os.stat(o).st_mtime,
)
for o in glob.glob(
str(whl_glob)
)
]
present_files = whl_files_get()
if d.mode == 'm':
if (d.source_path / 'm.py').exists():
cmd = [
sys.executable,
str(d.source_path / 'm.py'),
'deploy:wheel',
'-o',
str(self.dist_settings.wheel_dir),
]
if not d.args is None:
cmd.extend(d.args)
subprocess.check_call(
cmd,
cwd=d.source_path,
)
else:
raise NotImplementedError
updated_files = whl_files_get()
def index_get(o: dict[str, Any]) -> tuple[Any, ...]:
return (o['path'], o['stat'])
present_files_index = {
index_get(o) : o
for o in present_files
}
new_files : list[dict[str, Any]] = []
for o in updated_files:
entry_index = index_get(o)
if not entry_index in present_files_index:
new_files.append(o)
if len(new_files) == 0:
raise NotImplementedError
latest_file = sorted(
new_files,
key=lambda x: x['stat']
)[-1]
subprocess.check_call([
self.dist_settings.python_path,
'-m', 'pip',
'install',
latest_file['path'],
])
@property
def pkg_config_path(self,) -> set[pathlib.Path]:
return {
pathlib.Path(o)
for o in glob.glob(
str(self.dist_settings.env_path / 'lib' / 'python*' / '**' / 'pkgconfig'),
recursive=True,
)
}
def deploy_wheel(
self,
project_name: str,
argv: Optional[list[str]] = None,
output_dir: Optional[pathlib.Path] = None,
force: Optional[bool] = None,
env: Optional[dict[str, str]] = None,
mypy: bool = False,
tests: bool = False,
) -> None:
project = self.projects[project_name]
# subprocess.check_call([
# sys.argv[0],
# # sys.executable,
# '-p', options.project,
# Command.meson_setup.value,
# ])
if argv is None:
argv = []
# assert argv is None or len(argv) == 0
if not project.meson_path is None:
if tests:
self.meson_test(
project_name=project_name,
)
self.meson_install(
project_name=project_name,
force=force,
)
if mypy:
self.mypy([])
if env is None:
env = dict()
extra_args: list[str] = []
if len(self.third_party_roots) > 0:
extra_args.extend([
'-Csetup-args=%s' % (
'-Dthird_party_roots=%s' % str(o.absolute())
)
for o in self.third_party_roots
])
cmd = [
sys.executable,
'-m',
'build',
'-w', '-n',
*extra_args,
'-Csetup-args=-Dmodes=pyproject',
'-Cbuild-dir=%s' % str(project.build_dir / 'pyproject'),
'-Csetup-args=-Dinstall_path=%s' % str(project.dest_dir),
# '-Cbuild-dir=%s' % str(project.build_dir),
str(project.source_dir),
*argv,
]
if not output_dir is None:
cmd.extend(['-o', str(output_dir)])
logger.info(dict(env=env))
subprocess.check_call(
cmd,
env=dict(list(os.environ.items())) | env,
)
if not project.meson_path is None:
if tests:
subprocess.check_call(
[
'ninja',
'-C',
str(project.build_dir / 'pyproject'),
'test',
]
)
def meson_install(
self,
project_name: str,
force: Optional[bool] = None,
argv: Optional[list[str]] = None,
) -> None:
project = self.projects[project_name]
if force is None:
force = False
if argv is None:
argv = []
if force and project.dest_dir.exists():
shutil.rmtree(project.dest_dir)
subprocess.check_call([
shutil_which('meson', True,),
'install',
'-C',
project.build_dir / 'meson',
'--destdir', project.dest_dir,
*argv,
])
for o in glob.glob(
str(project.dest_dir / 'lib' / 'pkgconfig' / '*.pc'),
recursive=True,
):
logger.info(dict(
path=o,
action='patch prefix',
))
with io.open(o, 'r') as f:
content = f.read()
with io.open(o, 'w') as f:
f.write(
content.replace('prefix=/', 'prefix=${pcfiledir}/../../')
)
def ninja(
self,
project_name: str,
argv: Optional[list[str]] = None,
env: Optional[dict[str, str]] = None,
) -> None:
project = self.projects[project_name]
if argv is None:
argv = []
if env is None:
env = dict()
logger.info(dict(env=env))
subprocess.check_call(
[
shutil_which('ninja', True),
'-C',
str(project.build_dir / 'meson'),
*argv,
],
env=dict(list(os.environ.items())) | env,
)
def meson_test(
self,
project_name: str,
argv: Optional[list[str]] = None,
) -> None:
project = self.projects[project_name]
if argv is None:
argv = []
subprocess.check_call([
shutil_which('meson', True,),
'test',
'-C',
project.build_dir / 'meson',
*argv,
])
def meson_compile(
self,
project_name: str,
argv: Optional[list[str]] = None,
) -> None:
project = self.projects[project_name]
if argv is None:
argv = []
subprocess.check_call([
shutil_which('meson', True,),
'compile',
'-C',
project.build_dir / 'meson',
*argv,
])
@property
def third_party_roots(self) -> list[pathlib.Path]:
return []
def meson_setup(
self,
project_name: str,
force: bool,
argv: Optional[list[str]] = None,
env: Optional[dict[str, str]] = None,
# third_party_roots: Optional[list[pathlib.Path]] = None,
) -> None:
project = self.projects[project_name]
if argv is None:
argv = []
if env is None:
env = dict()
logger.info(dict(env=env))
if force:
if (project.build_dir / 'meson').exists():
logger.info(dict(action='removing build dir', path=project.build_dir / 'meson'))
shutil.rmtree(project.build_dir / 'meson')
extra_args : list[str] = []
if len(self.third_party_roots) > 0:
extra_args.extend([
'-Dthird_party_roots=%s' % str(o.absolute())
for o in self.third_party_roots
])
cmd = [
shutil_which('meson', True,),
'setup',
str(project.source_dir),
str(project.build_dir / 'meson'),
'-Dmodes=["meson"]',
*extra_args,
# '-Dpkgconfig.relocatable=true',
'-Dprefix=/',
*argv,
]
logger.info(dict(cmd=cmd))
subprocess.check_call(
cmd,
env=dict(list(os.environ.items())) | env,
)

@ -0,0 +1,336 @@
#!/usr/bin/env python3
import glob
import io
import tempfile
import dataclasses
import pathlib
import sys
import subprocess
import os
import logging
from typing import (Optional, Any,)
from typing_extensions import (
Self, BinaryIO,
)
logger = logging.getLogger(__name__)
def toml_load(f: BinaryIO) -> Any:
try:
import tomllib
return tomllib.load(f)
except:
pass
try:
import tomli
return tomli.load(f)
except:
pass
raise NotImplementedError
@dataclasses.dataclass
class PyProject:
path: pathlib.Path
dependencies: dict[str, list[str]]
early_features: Optional[list[str]] = None
pip_find_links: Optional[list[pathlib.Path]] = None
runtime_libdirs: Optional[list[pathlib.Path]] = None
runtime_preload: Optional[list[pathlib.Path]] = None
requirements: dict[str, pathlib.Path] = dataclasses.field(default_factory=lambda : dict())
def pyproject_load(
d: pathlib.Path,
) -> PyProject:
with io.open(d, 'rb') as f:
content = toml_load(f)
assert isinstance(content, dict)
dependencies : dict[str, list[str]] = dict()
dependencies['default'] = content['project']['dependencies']
if (
'optional-dependencies' in content['project']
):
assert isinstance(
content['project']['optional-dependencies'],
dict
)
for k, v in content['project']['optional-dependencies'].items():
assert isinstance(v, list)
assert isinstance(k, str)
dependencies[k] = v
res = PyProject(
path=d,
dependencies=dependencies,
)
tool_name = 'online.fxreader.pr34'.replace('.', '-')
if (
'tool' in content and
isinstance(
content['tool'], dict
) and
tool_name in content['tool'] and
isinstance(
content['tool'][tool_name],
dict
)
):
if 'early_features' in content['tool'][tool_name]:
res.early_features = content['tool'][tool_name]['early_features']
if 'pip_find_links' in content['tool'][tool_name]:
res.pip_find_links = [
d.parent / pathlib.Path(o)
for o in content['tool'][tool_name]['pip_find_links']
]
if 'runtime_libdirs' in content['tool'][tool_name]:
res.runtime_libdirs = [
d.parent / pathlib.Path(o)
# pathlib.Path(o)
for o in content['tool'][tool_name]['runtime_libdirs']
]
if 'runtime_preload' in content['tool'][tool_name]:
res.runtime_preload = [
d.parent / pathlib.Path(o)
# pathlib.Path(o)
for o in content['tool'][tool_name]['runtime_preload']
]
if 'requirements' in content['tool'][tool_name]:
assert isinstance(content['tool'][tool_name]['requirements'], dict)
res.requirements = {
k : d.parent / pathlib.Path(v)
# pathlib.Path(o)
for k, v in content['tool'][tool_name]['requirements'].items()
}
return res
@dataclasses.dataclass
class BootstrapSettings:
env_path: pathlib.Path
python_path: pathlib.Path
base_dir: pathlib.Path
python_version: Optional[str] = dataclasses.field(
default_factory=lambda : os.environ.get(
'PYTHON_VERSION',
'%d.%d' % (
sys.version_info.major,
sys.version_info.minor,
),
).strip()
)
uv_args: list[str] = dataclasses.field(
default_factory=lambda : os.environ.get(
'UV_ARGS',
'--offline',
).split(),
)
@classmethod
def get(
cls,
base_dir: Optional[pathlib.Path] = None,
) -> Self:
if base_dir is None:
base_dir = pathlib.Path.cwd()
env_path = base_dir / '.venv'
python_path = env_path / 'bin' / 'python3'
return cls(
base_dir=base_dir,
env_path=env_path,
python_path=python_path,
)
def env_bootstrap(
bootstrap_settings: BootstrapSettings,
pyproject: PyProject,
) -> None:
pip_find_links : list[pathlib.Path] = []
if not pyproject.pip_find_links is None:
pip_find_links.extend(pyproject.pip_find_links)
pip_find_links_args = sum([
['-f', str(o),]
for o in pip_find_links
], [])
features : list[str] = []
if pyproject.early_features:
features.extend(pyproject.early_features)
requirements_python_version: Optional[str] = None
if not bootstrap_settings.python_version is None:
requirements_python_version = bootstrap_settings.python_version.replace('.', '_')
requirements_name = '_'.join(sorted(features))
if requirements_python_version:
requirements_name += '_' + requirements_python_version
requirements_path : Optional[pathlib.Path] = None
if requirements_name in pyproject.requirements:
requirements_path = pyproject.requirements[requirements_name]
else:
requirements_path = pyproject.path.parent / 'requirements.txt'
requirements_in : list[str] = []
requirements_in.extend([
'uv', 'pip', 'build', 'setuptools', 'meson-python', 'pybind11'
])
if pyproject.early_features:
early_dependencies = sum([
pyproject.dependencies[o]
for o in pyproject.early_features
], [])
logger.info(dict(
requirements_name=requirements_name,
early_dependencies=early_dependencies,
))
requirements_in.extend(early_dependencies)
# if len(early_dependencies) > 0:
# subprocess.check_call([
# bootstrap_settings.python_path,
# '-m',
# 'uv', 'pip', 'install',
# *pip_find_links_args,
# # '-f', str(pathlib.Path(__file__).parent / 'deps' / 'dist'),
# *bootstrap_settings.uv_args,
# *early_dependencies,
# ])
if not requirements_path.exists():
with tempfile.NamedTemporaryFile(
mode='w',
prefix='requirements',
suffix='.in',
) as f:
f.write(
'\n'.join(requirements_in)
)
f.flush()
subprocess.check_call([
'uv',
'pip',
'compile',
'--generate-hashes',
*pip_find_links_args,
# '-p',
# bootstrap_settings.python_path,
*bootstrap_settings.uv_args,
'-o', str(requirements_path),
f.name,
])
uv_python_version: list[str] = []
if not bootstrap_settings.python_version is None:
uv_python_version.extend([
'-p', bootstrap_settings.python_version,
])
subprocess.check_call([
'uv', 'venv',
*uv_python_version,
*pip_find_links_args,
# '--seed',
*bootstrap_settings.uv_args,
str(bootstrap_settings.env_path)
])
subprocess.check_call([
'uv',
'pip',
'install',
*pip_find_links_args,
'-p',
bootstrap_settings.python_path,
'--require-hashes',
*bootstrap_settings.uv_args,
'-r', str(requirements_path),
])
def paths_equal(
a: pathlib.Path | str,
b: pathlib.Path | str
) -> bool:
return (
os.path.abspath(str(a)) ==
os.path.abspath(str(b))
)
def run(
d: Optional[pathlib.Path] = None,
cli_path: Optional[pathlib.Path] = None,
) -> None:
if cli_path is None:
cli_path = pathlib.Path(__file__).parent / 'cli.py'
if d is None:
d = pathlib.Path(__file__).parent / 'pyproject.toml'
bootstrap_settings = BootstrapSettings.get()
pyproject : PyProject = pyproject_load(
d
)
logging.basicConfig(level=logging.INFO)
if not bootstrap_settings.env_path.exists():
env_bootstrap(
bootstrap_settings=bootstrap_settings,
pyproject=pyproject,
)
logger.info([sys.executable, sys.argv, bootstrap_settings.python_path])
if not paths_equal(sys.executable, bootstrap_settings.python_path):
os.execv(
str(bootstrap_settings.python_path),
[
str(bootstrap_settings.python_path),
*sys.argv,
]
)
os.execv(
str(bootstrap_settings.python_path),
[
str(bootstrap_settings.python_path),
str(
cli_path
),
*sys.argv[1:],
]
)
if __name__ == '__main__':
run()

@ -0,0 +1,90 @@
import base64
import os
import cryptography.hazmat.primitives.kdf.scrypt
from typing import (Literal, overload, Optional,)
class PasswordUtils:
@overload
@classmethod
def secret_hash(
cls,
secret: str | bytes,
mode: Literal['base64'],
salt: Optional[bytes] = None,
) -> tuple[str, str]: ...
@overload
@classmethod
def secret_hash(
cls,
secret: str | bytes,
mode: Literal['bytes'],
salt: Optional[bytes] = None,
) -> tuple[bytes, bytes]: ...
@classmethod
def secret_hash(
cls,
secret: str | bytes,
mode: Literal['bytes', 'base64'],
salt: Optional[bytes] = None,
) -> tuple[str, str] | tuple[bytes, bytes]:
if salt is None:
salt = os.urandom(16)
if isinstance(secret, str):
secret = secret.encode('utf-8')
# derive
kdf = cls._scrypt_init(salt=salt)
hashed_secret = kdf.derive(secret)
if mode == 'bytes':
return (salt, hashed_secret)
elif mode == 'base64':
res_tuple = tuple((
base64.b64encode(o).decode('utf-8')
for o in (salt, hashed_secret,)
))
return (res_tuple[0], res_tuple[1])
else:
raise NotImplementedError
@classmethod
def _scrypt_init(
cls,
salt: bytes
) -> cryptography.hazmat.primitives.kdf.scrypt.Scrypt:
return cryptography.hazmat.primitives.kdf.scrypt.Scrypt(
salt=salt,
length=32,
n=2**14,
r=8,
p=1,
)
@classmethod
def secret_check(
cls,
secret: str | bytes,
salt: str | bytes,
hashed_secret: str | bytes,
) -> bool:
if isinstance(salt, str):
salt = base64.b64decode(salt)
if isinstance(secret, str):
secret = secret.encode('utf-8')
if isinstance(hashed_secret, str):
hashed_secret = base64.b64decode(hashed_secret)
kdf = cls._scrypt_init(salt=salt)
try:
kdf.verify(secret, hashed_secret)
return True
except cryptography.exceptions.InvalidKey:
return False

@ -0,0 +1,35 @@
import os
import logging
from typing import (Optional,)
logger = logging.getLogger(__name__)
class DebugPy:
@classmethod
def set_trace(
cls,
host: Optional[str] = None,
port: Optional[int] = None,
wait: Optional[bool] = None,
) -> None:
if host is None:
host = '127.0.0.1'
if port is None:
port = 4444
if wait is None:
wait = True
import debugpy
if os.environ.get('DEBUGPY_RUNNING') != 'true':
logger.info('debugpy init')
import debugpy
debugpy.listen((host, port))
os.environ['DEBUGPY_RUNNING'] = 'true'
if wait:
debugpy.wait_for_client()
debugpy.breakpoint()
logger.info('debugpy done')

@ -0,0 +1,16 @@
import logging
from typing import (Optional,)
def setup(level: Optional[int] = None) -> None:
if level is None:
level = logging.INFO
logging.basicConfig(
level=level,
format=(
'%(levelname)s:%(name)s:%(message)s'
':%(process)d'
':%(asctime)s'
':%(pathname)s:%(funcName)s:%(lineno)s'
),
)

@ -0,0 +1,216 @@
import pydantic.dataclasses
import datetime
import pydantic_settings
import marisa_trie
import json
import pathlib
import subprocess
import logging
import sys
import argparse
from pydantic import (Field,)
from typing import (ClassVar, Generator, Annotated, Optional, Any,)
logger = logging.getLogger(__name__)
@pydantic.dataclasses.dataclass
class MypyFormatEntry:
name : str
value : str
def __eq__(self, other: object) -> bool:
if not isinstance(other, type(self)):
raise NotImplementedError
return self.value == other.value
class MypyFormat:
vscode : ClassVar[MypyFormatEntry] = MypyFormatEntry(name='vscode', value='vscode')
json : ClassVar[MypyFormatEntry] = MypyFormatEntry(name='json', value='json')
@classmethod
def from_value(cls, value: str) -> MypyFormatEntry:
for e in cls.entries():
if value == e.value:
return e
raise NotImplementedError
@classmethod
def entries(cls) -> Generator[MypyFormatEntry, None, None,]:
for o in dir(cls):
e = getattr(cls, o)
if not isinstance(e, MypyFormatEntry):
continue
yield e
class MypySettings(pydantic_settings.BaseSettings):
model_config = pydantic_settings.SettingsConfigDict(
env_prefix='online_fxreader_pr34_mypy_',
case_sensitive=False,
)
config_path : pathlib.Path = pathlib.Path.cwd() / '.mypy.ini'
max_errors : dict[str, int] = dict()
paths : Annotated[list[pathlib.Path], Field(default_factory=lambda : ['.'])]
def run(
argv: Optional[list[str]] = None,
settings: Optional[MypySettings] = None,
) -> None:
if argv is None:
argv = []
if settings is None:
settings = MypySettings()
parser = argparse.ArgumentParser()
parser.add_argument(
'-q', '--quiet',
dest='quiet',
action='store_true',
help='do not print anything if the program is correct according to max_errors limits',
default=False,
)
parser.add_argument(
'-i',
dest='paths',
help='specify paths to check',
default=[],
action='append',
)
parser.add_argument(
'-f', '--format',
dest='_format',
help='output format of errors',
default=MypyFormat.json.value,
choices=[
o.value
for o in MypyFormat.entries()
],
)
options, args = parser.parse_known_args(argv)
if len(args) > 0 and args[0] == '--':
del args[0]
options.format = MypyFormat.from_value(options._format)
if len(options.paths) == 0:
options.paths.extend(settings.paths)
started_at = datetime.datetime.now()
mypy_cmd = [
sys.executable,
'-m',
'mypy',
'--config-file', str(settings.config_path),
'--strict',
'-O',
'json',
*args,
*options.paths,
]
logger.info(dict(cmd=mypy_cmd))
res = subprocess.run(
mypy_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
done_at = datetime.datetime.now()
try:
assert not res.returncode is None
errors = sorted([
json.loads(o)
for o in res.stdout.decode('utf-8').splitlines()
if not o.strip() == ''
], key=lambda x: (
x.get('file', ''),
x.get('line', 0),
))
if not options.quiet:
if (len(res.stderr)) > 0:
logger.error(res.stderr.decode('utf-8'))
except:
logger.exception('')
logger.error(res.stdout.decode('utf-8'))
logger.error(res.stderr.decode('utf-8'))
sys.exit(res.returncode)
g : dict[str, Any] = dict()
for o in errors:
if not o['file'] in g:
g[o['file']] = []
g[o['file']].append(o)
h = {
k : len(v)
for k, v in sorted(
list(g.items()),
key=lambda x: x[0],
)
}
mentioned_paths = marisa_trie.Trie(list(h))
violated_limits : dict[str, str] = dict()
for k, v in settings.max_errors.items():
matching_paths = mentioned_paths.keys(k)
total_errors = sum([
h[o]
for o in matching_paths
], 0)
if total_errors > v:
violated_limits[k] = '%s - [%s]: has %d errors > %d' % (
k, ', '.join(matching_paths), total_errors, v,
)
if len(violated_limits) > 0 or not options.quiet:
if options.format == MypyFormat.vscode:
for o in errors:
sys.stdout.write('[%s] %s:%d,%d %s - %s - %s\n' % (
o['severity'],
o['file'],
o['line'],
o['column'],
o['message'],
o['hint'],
o['code'],
))
sys.stdout.flush()
#logger.info(json.dumps(errors, indent=4))
else:
logger.info(json.dumps(errors, indent=4))
#if len(violated_limits) > 0:
# logger.info(json.dumps(violated_limits, indent=4))
logger.info(json.dumps(dict(
max_errors=settings.max_errors,
violated_limits=violated_limits,
histogram=h,
elapsed=(done_at - started_at).total_seconds(),
), indent=4))
if len(violated_limits) > 0:
sys.exit(1)
if __name__ == '__main__':
from . import logging as _logging
_logging.setup()
run(sys.argv[1:])

@ -0,0 +1,122 @@
import shutil
import glob
import subprocess
import pydantic
import pathlib
import ctypes
import os
import sys
import logging
import dataclasses
logger = logging.getLogger(__name__)
from typing import (overload, Optional, Literal, Any, Annotated,)
from .cli_bootstrap import PyProject
@overload
def shutil_which(
name: str,
raise_on_failure: Literal[True],
) -> str: ...
@overload
def shutil_which(
name: str,
raise_on_failure: bool,
) -> Optional[str]: ...
def shutil_which(
name: str,
raise_on_failure: bool,
) -> Optional[str]:
res = shutil.which(name)
if res is None and raise_on_failure:
raise NotImplementedError
else:
return res
def runtime_libdirs_init(
project: PyProject,
) -> None:
if sys.platform == 'linux':
ld_library_path : list[pathlib.Path] = [
o
for o in [
*[
o.absolute()
for o in (
project.runtime_libdirs
if project.runtime_libdirs
else []
)
],
*[
pathlib.Path(o)
for o in os.environ.get(
'LD_LIBRARY_PATH',
''
).split(os.path.pathsep)
if o != ''
]
]
]
ld_library_path_present : list[pathlib.Path] = []
for o in ld_library_path:
if not o.exists():
logger.warning(dict(
ld_library_path=o,
msg='not found',
))
ld_library_path_present.append(o)
os.environ.update(
LD_LIBRARY_PATH=os.path.pathsep.join([
str(o) for o in ld_library_path_present
])
)
for preload_path in (project.runtime_preload or []):
for preload_found in glob.glob(str(
preload_path.parent / ('lib%s.so' % preload_path.name)
)):
logger.info(dict(
preload_path=preload_path, preload_found=preload_found,
# lib_path=o,
msg='load_library',
))
ctypes.cdll.LoadLibrary(preload_found)
else:
raise NotImplementedError
class interfaces_index_t:
@dataclasses.dataclass
class Interface:
@dataclasses.dataclass
class AddrInfo:
family: str
local: str
name: Annotated[
str,
pydantic.Field(
alias='ifname',
)
]
addr_info: list[AddrInfo]
def interfaces_index() -> list[interfaces_index_t.Interface]:
res = pydantic.RootModel[
list[interfaces_index_t.Interface]
].model_validate_json(
subprocess.check_output([
'ip', '-j', 'addr',
]).decode('utf-8')
).root
return res

@ -0,0 +1,524 @@
import contextlib
import pathlib
import sys
import enum
import dataclasses
import subprocess
import tempfile
import unittest.mock
import logging
import typing
if typing.TYPE_CHECKING:
import pip._internal.commands.show
import pip._internal.commands.download
import pip._internal.cli.main_parser
import pip._internal.models.index
import pip._internal.utils.temp_dir
import pip._internal.cli.main
import pip._internal.network.download
import pip._internal.resolution.base
import pip._internal.resolution.resolvelib.resolver
import pip._internal.operations.prepare
from typing import (
Literal, Optional, Iterable, Any,
)
logger = logging.getLogger(__name__)
def pip_show(
argv: list[str],
) -> list['pip._internal.commands.show._PackageInfo']:
import pip._internal.commands.show
return list(
pip._internal.commands.show.search_packages_info(
argv,
)
)
class pip_resolve_t:
class kwargs_t:
class mode_t(enum.StrEnum):
copy_paste = "copy_paste"
monkey_patch = "monkey_patch"
uv_pip_freeze = "uv_pip_freeze"
uv_pip_compile = "uv_pip_compile"
@dataclasses.dataclass
class res_t:
@dataclasses.dataclass
class download_info_t:
url: str
sha256: str
constraint: str
txt: Optional[str] = None
entries: Optional[list[download_info_t]] = None
def pip_resolve_entries_to_txt(
entries: list[pip_resolve_t.res_t.download_info_t]
) -> str:
return '\n'.join([
'#%s\n%s %s' % (
o.url,
o.constraint,
' '.join([
'--hash=sha256:%s' % o2
for o2 in o.sha256
])
)
for o in entries
])
def pip_resolve(
argv: list[str],
mode: pip_resolve_t.kwargs_t.mode_t,
requirements: Optional[list[str]] = None,
) -> pip_resolve_t.res_t:
if mode is pip_resolve_t.kwargs_t.mode_t.copy_paste:
import pip._internal.commands.show
import pip._internal.commands.download
import pip._internal.cli.cmdoptions
import pip._internal.cli.main_parser
import pip._internal.models.index
import pip._internal.utils.temp_dir
import pip._internal.cli.main
import pip._internal.network.download
import pip._internal.resolution.base
import pip._internal.req.req_install
import pip._internal.resolution.resolvelib.resolver
import pip._internal.operations.prepare
import pip._internal.utils.temp_dir
import pip._internal.operations.build.build_tracker
import pip._internal.models.direct_url
with contextlib.ExitStack() as stack:
stack.enter_context(pip._internal.utils.temp_dir.global_tempdir_manager())
t2 = pip._internal.cli.main_parser.create_main_parser()
t3 = t2.parse_args(["download"])
t1 = pip._internal.commands.download.DownloadCommand("blah", "shit")
stack.enter_context(t1.main_context())
# options = pip._internal.commands.download.Values()
options = t3[0]
options.python_version = None
options.platforms = []
options.abis = []
options.implementation = []
options.format_control = None
options.ignore_dependencies = None
options.index_url = pip._internal.models.index.PyPI.simple_url
options.extra_index_urls = []
options.no_index = None
options.find_links = []
options.pre = None
options.prefer_binary = True
options.only_binary = True
options.constraints = []
options.use_pep517 = None
options.editables = []
options.requirements = []
options.src_dir = str(pathlib.Path(__file__).parent)
options.build_isolation = None
options.check_build_deps = None
options.progress_bar = True
options.require_hashes = None
options.ignore_requires_python = False
# options.cache_dir
pip._internal.cli.cmdoptions.check_dist_restriction(options)
# t1._in_main_context = True
session = t1.get_default_session(options)
target_python = pip._internal.cli.cmdoptions.make_target_python(options)
finder = t1._build_package_finder(
options=options,
session=session,
target_python=target_python,
ignore_requires_python=options.ignore_requires_python,
)
build_tracker = t1.enter_context(
pip._internal.operations.build.build_tracker.get_build_tracker()
)
reqs = t1.get_requirements(
[
#'pip', 'uv', 'ipython',
*argv,
],
options,
finder,
session,
)
pip._internal.req.req_install.check_legacy_setup_py_options(options, reqs)
directory = pip._internal.utils.temp_dir.TempDirectory(
delete=True, kind="download", globally_managed=True
)
preparer = t1.make_requirement_preparer(
temp_build_dir=directory,
options=options,
build_tracker=build_tracker,
session=session,
finder=finder,
download_dir=None,
use_user_site=False,
verbosity=False,
)
resolver = t1.make_resolver(
preparer=preparer,
finder=finder,
options=options,
ignore_requires_python=options.ignore_requires_python,
use_pep517=options.use_pep517,
py_version_info=options.python_version,
)
t1.trace_basic_info(finder)
requirement_set = resolver.resolve(reqs, check_supported_wheels=True)
res = pip_resolve_t.res_t()
res.entries = []
for k, v in requirement_set.requirements.items():
assert not v.download_info is None
assert isinstance(
v.download_info.info,
pip._internal.models.direct_url.ArchiveInfo,
)
assert not v.download_info.info.hashes is None
res.entries.append(
pip_resolve_t.res_t.download_info_t(
constraint=k,
sha256=v.download_info.info.hashes["sha256"],
url=v.download_info.url,
)
)
res.txt = pip_resolve_entries_to_txt(
res.entries
)
return res
elif mode is pip_resolve_t.kwargs_t.mode_t.monkey_patch:
import pip._internal.commands.show
import pip._internal.commands.download
import pip._internal.cli.main_parser
import pip._internal.models.index
import pip._internal.models.link
from pip._internal.models.link import (
Link,
)
import pip._internal.utils.temp_dir
from pip._internal.metadata.base import (
BaseDistribution,
)
import pip._internal.cli.main
import pip._internal.network.download
import pip._internal.resolution.base
import pip._internal.resolution.resolvelib.resolver
import pip._internal.operations.prepare
from pip._internal.network.download import (
Downloader,
)
from pip._internal.operations.prepare import (
File,
)
from pip._internal.req.req_set import RequirementSet
from pip._internal.utils.hashes import Hashes
from pip._internal.req.req_install import InstallRequirement
downloader_call_def = pip._internal.network.download.Downloader.__call__
def downloader_call(
_self: pip._internal.network.download.Downloader,
link: pip._internal.models.link.Link,
location: str,
) -> tuple[str, str]:
logger.info(
dict(
url=link.url,
)
)
return downloader_call_def(
_self,
link, location,
)
batch_downloader_call_def = (
pip._internal.network.download.BatchDownloader.__call__
)
def batch_downloader_call(
_self: pip._internal.network.download.BatchDownloader,
links: Iterable[pip._internal.models.link.Link],
location: str,
) -> Iterable[
tuple[
pip._internal.models.link.Link,
tuple[str, str]
]
]:
# print(args)
logger.info(
dict(
links=links,
location=location,
)
)
return [
(o, ("/dev/null", ''))
for o in links
]
# base_resolver_resolve_def = pip._internal.resolution.base.BaseResolver.resolve
base_resolver_resolve_def = (
pip._internal.resolution.resolvelib.resolver.Resolver.resolve
)
result_requirements : list[
RequirementSet | InstallRequirement
] = []
def base_resolver_resolve(
_self: pip._internal.resolution.resolvelib.resolver.Resolver,
root_reqs: list[
InstallRequirement,
],
check_supported_wheels: bool,
) -> RequirementSet:
# print(args, kwargs)
res = base_resolver_resolve_def(
_self,
root_reqs,
check_supported_wheels
)
result_requirements.append(res)
raise NotImplementedError
return res
get_http_url_def = pip._internal.operations.prepare.get_http_url
def get_http_url(
link: Link,
download: Downloader,
download_dir: Optional[str] = None,
hashes: Optional[Hashes] = None,
) -> File:
logger.info(
dict(
url=link.url,
hashes=hashes,
)
)
if link.url.endswith(".whl"):
print("blah")
hashes = None
return File(
"/dev/null",
'',
)
else:
return get_http_url_def(
link,
download,
download_dir,
hashes
)
prepare_linked_requirements_more_def = pip._internal.operations.prepare.RequirementPreparer.prepare_linked_requirements_more
def prepare_linked_requirements_more(
_self: pip._internal.resolution.resolvelib.resolver.Resolver,
reqs: Iterable[InstallRequirement],
parallel_builds: bool = False,
) -> None:
result_requirements.extend(
reqs
)
raise NotImplementedError
_complete_partial_requirements_def = pip._internal.operations.prepare.RequirementPreparer._complete_partial_requirements
def _complete_partial_requirements(
_self: pip._internal.resolution.resolvelib.resolver.Resolver,
partially_downloaded_reqs: Iterable[InstallRequirement],
parallel_builds: bool = False,
) -> None:
result_requirements.extend(
partially_downloaded_reqs
)
raise NotImplementedError
patches : list[Any] = []
patches.append(
unittest.mock.patch.object(
pip._internal.network.download.Downloader, "__call__", downloader_call
)
)
# patches.append(
# unittest.mock.patch.object(
# pip._internal.network.download.BatchDownloader,
# '__call__',
# batch_downloader_call
# )
# )
# patches.append(
# unittest.mock.patch.object(
# pip._internal.resolution.base.BaseResolver, 'resolve', base_resolver_resolve))
patches.append(
unittest.mock.patch.object(
pip._internal.resolution.resolvelib.resolver.Resolver,
"resolve",
base_resolver_resolve,
)
)
patches.append(
unittest.mock.patch.object(
pip._internal.operations.prepare,
"get_http_url",
get_http_url,
)
)
patches.append(
unittest.mock.patch.object(
pip._internal.operations.prepare.RequirementPreparer,
"prepare_linked_requirements_more",
prepare_linked_requirements_more,
)
)
# patches.append(
# unittest.mock.patch.object(
# pip._internal.operations.prepare.RequirementPreparer,
# '_complete_partial_requirements',
# _complete_partial_requirements
# )
# )
with contextlib.ExitStack() as stack:
for p in patches:
stack.enter_context(p)
pip._internal.cli.main.main(
[
"download",
"-q",
"--no-cache",
"-d",
"/dev/null",
*argv,
# 'numpy',
]
)
# return sum([
# [
# pip_resolve_t.res_t.download_info_t(
# constraint=k,
# sha256=v.download_info.info.hashes['sha256'],
# url=v.download_info.url,
# )
# for k, v in o.requirements.items()
# ]
# for o in result_requirements
# ], [])
logger.warn(result_requirements)
res = pip_resolve_t.res_t()
res.entries = []
for o in result_requirements:
assert isinstance(o, InstallRequirement)
sha256_hashes = o.hashes()._allowed["sha256"]
assert len(sha256_hashes) == 1
assert not o.link is None
res.entries.append(
pip_resolve_t.res_t.download_info_t(
constraint=str(o.req),
sha256=sha256_hashes[0],
url=o.link.url,
)
)
res.txt = pip_resolve_entries_to_txt(
res.entries
)
return res
elif mode is pip_resolve_t.kwargs_t.mode_t.uv_pip_freeze:
assert len(argv) == 0
pip_freeze = subprocess.check_output(
[
sys.executable,
"-m",
"uv",
"pip",
"freeze",
],
).decode('utf-8')
pip_compile = subprocess.check_output(
[
sys.executable, '-m',
'uv', 'pip', 'compile',
'--generate-hashes',
'-',
],
input=pip_freeze.encode('utf-8')
).decode('utf-8')
return pip_resolve_t.res_t(
txt=pip_compile,
)
elif mode is pip_resolve_t.kwargs_t.mode_t.uv_pip_compile:
with contextlib.ExitStack() as stack:
if not requirements is None:
# assert len(argv) == 0
f = stack.enter_context(
tempfile.NamedTemporaryFile(
suffix='.txt',
)
)
f.write(
('\n'.join(requirements)).encode('utf-8')
)
f.flush()
argv.append(f.name)
if argv[0] == '--':
del argv[0]
pip_compile = subprocess.check_output(
[
sys.executable, '-m',
'uv', 'pip', 'compile',
'--generate-hashes',
*argv,
],
).decode('utf-8')
return pip_resolve_t.res_t(
txt=pip_compile,
)
else:
raise NotImplementedError

@ -0,0 +1,27 @@
# https://github.com/python/typing/issues/59#issuecomment-353878355
# https://gitea.fxreader.online/fxreader.online/freelance-project-34-marketing-blog/issues/2#issue-25
import typing
from typing import Any
from typing_extensions import Protocol
from abc import abstractmethod
C = typing.TypeVar("C", bound="Comparable")
class Comparable(Protocol):
@abstractmethod
def __eq__(self, other: Any) -> bool:
pass
@abstractmethod
def __lt__(self: C, other: C) -> bool:
pass
def __gt__(self: C, other: C) -> bool:
return (not self < other) and self != other
def __le__(self: C, other: C) -> bool:
return self < other or self == other
def __ge__(self: C, other: C) -> bool:
return (not self < other)

@ -0,0 +1,277 @@
import time
import glob
import io
import os
import numpy
import numpy.typing
import functools
import pathlib
import threading
import cython
import datetime
from typing import (Any, Optional, TypeVar, Type, cast)
# from scoping import scoping as s
def test(
_id: int,
T: float,
a: numpy.ndarray[Any, numpy.dtype[numpy.int32]],
) -> None:
with cython.nogil:
#if True:
started_at = datetime.datetime.now()
print('started')
def elapsed() -> float:
return (datetime.datetime.now() - started_at).total_seconds()
#a = 0
while elapsed() < T:
#a += 1
for k in range(1024 * 1024):
a[_id] += 1
print(['done', started_at, elapsed(), a[_id]])
M = TypeVar('M', bound=Type[Any])
def build(content: str, module: M) -> M:
import pathlib
import tempfile
import hashlib
import Cython.Build.Inline
sha256sum = hashlib.sha256(content.encode('utf-8')).digest().hex()
output_dir = (pathlib.Path('.') / 'tmp' / 'cython' / sha256sum).absolute()
if not output_dir.exists() or True:
os.makedirs(str(output_dir), exist_ok=True)
source_path = output_dir / ('_%s.pyx' % sha256sum)
if not source_path.exists():
with io.open(str(source_path), 'w') as f:
f.write(content)
t1 = Cython.Build.Inline._get_build_extension()
t1.extensions = Cython.Build.cythonize(str(source_path))
t1.build_temp = str(pathlib.Path('/'))
t1.build_lib = str(output_dir)
#t2 = Cython.Build.Inline.Extension(
# name=sha256sum,
#)
t1.run()
return cast(
M,
Cython.Build.Inline.load_dynamic(
'_%s' % sha256sum,
glob.glob(
str(output_dir / ('_%s*.so' % sha256sum))
)[0]
)
)
raise NotImplementedError
def mypyc_build(file_path: pathlib.Path) -> Any:
import pathlib
import tempfile
import hashlib
import mypyc.build
import Cython.Build.Inline
assert isinstance(file_path, pathlib.Path)
#sha256sum = hashlib.sha256(content.encode('utf-8')).digest().hex()
#output_dir = (pathlib.Path('.') / 'tmp' / 'cython' / sha256sum).absolute()
output_dir = pathlib.Path('.') / 'tmp' / 'mypyc'
sha256sum = file_path.stem
lib_pattern = file_path.parent / ('%s.cpython*.so' % sha256sum)
lib_dir = pathlib.Path('.')
def lib_path_glob(path: str | pathlib.Path) -> Optional[pathlib.Path]:
res : list[str] = glob.glob(str(path))
if len(res) == 0:
return None
else:
return pathlib.Path(res[0])
need_build : bool = False
lib_path : Optional[pathlib.Path] = None
lib_path = lib_path_glob(lib_pattern)
if not lib_path is None:
t2 = file_path.stat()
t3 = lib_path.stat()
if t3.st_mtime < t2.st_mtime:
need_build = True
del t2
del t3
else:
need_build = True
if need_build:
for o in [
output_dir,
output_dir / 'build' / file_path.parent,
]:
os.makedirs(
str(o),
exist_ok=True
)
#source_path = output_dir / ('_%s.py' % sha256sum)
source_path = file_path
#with io.open(str(source_path), 'w') as f:
# f.write(content)
t1 = Cython.Build.Inline._get_build_extension()
t1.extensions = mypyc.build.mypycify(
[str(source_path)],
target_dir=str(output_dir / 'build')
)
t1.build_temp = str(output_dir)
t1.build_lib = str(lib_dir)
#t2 = Cython.Build.Inline.Extension(
# name=sha256sum,
#)
t1.run()
lib_path = lib_path_glob(lib_pattern)
return Cython.Build.Inline.load_dynamic(
#'_%s' % sha256sum,
#t1.extensions[0].name,
file_path.stem,
str(lib_path),
)
raise NotImplementedError
class Source:
@staticmethod
def test2(
_a : numpy.ndarray[Any, numpy.dtype[numpy.int64]],
_id : numpy.dtype[numpy.int32] | int,
T : float=16
) -> int:
raise NotImplementedError
source = build(r'''
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def test4(int[:] a, int[:] b):
cdef int N = a.shape[0]
assert N == b.shape[0]
with cython.nogil:
for i in range(N):
a[i] += b[i]
return N
import datetime
def elapsed(started_at: datetime.datetime):
res = (datetime.datetime.now() - started_at).total_seconds()
return res
@cython.boundscheck(False) # Deactivate bounds checking
@cython.wraparound(False) # Deactivate negative indexing.
def has_time(started_at: datetime.datetime, T: float):
t1 = elapsed(started_at)
res = t1 < T
return res
@cython.boundscheck(False)
@cython.wraparound(False)
def test2(long long [:] _a, int _id, double T=16) -> int:
started_at = datetime.datetime.now()
print('started')
cdef int C = 1;
cdef int cond;
with cython.nogil:
#if True:
#a = 0
while True:
with cython.gil:
cond = has_time(started_at, T)
#cond = 0
if cond != 1:
break
#a += 1
for k in range(1024 * 1024 * 1024):
_a[_id] += C
print(['done', started_at, elapsed(started_at), _a[_id]])
return _a[_id]
''', Source)
def test_cython(N: int=4, T:int=16) -> None:
#a = [0] * N
a = numpy.zeros((N,), dtype=numpy.int64)
t = [
threading.Thread(
target=functools.partial(
source.test2,
a,
k,
T,
)
)
for k in range(N)
]
for o in t:
o.start()
for o in t:
o.join()
#cython_module['test2'](a, 0)
def test_mypyc(N: int=4, W:int=35) -> None:
cython2 = mypyc_build(
(pathlib.Path(__file__).parent / 'cython2.py').relative_to(
pathlib.Path.cwd()
)
)
# from .cython2 import fib
#a = [0] * N
t = [
threading.Thread(
target=functools.partial(
cython2.fib,
W,
)
)
for k in range(N)
]
for o in t:
o.start()
for o in t:
o.join()

@ -0,0 +1,11 @@
import time
def fib(n: int) -> int:
if n <= 1:
return n
else:
return fib(n - 2) + fib(n - 1)
t0 = time.time()
fib(32)
print(time.time() - t0)

@ -0,0 +1,36 @@
from online.fxreader.pr34.commands_typed import crypto
import unittest
class TestCrypto(unittest.TestCase):
def test_password_utils(self) -> None:
salt = b'asdfasdfasdf'
secret = 'blah'
hash_res = crypto.PasswordUtils.secret_hash(
secret,
mode='bytes',
salt=salt,
)
self.assertEqual(
hash_res,
(
salt,
b'\xdak\xd15\xfa\x8e\xc8\r\xc3\xd2c\xf1m\xb0\xbf\xe6\x98\x01$!j\xc8\xc0Hh\x84\xea,\x91\x8b\x08\xce',
),
)
check_res = crypto.PasswordUtils.secret_check(
secret,
*hash_res,
)
self.assertTrue(check_res)
self.assertFalse(
crypto.PasswordUtils.secret_check(
secret + 'asdfasdfsdf',
*hash_res,
)
)

Some files were not shown because too many files have changed in this diff Show More