chgksuite 0.27.0b5__tar.gz → 0.27.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- chgksuite-0.27.2/.claude/settings.local.json +10 -0
- chgksuite-0.27.2/.github/workflows/build.yml +283 -0
- chgksuite-0.27.2/.gitignore +10 -0
- chgksuite-0.27.2/.gitlab-ci.yml +17 -0
- chgksuite-0.27.2/.hgignore +2 -0
- {chgksuite-0.27.0b5/chgksuite.egg-info → chgksuite-0.27.2}/PKG-INFO +6 -8
- chgksuite-0.27.2/adhoc/regexes_fixer.py +66 -0
- chgksuite-0.27.2/author_counter.py +24 -0
- chgksuite-0.27.2/chgksuite/_html2md.py +94 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/cli.py +9 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/common.py +16 -5
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/composer/__init__.py +9 -9
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/composer/chgksuite_parser.py +3 -4
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/composer/db.py +1 -2
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/composer/latex.py +1 -2
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/composer/lj.py +1 -2
- chgksuite-0.27.0b5/chgksuite/composer/reddit.py → chgksuite-0.27.2/chgksuite/composer/markdown.py +35 -25
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/composer/openquiz.py +1 -2
- chgksuite-0.27.2/chgksuite/handouter/runner.py +473 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/handouter/tex_internals.py +12 -2
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/handouter/utils.py +8 -0
- chgksuite-0.27.2/chgksuite/lastdir +1 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/parser.py +34 -27
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/parser_db.py +1 -2
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/trello.py +8 -10
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/typotools.py +4 -4
- chgksuite-0.27.2/chgksuite/version.py +1 -0
- chgksuite-0.27.2/dev_readme.md +25 -0
- chgksuite-0.27.2/docs/.cache/.gitignore +1 -0
- chgksuite-0.27.2/docs/.cache/12897346880794287463 +43 -0
- chgksuite-0.27.2/docs/.cache/13071136909783630831 +27 -0
- chgksuite-0.27.2/docs/.cache/13307108790744403429 +58 -0
- chgksuite-0.27.2/docs/.cache/13333983167045209281 +27 -0
- chgksuite-0.27.2/docs/.cache/14085495286103177657 +4 -0
- chgksuite-0.27.2/docs/.cache/15213489598760314030 +149 -0
- chgksuite-0.27.2/docs/.cache/15319492834190874243 +4 -0
- chgksuite-0.27.2/docs/.cache/17387058097034297385 +4 -0
- chgksuite-0.27.2/docs/.cache/17722115158263369208 +4 -0
- chgksuite-0.27.2/docs/.cache/18247088324849079572 +4 -0
- chgksuite-0.27.2/docs/.cache/1840587404175770520 +43 -0
- chgksuite-0.27.2/docs/.cache/2517734129797249711 +4 -0
- chgksuite-0.27.2/docs/.cache/273431981325847810 +164 -0
- chgksuite-0.27.2/docs/.cache/2872065536916780406 +27 -0
- chgksuite-0.27.2/docs/.cache/3476900567878811119 +4 -0
- chgksuite-0.27.2/docs/.cache/4757258273854424423 +58 -0
- chgksuite-0.27.2/docs/.cache/5728722062471071239 +58 -0
- chgksuite-0.27.2/docs/.cache/6061198691539556612 +4 -0
- chgksuite-0.27.2/docs/.cache/6079179394456200124 +4 -0
- chgksuite-0.27.2/docs/.cache/735877668610100612 +73 -0
- chgksuite-0.27.2/docs/.cache/9345880734637750342 +4 -0
- chgksuite-0.27.2/docs/.cache/9490951945832949972 +4 -0
- chgksuite-0.27.2/docs/docs/4s.md +229 -0
- chgksuite-0.27.2/docs/docs/add_stats.md +9 -0
- chgksuite-0.27.2/docs/docs/base.md +43 -0
- chgksuite-0.27.2/docs/docs/i14n.md +31 -0
- chgksuite-0.27.2/docs/docs/images/base.png +0 -0
- chgksuite-0.27.2/docs/docs/images/douplet_problem.png +0 -0
- chgksuite-0.27.2/docs/docs/images/i14n.png +0 -0
- chgksuite-0.27.2/docs/docs/images/i14n_parse.png +0 -0
- chgksuite-0.27.2/docs/docs/images/lj.png +0 -0
- chgksuite-0.27.2/docs/docs/images/main.png +0 -0
- chgksuite-0.27.2/docs/docs/images/openquiz.png +0 -0
- chgksuite-0.27.2/docs/docs/images/openquiz2.png +0 -0
- chgksuite-0.27.2/docs/docs/images/parse.png +0 -0
- chgksuite-0.27.2/docs/docs/images/pptx.png +0 -0
- chgksuite-0.27.2/docs/docs/images/pptx_additional_conf.png +0 -0
- chgksuite-0.27.2/docs/docs/images/pptx_slide_a.png +0 -0
- chgksuite-0.27.2/docs/docs/images/pptx_slide_q.png +0 -0
- chgksuite-0.27.2/docs/docs/images/roenko.png +0 -0
- chgksuite-0.27.2/docs/docs/images/rozhdsushkov.png +0 -0
- chgksuite-0.27.2/docs/docs/images/stats.png +0 -0
- chgksuite-0.27.2/docs/docs/images/telegram.png +0 -0
- chgksuite-0.27.2/docs/docs/images/trello_download.png +0 -0
- chgksuite-0.27.2/docs/docs/images/trello_token.png +0 -0
- chgksuite-0.27.2/docs/docs/images/trello_upload.png +0 -0
- chgksuite-0.27.2/docs/docs/images/word.png +0 -0
- chgksuite-0.27.2/docs/docs/index.md +59 -0
- chgksuite-0.27.2/docs/docs/lj.md +9 -0
- chgksuite-0.27.2/docs/docs/openquiz.md +7 -0
- chgksuite-0.27.2/docs/docs/pptx.md +66 -0
- chgksuite-0.27.2/docs/docs/stylesheets/extra.css +29 -0
- chgksuite-0.27.2/docs/docs/telegram.md +46 -0
- chgksuite-0.27.2/docs/docs/trello.md +31 -0
- chgksuite-0.27.2/docs/docs/word.md +24 -0
- chgksuite-0.27.2/docs/mkdocs.yml +35 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/history.md +5 -1
- chgksuite-0.27.2/hook-dateparser.py +12 -0
- chgksuite-0.27.2/packer.py +172 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/pyproject.toml +8 -16
- chgksuite-0.27.2/pytest.ini +5 -0
- chgksuite-0.27.2/pytest.sh +7 -0
- chgksuite-0.27.2/re_helper.py +24 -0
- chgksuite-0.27.2/requirements_dev.txt +2 -0
- chgksuite-0.27.2/ruff.toml +2 -0
- chgksuite-0.27.2/tests/2019-07-23_beln19_u.docx +0 -0
- chgksuite-0.27.2/tests/2019-07-23_beln19_u.docx.canon +690 -0
- chgksuite-0.27.2/tests/Kubok_knyagini_Olgi-2015.docx +0 -0
- chgksuite-0.27.2/tests/Kubok_knyagini_Olgi-2015.docx.canon +644 -0
- chgksuite-0.27.2/tests/Shkolny_Chemp_Estonii-2014_(48v).docx +0 -0
- chgksuite-0.27.2/tests/Shkolny_Chemp_Estonii-2014_(48v).docx.canon +361 -0
- chgksuite-0.27.2/tests/__init__.py +0 -0
- chgksuite-0.27.2/tests/balt09-1.txt +783 -0
- chgksuite-0.27.2/tests/balt09-1.txt.canon +286 -0
- chgksuite-0.27.2/tests/borromeo.txt +11 -0
- chgksuite-0.27.2/tests/borromeo.txt.canon +16 -0
- chgksuite-0.27.2/tests/canonize.py +69 -0
- chgksuite-0.27.2/tests/chgksuite_test.py +364 -0
- chgksuite-0.27.2/tests/conftest.py +21 -0
- chgksuite-0.27.2/tests/encrypt_test_files.py +147 -0
- chgksuite-0.27.2/tests/haifa2025.docx.encrypted +0 -0
- chgksuite-0.27.2/tests/haifa2025.docx.encrypted.canon +0 -0
- chgksuite-0.27.2/tests/handouter_layout_test.py +310 -0
- chgksuite-0.27.2/tests/link_unwrap.docx +0 -0
- chgksuite-0.27.2/tests/link_unwrap.docx.canon +10 -0
- chgksuite-0.27.2/tests/ljcredentials +1 -0
- chgksuite-0.27.2/tests/long_handout.png +0 -0
- chgksuite-0.27.2/tests/malkin_papkov_synchr.docx +0 -0
- chgksuite-0.27.2/tests/malkin_papkov_synchr.docx.canon +99 -0
- chgksuite-0.27.2/tests/octo2021_khmelkov.docx +0 -0
- chgksuite-0.27.2/tests/octo2021_khmelkov.docx.canon +102 -0
- chgksuite-0.27.2/tests/ovsch_boronenko_3.docx +0 -0
- chgksuite-0.27.2/tests/ovsch_boronenko_3.docx.canon +334 -0
- chgksuite-0.27.2/tests/pass1.docx +0 -0
- chgksuite-0.27.2/tests/pass1.docx.canon +183 -0
- chgksuite-0.27.2/tests/settings.json +3 -0
- chgksuite-0.27.2/tests/single_number_line_test.docx +0 -0
- chgksuite-0.27.2/tests/single_number_line_test.docx.canon +46 -0
- chgksuite-0.27.2/tests/smalltest.4s +6 -0
- chgksuite-0.27.2/tests/test.jpg +0 -0
- chgksuite-0.27.2/tests/test_blitz.txt +8 -0
- chgksuite-0.27.2/tests/test_blitz.txt.canon +9 -0
- chgksuite-0.27.2/tests/tourrev_with_razmin.docx +0 -0
- chgksuite-0.27.2/tests/tourrev_with_razmin.docx.canon +34 -0
- chgksuite-0.27.2/tests//320/241/320/247/320/240_/320/250/320/265/321/200/320/265/320/264/320/265/320/263/320/260_/320/225/321/200/320/274/320/270/321/210/320/272/320/270/320/275.docx +0 -0
- chgksuite-0.27.2/tests//320/241/320/247/320/240_/320/250/320/265/321/200/320/265/320/264/320/265/320/263/320/260_/320/225/321/200/320/274/320/270/321/210/320/272/320/270/320/275.docx.canon +13 -0
- chgksuite-0.27.2/uv.lock +1454 -0
- chgksuite-0.27.0b5/PKG-INFO +0 -40
- chgksuite-0.27.0b5/chgksuite/handouter/runner.py +0 -243
- chgksuite-0.27.0b5/chgksuite/version.py +0 -1
- chgksuite-0.27.0b5/chgksuite.egg-info/SOURCES.txt +0 -67
- chgksuite-0.27.0b5/chgksuite.egg-info/dependency_links.txt +0 -1
- chgksuite-0.27.0b5/chgksuite.egg-info/entry_points.txt +0 -2
- chgksuite-0.27.0b5/chgksuite.egg-info/requires.txt +0 -19
- chgksuite-0.27.0b5/chgksuite.egg-info/top_level.txt +0 -1
- chgksuite-0.27.0b5/setup.cfg +0 -4
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/LICENSE +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/MANIFEST.in +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/README.md +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/__init__.py +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/__main__.py +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/composer/composer_common.py +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/composer/docx.py +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/composer/pptx.py +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/composer/stats.py +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/composer/telegram.py +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/composer/telegram_bot.py +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/handouter/__init__.py +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/handouter/gen.py +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/handouter/installer.py +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/handouter/pack.py +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/cheader.tex +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/fix-unnumbered-sections.sty +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/labels_az.toml +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/labels_by.toml +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/labels_by_tar.toml +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/labels_en.toml +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/labels_kz_cyr.toml +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/labels_ru.toml +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/labels_sr.toml +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/labels_ua.toml +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/labels_uz.toml +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/labels_uz_cyr.toml +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/pptx_config.toml +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/regexes_az.json +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/regexes_by.json +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/regexes_by_tar.json +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/regexes_en.json +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/regexes_kz_cyr.json +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/regexes_ru.json +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/regexes_sr.json +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/regexes_ua.json +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/regexes_uz.json +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/regexes_uz_cyr.json +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/template.docx +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/template.pptx +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/resources/trello.json +0 -0
- {chgksuite-0.27.0b5 → chgksuite-0.27.2}/chgksuite/vulture_whitelist.py +0 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
name: Build Standalone Executables
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
tag:
|
|
10
|
+
description: 'Tag to build and release (e.g., v0.26.1). Leave empty for build-only.'
|
|
11
|
+
required: false
|
|
12
|
+
default: ''
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
build:
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
include:
|
|
20
|
+
- os: ubuntu-24.04
|
|
21
|
+
platform: linux-x64
|
|
22
|
+
rust_target: x86_64-unknown-linux-gnu
|
|
23
|
+
- os: ubuntu-24.04-arm
|
|
24
|
+
platform: linux-arm64
|
|
25
|
+
rust_target: aarch64-unknown-linux-gnu
|
|
26
|
+
- os: macos-15-intel
|
|
27
|
+
platform: macos-x64
|
|
28
|
+
rust_target: x86_64-apple-darwin
|
|
29
|
+
- os: macos-latest
|
|
30
|
+
platform: macos-arm64
|
|
31
|
+
rust_target: aarch64-apple-darwin
|
|
32
|
+
- os: windows-latest
|
|
33
|
+
platform: windows-x64
|
|
34
|
+
rust_target: x86_64-pc-windows-msvc
|
|
35
|
+
|
|
36
|
+
runs-on: ${{ matrix.os }}
|
|
37
|
+
|
|
38
|
+
steps:
|
|
39
|
+
- name: Checkout chgksuite
|
|
40
|
+
uses: actions/checkout@v4
|
|
41
|
+
|
|
42
|
+
- name: Checkout pyapp
|
|
43
|
+
uses: actions/checkout@v4
|
|
44
|
+
with:
|
|
45
|
+
repository: ofek/pyapp
|
|
46
|
+
path: pyapp
|
|
47
|
+
ref: v0.29.0
|
|
48
|
+
|
|
49
|
+
- name: Install Rust
|
|
50
|
+
uses: dtolnay/rust-toolchain@stable
|
|
51
|
+
with:
|
|
52
|
+
targets: ${{ matrix.rust_target }}
|
|
53
|
+
|
|
54
|
+
- name: Create build directory
|
|
55
|
+
shell: bash
|
|
56
|
+
run: mkdir -p artifacts
|
|
57
|
+
|
|
58
|
+
# Determine versions and create requirements files
|
|
59
|
+
- name: Setup build configuration
|
|
60
|
+
id: config
|
|
61
|
+
shell: bash
|
|
62
|
+
run: |
|
|
63
|
+
TAG="${{ inputs.tag || github.ref_name }}"
|
|
64
|
+
|
|
65
|
+
# Check if this is a release build (tag) or dev build (branch)
|
|
66
|
+
IS_RELEASE="false"
|
|
67
|
+
if [[ "${{ github.ref }}" == refs/tags/* ]] || [[ -n "${{ inputs.tag }}" ]]; then
|
|
68
|
+
IS_RELEASE="true"
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
# Extract version from tag (remove 'v' prefix if present)
|
|
72
|
+
if [[ "$TAG" =~ ^v ]]; then
|
|
73
|
+
VERSION="${TAG:1}"
|
|
74
|
+
else
|
|
75
|
+
VERSION="$TAG"
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Fallback to reading from version.py if no tag
|
|
79
|
+
if [ -z "$VERSION" ] || [[ ! "$VERSION" =~ ^[0-9] ]]; then
|
|
80
|
+
VERSION=$(grep -oP '__version__\s*=\s*"\K[^"]+' chgksuite/version.py 2>/dev/null || \
|
|
81
|
+
grep -o '__version__\s*=\s*"[^"]*"' chgksuite/version.py | cut -d'"' -f2 || \
|
|
82
|
+
echo "0.0.0")
|
|
83
|
+
fi
|
|
84
|
+
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
85
|
+
echo "is_release=$IS_RELEASE" >> $GITHUB_OUTPUT
|
|
86
|
+
|
|
87
|
+
# For non-release builds, always use --pre to get latest beta versions
|
|
88
|
+
if [ "$IS_RELEASE" = "false" ]; then
|
|
89
|
+
PIP_PRE="--pre"
|
|
90
|
+
elif [[ "$VERSION" =~ (a|b|rc)[0-9]+ ]]; then
|
|
91
|
+
PIP_PRE="--pre"
|
|
92
|
+
else
|
|
93
|
+
PIP_PRE=""
|
|
94
|
+
fi
|
|
95
|
+
echo "pip_pre=$PIP_PRE" >> $GITHUB_OUTPUT
|
|
96
|
+
|
|
97
|
+
echo "Build configuration:"
|
|
98
|
+
echo " Version: $VERSION"
|
|
99
|
+
echo " Is release: $IS_RELEASE"
|
|
100
|
+
echo " Pip pre flag: $PIP_PRE"
|
|
101
|
+
|
|
102
|
+
# Create requirements files in pyapp directory to avoid Windows path issues
|
|
103
|
+
- name: Create requirements files
|
|
104
|
+
shell: bash
|
|
105
|
+
run: |
|
|
106
|
+
# Qt requirements
|
|
107
|
+
echo "chgksuite" > pyapp/requirements-qt.txt
|
|
108
|
+
echo "chgksuite-qt" >> pyapp/requirements-qt.txt
|
|
109
|
+
|
|
110
|
+
# Tk requirements
|
|
111
|
+
echo "chgksuite" > pyapp/requirements-tk.txt
|
|
112
|
+
echo "chgksuite-tk" >> pyapp/requirements-tk.txt
|
|
113
|
+
|
|
114
|
+
echo "=== Qt requirements ==="
|
|
115
|
+
cat pyapp/requirements-qt.txt
|
|
116
|
+
echo "=== Tk requirements ==="
|
|
117
|
+
cat pyapp/requirements-tk.txt
|
|
118
|
+
|
|
119
|
+
# Build Qt GUI (skip on linux-arm64 - no PyQt6 wheel)
|
|
120
|
+
- name: Build Qt GUI
|
|
121
|
+
if: matrix.platform != 'linux-arm64'
|
|
122
|
+
shell: bash
|
|
123
|
+
working-directory: pyapp
|
|
124
|
+
run: |
|
|
125
|
+
export PYAPP_PROJECT_NAME="chgksuite-qt"
|
|
126
|
+
export PYAPP_PROJECT_VERSION="${{ steps.config.outputs.version }}"
|
|
127
|
+
export PYAPP_PROJECT_DEPENDENCY_FILE="$(pwd)/requirements-qt.txt"
|
|
128
|
+
export PYAPP_EXEC_SPEC="chgksuite_qt.__main__:main"
|
|
129
|
+
export PYAPP_PYTHON_VERSION="3.12"
|
|
130
|
+
export PYAPP_IS_GUI="1"
|
|
131
|
+
export PYAPP_UV_ENABLED="1"
|
|
132
|
+
export PYAPP_PIP_EXTRA_ARGS="${{ steps.config.outputs.pip_pre }}"
|
|
133
|
+
export PYAPP_PASS_LOCATION="1"
|
|
134
|
+
|
|
135
|
+
echo "Building Qt GUI with:"
|
|
136
|
+
echo " PYAPP_PROJECT_DEPENDENCY_FILE=$PYAPP_PROJECT_DEPENDENCY_FILE"
|
|
137
|
+
echo " PYAPP_PIP_EXTRA_ARGS=$PYAPP_PIP_EXTRA_ARGS"
|
|
138
|
+
|
|
139
|
+
cargo build --release --target ${{ matrix.rust_target }}
|
|
140
|
+
|
|
141
|
+
# Copy binary with platform-specific naming
|
|
142
|
+
if [ "${{ runner.os }}" = "Windows" ]; then
|
|
143
|
+
cp target/${{ matrix.rust_target }}/release/pyapp.exe ../artifacts/chgkq-${{ matrix.platform }}.exe
|
|
144
|
+
else
|
|
145
|
+
cp target/${{ matrix.rust_target }}/release/pyapp ../artifacts/chgkq-${{ matrix.platform }}
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
# Build Tk GUI
|
|
149
|
+
- name: Build Tk GUI
|
|
150
|
+
shell: bash
|
|
151
|
+
working-directory: pyapp
|
|
152
|
+
run: |
|
|
153
|
+
export PYAPP_PROJECT_NAME="chgksuite-tk"
|
|
154
|
+
export PYAPP_PROJECT_VERSION="${{ steps.config.outputs.version }}"
|
|
155
|
+
export PYAPP_PROJECT_DEPENDENCY_FILE="$(pwd)/requirements-tk.txt"
|
|
156
|
+
export PYAPP_EXEC_SPEC="chgksuite_tk.__main__:main"
|
|
157
|
+
export PYAPP_PYTHON_VERSION="3.12"
|
|
158
|
+
export PYAPP_IS_GUI="1"
|
|
159
|
+
export PYAPP_UV_ENABLED="1"
|
|
160
|
+
export PYAPP_PIP_EXTRA_ARGS="${{ steps.config.outputs.pip_pre }}"
|
|
161
|
+
export PYAPP_PASS_LOCATION="1"
|
|
162
|
+
|
|
163
|
+
echo "Building Tk GUI with:"
|
|
164
|
+
echo " PYAPP_PROJECT_DEPENDENCY_FILE=$PYAPP_PROJECT_DEPENDENCY_FILE"
|
|
165
|
+
echo " PYAPP_PIP_EXTRA_ARGS=$PYAPP_PIP_EXTRA_ARGS"
|
|
166
|
+
|
|
167
|
+
cargo build --release --target ${{ matrix.rust_target }}
|
|
168
|
+
|
|
169
|
+
# Copy binary with platform-specific naming
|
|
170
|
+
if [ "${{ runner.os }}" = "Windows" ]; then
|
|
171
|
+
cp target/${{ matrix.rust_target }}/release/pyapp.exe ../artifacts/chgkt-${{ matrix.platform }}.exe
|
|
172
|
+
else
|
|
173
|
+
cp target/${{ matrix.rust_target }}/release/pyapp ../artifacts/chgkt-${{ matrix.platform }}
|
|
174
|
+
fi
|
|
175
|
+
|
|
176
|
+
# Create macOS .app bundles (required for Finder launch)
|
|
177
|
+
- name: Create macOS app bundles
|
|
178
|
+
if: runner.os == 'macOS'
|
|
179
|
+
shell: bash
|
|
180
|
+
run: |
|
|
181
|
+
# Create Qt .app bundle
|
|
182
|
+
if [ -f "artifacts/chgkq-${{ matrix.platform }}" ]; then
|
|
183
|
+
mkdir -p "artifacts/chgkq.app/Contents/MacOS"
|
|
184
|
+
mv "artifacts/chgkq-${{ matrix.platform }}" "artifacts/chgkq.app/Contents/MacOS/chgkq"
|
|
185
|
+
cat > "artifacts/chgkq.app/Contents/Info.plist" << 'EOF'
|
|
186
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
187
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
188
|
+
<plist version="1.0">
|
|
189
|
+
<dict>
|
|
190
|
+
<key>CFBundleExecutable</key>
|
|
191
|
+
<string>chgkq</string>
|
|
192
|
+
<key>CFBundleIdentifier</key>
|
|
193
|
+
<string>me.pecheny.chgkq</string>
|
|
194
|
+
<key>CFBundleName</key>
|
|
195
|
+
<string>chgksuite-qt</string>
|
|
196
|
+
<key>CFBundlePackageType</key>
|
|
197
|
+
<string>APPL</string>
|
|
198
|
+
<key>CFBundleVersion</key>
|
|
199
|
+
<string>${{ steps.config.outputs.version }}</string>
|
|
200
|
+
<key>CFBundleShortVersionString</key>
|
|
201
|
+
<string>${{ steps.config.outputs.version }}</string>
|
|
202
|
+
<key>LSMinimumSystemVersion</key>
|
|
203
|
+
<string>10.15</string>
|
|
204
|
+
<key>NSHighResolutionCapable</key>
|
|
205
|
+
<true/>
|
|
206
|
+
</dict>
|
|
207
|
+
</plist>
|
|
208
|
+
EOF
|
|
209
|
+
# Ad-hoc sign the app bundle to prevent "damaged" error
|
|
210
|
+
codesign --force --deep --sign - "artifacts/chgkq.app"
|
|
211
|
+
# Zip the .app bundle
|
|
212
|
+
cd artifacts && zip -r "chgkq-${{ matrix.platform }}.zip" chgkq.app && rm -rf chgkq.app && cd ..
|
|
213
|
+
fi
|
|
214
|
+
|
|
215
|
+
# Create Tk .app bundle
|
|
216
|
+
if [ -f "artifacts/chgkt-${{ matrix.platform }}" ]; then
|
|
217
|
+
mkdir -p "artifacts/chgkt.app/Contents/MacOS"
|
|
218
|
+
mv "artifacts/chgkt-${{ matrix.platform }}" "artifacts/chgkt.app/Contents/MacOS/chgkt"
|
|
219
|
+
cat > "artifacts/chgkt.app/Contents/Info.plist" << 'EOF'
|
|
220
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
221
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
222
|
+
<plist version="1.0">
|
|
223
|
+
<dict>
|
|
224
|
+
<key>CFBundleExecutable</key>
|
|
225
|
+
<string>chgkt</string>
|
|
226
|
+
<key>CFBundleIdentifier</key>
|
|
227
|
+
<string>me.pecheny.chgkt</string>
|
|
228
|
+
<key>CFBundleName</key>
|
|
229
|
+
<string>chgksuite-tk</string>
|
|
230
|
+
<key>CFBundlePackageType</key>
|
|
231
|
+
<string>APPL</string>
|
|
232
|
+
<key>CFBundleVersion</key>
|
|
233
|
+
<string>${{ steps.config.outputs.version }}</string>
|
|
234
|
+
<key>CFBundleShortVersionString</key>
|
|
235
|
+
<string>${{ steps.config.outputs.version }}</string>
|
|
236
|
+
<key>LSMinimumSystemVersion</key>
|
|
237
|
+
<string>10.15</string>
|
|
238
|
+
<key>NSHighResolutionCapable</key>
|
|
239
|
+
<true/>
|
|
240
|
+
</dict>
|
|
241
|
+
</plist>
|
|
242
|
+
EOF
|
|
243
|
+
# Ad-hoc sign the app bundle to prevent "damaged" error
|
|
244
|
+
codesign --force --deep --sign - "artifacts/chgkt.app"
|
|
245
|
+
# Zip the .app bundle
|
|
246
|
+
cd artifacts && zip -r "chgkt-${{ matrix.platform }}.zip" chgkt.app && rm -rf chgkt.app && cd ..
|
|
247
|
+
fi
|
|
248
|
+
|
|
249
|
+
- name: List artifacts
|
|
250
|
+
shell: bash
|
|
251
|
+
run: ls -lh artifacts/
|
|
252
|
+
|
|
253
|
+
- name: Upload artifacts
|
|
254
|
+
uses: actions/upload-artifact@v4
|
|
255
|
+
with:
|
|
256
|
+
name: builds-${{ matrix.platform }}
|
|
257
|
+
path: artifacts/*
|
|
258
|
+
|
|
259
|
+
release:
|
|
260
|
+
needs: build
|
|
261
|
+
runs-on: ubuntu-latest
|
|
262
|
+
if: startsWith(github.ref, 'refs/tags/') || inputs.tag != ''
|
|
263
|
+
permissions:
|
|
264
|
+
contents: write
|
|
265
|
+
|
|
266
|
+
steps:
|
|
267
|
+
- name: Download all artifacts
|
|
268
|
+
uses: actions/download-artifact@v4
|
|
269
|
+
with:
|
|
270
|
+
path: artifacts
|
|
271
|
+
merge-multiple: true
|
|
272
|
+
|
|
273
|
+
- name: List artifacts
|
|
274
|
+
run: ls -la artifacts/
|
|
275
|
+
|
|
276
|
+
- name: Create Release
|
|
277
|
+
uses: softprops/action-gh-release@v1
|
|
278
|
+
with:
|
|
279
|
+
tag_name: ${{ inputs.tag || github.ref_name }}
|
|
280
|
+
files: artifacts/*
|
|
281
|
+
generate_release_notes: true
|
|
282
|
+
env:
|
|
283
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
image: python:3.14-trixie
|
|
2
|
+
|
|
3
|
+
before_script:
|
|
4
|
+
- pip install zensical
|
|
5
|
+
|
|
6
|
+
pages:
|
|
7
|
+
stage: deploy
|
|
8
|
+
script:
|
|
9
|
+
- cd docs
|
|
10
|
+
- zensical build
|
|
11
|
+
- mv public ../public
|
|
12
|
+
- cd ..
|
|
13
|
+
artifacts:
|
|
14
|
+
paths:
|
|
15
|
+
- public
|
|
16
|
+
rules:
|
|
17
|
+
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
|
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chgksuite
|
|
3
|
-
Version: 0.27.
|
|
3
|
+
Version: 0.27.2
|
|
4
4
|
Summary: A package for chgk automation
|
|
5
|
+
Project-URL: Homepage, https://gitlab.com/peczony/chgksuite
|
|
5
6
|
Author-email: Alexander Pecheny <ap@pecheny.me>
|
|
6
7
|
License-Expression: MIT
|
|
7
|
-
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
License-File: LICENSE
|
|
9
9
|
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
11
|
Requires-Python: >=3.9
|
|
11
|
-
Description-Content-Type: text/markdown
|
|
12
|
-
License-File: LICENSE
|
|
13
12
|
Requires-Dist: beautifulsoup4
|
|
14
13
|
Requires-Dist: chardet
|
|
15
|
-
Requires-Dist: dashtable
|
|
16
14
|
Requires-Dist: dateparser
|
|
17
15
|
Requires-Dist: mammoth
|
|
18
16
|
Requires-Dist: openpyxl
|
|
19
17
|
Requires-Dist: parse
|
|
20
|
-
Requires-Dist:
|
|
18
|
+
Requires-Dist: pillow
|
|
21
19
|
Requires-Dist: ply
|
|
22
20
|
Requires-Dist: pypandoc
|
|
23
21
|
Requires-Dist: pypdf
|
|
@@ -29,7 +27,7 @@ Requires-Dist: requests
|
|
|
29
27
|
Requires-Dist: toml
|
|
30
28
|
Requires-Dist: urllib3>=2.6.2
|
|
31
29
|
Requires-Dist: watchdog
|
|
32
|
-
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
33
31
|
|
|
34
32
|
**chgksuite** is an utility that helps chgk editors.
|
|
35
33
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import json
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def process_json_files(directory):
|
|
7
|
+
# Pattern to match filenames starting with "regexes_" and ending with ".json"
|
|
8
|
+
pattern = re.compile(r"^regexes_.*\.json$")
|
|
9
|
+
|
|
10
|
+
# Count for reporting
|
|
11
|
+
processed_files = 0
|
|
12
|
+
|
|
13
|
+
# Walk through the directory
|
|
14
|
+
for root, _, files in os.walk(directory):
|
|
15
|
+
for filename in files:
|
|
16
|
+
# Check if the filename matches our pattern
|
|
17
|
+
if pattern.match(filename):
|
|
18
|
+
filepath = os.path.join(root, filename)
|
|
19
|
+
print(f"Processing file: {filepath}")
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
# Load the JSON content
|
|
23
|
+
with open(filepath, "r", encoding="utf-8") as file:
|
|
24
|
+
data = json.load(file)
|
|
25
|
+
|
|
26
|
+
# Make sure it's a dictionary
|
|
27
|
+
if not isinstance(data, dict):
|
|
28
|
+
print(
|
|
29
|
+
f" Warning: {filepath} does not contain a dictionary. Skipping."
|
|
30
|
+
)
|
|
31
|
+
continue
|
|
32
|
+
|
|
33
|
+
# Replace spaces with '\s' in all values
|
|
34
|
+
modified = False
|
|
35
|
+
for key, value in data.items():
|
|
36
|
+
if isinstance(value, str) and " " in value:
|
|
37
|
+
data[key] = value.replace(" ", "\\s")
|
|
38
|
+
modified = True
|
|
39
|
+
|
|
40
|
+
# Save the modified content only if changes were made
|
|
41
|
+
if modified:
|
|
42
|
+
with open(filepath, "w", encoding="utf-8") as file:
|
|
43
|
+
json.dump(data, file, ensure_ascii=False, indent=4)
|
|
44
|
+
print(f" Updated {filepath}")
|
|
45
|
+
else:
|
|
46
|
+
print(f" No spaces found in values of {filepath}")
|
|
47
|
+
|
|
48
|
+
processed_files += 1
|
|
49
|
+
|
|
50
|
+
except json.JSONDecodeError:
|
|
51
|
+
print(f" Error: {filepath} is not a valid JSON file. Skipping.")
|
|
52
|
+
except Exception as e:
|
|
53
|
+
print(f" Error processing {filepath}: {str(e)}")
|
|
54
|
+
|
|
55
|
+
print(f"\nSummary: Processed {processed_files} JSON files.")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
# Get the directory from user
|
|
60
|
+
directory = input("Enter the directory path to search: ")
|
|
61
|
+
|
|
62
|
+
# Validate directory exists
|
|
63
|
+
if not os.path.isdir(directory):
|
|
64
|
+
print(f"Error: '{directory}' is not a valid directory.")
|
|
65
|
+
else:
|
|
66
|
+
process_json_files(directory)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!usr/bin/env python
|
|
2
|
+
#! -*- coding: utf-8 -*-
|
|
3
|
+
import argparse
|
|
4
|
+
from collections import Counter
|
|
5
|
+
|
|
6
|
+
from chgksuite.composer import parse_4s
|
|
7
|
+
|
|
8
|
+
parser = argparse.ArgumentParser()
|
|
9
|
+
parser.add_argument("filename")
|
|
10
|
+
args = parser.parse_args()
|
|
11
|
+
|
|
12
|
+
authors = Counter()
|
|
13
|
+
|
|
14
|
+
with open(args.filename, "r", encoding="utf-8") as f:
|
|
15
|
+
structure = parse_4s(f.read().replace("\r", ""))
|
|
16
|
+
|
|
17
|
+
for element in structure:
|
|
18
|
+
if element[0] == "Question":
|
|
19
|
+
if "author" in element[1]:
|
|
20
|
+
authors[element[1]["author"].replace("`", "")] += 1
|
|
21
|
+
|
|
22
|
+
for au in authors.most_common():
|
|
23
|
+
print("{}\t{}".format(au[0], au[1]))
|
|
24
|
+
print("Total: {}".format(sum(authors.values())))
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Simple HTML table to Markdown converter.
|
|
2
|
+
|
|
3
|
+
Replaces dashtable.html2md with a minimal implementation that avoids
|
|
4
|
+
deprecated BeautifulSoup methods.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from bs4 import BeautifulSoup
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def html2md(html_string: str) -> str:
|
|
11
|
+
"""Convert an HTML table to a Markdown table string.
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
html_string : str
|
|
16
|
+
HTML string containing a table
|
|
17
|
+
|
|
18
|
+
Returns
|
|
19
|
+
-------
|
|
20
|
+
str
|
|
21
|
+
The table formatted as Markdown
|
|
22
|
+
"""
|
|
23
|
+
soup = BeautifulSoup(html_string, "html.parser")
|
|
24
|
+
table = soup.find("table")
|
|
25
|
+
|
|
26
|
+
if not table:
|
|
27
|
+
return ""
|
|
28
|
+
|
|
29
|
+
rows = table.find_all("tr")
|
|
30
|
+
if not rows:
|
|
31
|
+
return ""
|
|
32
|
+
|
|
33
|
+
# Extract all rows as lists of cell texts
|
|
34
|
+
data = []
|
|
35
|
+
for row in rows:
|
|
36
|
+
# Check for header cells first, then data cells
|
|
37
|
+
cells = row.find_all("th")
|
|
38
|
+
if not cells:
|
|
39
|
+
cells = row.find_all("td")
|
|
40
|
+
|
|
41
|
+
row_data = []
|
|
42
|
+
for cell in cells:
|
|
43
|
+
# Get text, normalize whitespace
|
|
44
|
+
text = " ".join(cell.get_text().split())
|
|
45
|
+
row_data.append(text)
|
|
46
|
+
if row_data:
|
|
47
|
+
data.append(row_data)
|
|
48
|
+
|
|
49
|
+
if not data:
|
|
50
|
+
return ""
|
|
51
|
+
|
|
52
|
+
# Normalize row lengths (pad shorter rows)
|
|
53
|
+
max_cols = max(len(row) for row in data)
|
|
54
|
+
for row in data:
|
|
55
|
+
while len(row) < max_cols:
|
|
56
|
+
row.append("")
|
|
57
|
+
|
|
58
|
+
# Calculate column widths (minimum 3 for markdown separator)
|
|
59
|
+
# Add 2 for space cushions on each side
|
|
60
|
+
widths = []
|
|
61
|
+
for col in range(max_cols):
|
|
62
|
+
width = max(len(row[col]) for row in data)
|
|
63
|
+
widths.append(max(width + 2, 3))
|
|
64
|
+
|
|
65
|
+
# Build markdown table
|
|
66
|
+
lines = []
|
|
67
|
+
|
|
68
|
+
# Header row (centered, with padding)
|
|
69
|
+
header = (
|
|
70
|
+
"|" + "|".join(_center(cell, widths[i]) for i, cell in enumerate(data[0])) + "|"
|
|
71
|
+
)
|
|
72
|
+
lines.append(header)
|
|
73
|
+
|
|
74
|
+
# Separator row (no spaces to avoid typotools converting --- to em-dash)
|
|
75
|
+
separator = "|" + "|".join("-" * w for w in widths) + "|"
|
|
76
|
+
lines.append(separator)
|
|
77
|
+
|
|
78
|
+
# Data rows (centered, with padding)
|
|
79
|
+
for row in data[1:]:
|
|
80
|
+
line = (
|
|
81
|
+
"|" + "|".join(_center(cell, widths[i]) for i, cell in enumerate(row)) + "|"
|
|
82
|
+
)
|
|
83
|
+
lines.append(line)
|
|
84
|
+
|
|
85
|
+
return "\n".join(lines)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _center(text: str, width: int) -> str:
|
|
89
|
+
"""Center text within width, with space padding."""
|
|
90
|
+
text = text.strip()
|
|
91
|
+
padding = width - len(text)
|
|
92
|
+
left = padding // 2
|
|
93
|
+
right = padding - left
|
|
94
|
+
return " " * left + text + " " * right
|
|
@@ -596,6 +596,15 @@ class ArgparseBuilder:
|
|
|
596
596
|
caption="Имя 4s-файла",
|
|
597
597
|
filetypes=[("chgksuite markup files", "*.4s")],
|
|
598
598
|
)
|
|
599
|
+
cmdcompose_markdown = cmdcompose_filetype.add_parser("markdown")
|
|
600
|
+
self.add_argument(
|
|
601
|
+
cmdcompose_markdown,
|
|
602
|
+
"filename",
|
|
603
|
+
nargs="*",
|
|
604
|
+
help="file(s) to compose from.",
|
|
605
|
+
caption="Имя 4s-файла",
|
|
606
|
+
filetypes=[("chgksuite markup files", "*.4s")],
|
|
607
|
+
)
|
|
599
608
|
cmdcompose_pptx = cmdcompose_filetype.add_parser("pptx")
|
|
600
609
|
self.add_argument(
|
|
601
610
|
cmdcompose_pptx,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
import argparse
|
|
4
|
-
import codecs
|
|
5
4
|
import csv
|
|
6
5
|
import itertools
|
|
7
6
|
import json
|
|
@@ -28,7 +27,7 @@ QUESTION_LABELS = [
|
|
|
28
27
|
"number",
|
|
29
28
|
"setcounter",
|
|
30
29
|
]
|
|
31
|
-
SEP =
|
|
30
|
+
SEP = "\n"
|
|
32
31
|
try:
|
|
33
32
|
ENC = sys.stdout.encoding or "utf8"
|
|
34
33
|
except AttributeError:
|
|
@@ -114,7 +113,7 @@ class DefaultArgs:
|
|
|
114
113
|
def set_lastdir(path):
|
|
115
114
|
chgksuite_dir = get_chgksuite_dir()
|
|
116
115
|
lastdir = os.path.join(chgksuite_dir, "lastdir")
|
|
117
|
-
with
|
|
116
|
+
with open(lastdir, "w", encoding="utf-8") as f:
|
|
118
117
|
f.write(path)
|
|
119
118
|
|
|
120
119
|
|
|
@@ -122,7 +121,7 @@ def get_lastdir():
|
|
|
122
121
|
chgksuite_dir = get_chgksuite_dir()
|
|
123
122
|
lastdir = os.path.join(chgksuite_dir, "lastdir")
|
|
124
123
|
if os.path.isfile(lastdir):
|
|
125
|
-
with
|
|
124
|
+
with open(lastdir, "r", encoding="utf-8") as f:
|
|
126
125
|
return f.read().rstrip()
|
|
127
126
|
return "."
|
|
128
127
|
|
|
@@ -153,6 +152,19 @@ def ensure_utf8(s):
|
|
|
153
152
|
return s
|
|
154
153
|
|
|
155
154
|
|
|
155
|
+
def read_text_file(filepath, encoding="utf-8"):
|
|
156
|
+
"""Read a text file, fixing corrupted line endings (\r\r\n -> \n) if present."""
|
|
157
|
+
with open(filepath, "rb") as f:
|
|
158
|
+
raw = f.read()
|
|
159
|
+
# Fix corrupted line endings at byte level before decoding
|
|
160
|
+
if b"\r\r\n" in raw:
|
|
161
|
+
raw = raw.replace(b"\r\r\n", b"\n")
|
|
162
|
+
text = raw.decode(encoding)
|
|
163
|
+
# Normalize any remaining line endings
|
|
164
|
+
text = text.replace("\r\n", "\n").replace("\r", "\n")
|
|
165
|
+
return text
|
|
166
|
+
|
|
167
|
+
|
|
156
168
|
class DummyLogger(object):
|
|
157
169
|
def info(self, *args, **kwargs):
|
|
158
170
|
pass
|
|
@@ -371,6 +383,5 @@ def compose_4s(structure, args=None):
|
|
|
371
383
|
+ SEP
|
|
372
384
|
)
|
|
373
385
|
tmp = re.sub(r"{}+".format(SEP), SEP, tmp)
|
|
374
|
-
tmp = tmp.replace("\r\r", "\r")
|
|
375
386
|
result += tmp + SEP
|
|
376
387
|
return result
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!usr/bin/env python
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
|
-
import codecs
|
|
4
3
|
import json
|
|
5
4
|
import os
|
|
6
5
|
import shutil
|
|
@@ -13,6 +12,7 @@ from chgksuite.common import (
|
|
|
13
12
|
get_source_dirs,
|
|
14
13
|
init_logger,
|
|
15
14
|
log_wrap,
|
|
15
|
+
read_text_file,
|
|
16
16
|
set_lastdir,
|
|
17
17
|
)
|
|
18
18
|
from chgksuite.composer.chgksuite_parser import parse_4s
|
|
@@ -22,7 +22,7 @@ from chgksuite.composer.docx import DocxExporter
|
|
|
22
22
|
from chgksuite.composer.latex import LatexExporter
|
|
23
23
|
from chgksuite.composer.lj import LjExporter
|
|
24
24
|
from chgksuite.composer.pptx import PptxExporter
|
|
25
|
-
from chgksuite.composer.
|
|
25
|
+
from chgksuite.composer.markdown import MarkdownExporter
|
|
26
26
|
from chgksuite.composer.stats import StatsAdder
|
|
27
27
|
from chgksuite.composer.telegram import TelegramExporter
|
|
28
28
|
from chgksuite.composer.openquiz import OpenquizExporter
|
|
@@ -75,11 +75,11 @@ def process_file_wrapper(filename, sourcedir, targetdir, args):
|
|
|
75
75
|
|
|
76
76
|
def parse_filepath(filepath, args=None):
|
|
77
77
|
args = args or DefaultArgs()
|
|
78
|
-
|
|
79
|
-
input_text = input_file.read()
|
|
80
|
-
input_text = input_text.replace("\r", "")
|
|
78
|
+
input_text = read_text_file(filepath)
|
|
81
79
|
debug_dir = os.path.dirname(os.path.abspath(filepath))
|
|
82
|
-
return parse_4s(
|
|
80
|
+
return parse_4s(
|
|
81
|
+
input_text, randomize=args.randomize, debug=args.debug, debug_dir=debug_dir
|
|
82
|
+
)
|
|
83
83
|
|
|
84
84
|
|
|
85
85
|
def make_merged_filename(filelist):
|
|
@@ -106,7 +106,7 @@ def process_file(filename, tmp_dir, targetdir, args=None, logger=None):
|
|
|
106
106
|
targetdir,
|
|
107
107
|
make_filename(os.path.basename(filename), "dbg", args),
|
|
108
108
|
)
|
|
109
|
-
with
|
|
109
|
+
with open(debug_fn, "w", encoding="utf-8") as output_file:
|
|
110
110
|
output_file.write(json.dumps(structure, indent=2, ensure_ascii=False))
|
|
111
111
|
|
|
112
112
|
if not args.filetype:
|
|
@@ -147,8 +147,8 @@ def process_file(filename, tmp_dir, targetdir, args=None, logger=None):
|
|
|
147
147
|
outfilename = os.path.join(targetdir, make_filename(filename, "txt", args))
|
|
148
148
|
exporter.export(outfilename)
|
|
149
149
|
|
|
150
|
-
if args.filetype
|
|
151
|
-
exporter =
|
|
150
|
+
if args.filetype in ("redditmd", "markdown"):
|
|
151
|
+
exporter = MarkdownExporter(structure, args, dir_kwargs)
|
|
152
152
|
outfilename = os.path.join(targetdir, make_filename(filename, "md", args))
|
|
153
153
|
exporter.export(outfilename)
|
|
154
154
|
|