├── .github └── workflows │ ├── build.yml │ ├── latest bump.yml │ └── latest commit comment.yml ├── .gitignore ├── .markdownlint.yml ├── .vscode └── settings.json ├── dev ├── constants │ ├── dictionary.txt │ ├── req.txt │ ├── scripts.yml │ ├── tpl │ │ ├── autodoc.mustache │ │ ├── pdoc │ │ │ ├── _lunr_search.inc.mako │ │ │ ├── config.mako │ │ │ ├── credits.mako │ │ │ ├── css.mako │ │ │ ├── head.mako │ │ │ ├── html.mako │ │ │ ├── logo.mako │ │ │ ├── pdf.mako │ │ │ └── text.mako │ │ └── scripts │ │ │ └── AppRun │ └── version │ │ └── 0 │ │ └── 0 │ │ ├── _meta.yml │ │ ├── cmd.yml │ │ ├── config.yml │ │ └── naming conventions.yml ├── raw_docs │ ├── README.ymd │ ├── changelog.mako │ ├── changelog.mmd │ ├── docs │ │ └── 0 │ │ │ └── 0 │ │ │ ├── config.mako │ │ │ ├── index.mako │ │ │ └── structure.ymd │ ├── faq.ymd │ ├── latest-bump.mako │ ├── latest-commit.mako │ ├── latest-commit.mmd │ ├── latest-release-notes.mako │ ├── license.ymd │ ├── notes-to-self.ymd │ └── todo.yml ├── scripts │ ├── ps1 │ │ ├── fmt.ps1 │ │ ├── req.ps1 │ │ └── start.ps1 │ ├── py │ │ ├── cd.py │ │ ├── cfg.py │ │ ├── docs.py │ │ ├── eb.py │ │ ├── exceptions.py │ │ ├── inst_mods │ │ │ └── whine_md_fmt │ │ │ │ ├── main.py │ │ │ │ └── setup.py │ │ ├── main.py │ │ ├── md_vars.py │ │ ├── rn_md.py │ │ ├── schema.py │ │ ├── scripts.py │ │ └── utils.py │ └── sh │ │ └── source.sh ├── site │ ├── 404.html │ ├── _meta.yml │ ├── assets │ │ ├── images │ │ │ ├── favicon.png │ │ │ └── icons │ │ │ │ ├── code.png │ │ │ │ ├── contributors.png │ │ │ │ ├── discord.png │ │ │ │ ├── dl.png │ │ │ │ ├── forks.png │ │ │ │ ├── icon.png │ │ │ │ ├── issues.png │ │ │ │ ├── license.png │ │ │ │ ├── logo-black.png │ │ │ │ ├── logo-black.xcf │ │ │ │ ├── logo.png │ │ │ │ ├── logo.xcf │ │ │ │ ├── read.png │ │ │ │ └── stars.png │ │ ├── javascripts │ │ │ ├── bundle.9c69f0bc.min.js │ │ │ ├── bundle.9c69f0bc.min.js.map │ │ │ ├── lunr │ │ │ │ ├── min │ │ │ │ │ ├── lunr.ar.min.js │ │ │ │ │ ├── lunr.da.min.js │ │ │ │ │ ├── lunr.de.min.js │ │ │ │ │ ├── lunr.du.min.js │ │ │ │ │ ├── lunr.es.min.js │ │ │ │ │ ├── lunr.fi.min.js │ │ │ │ │ ├── lunr.fr.min.js │ │ │ │ │ ├── lunr.hi.min.js │ │ │ │ │ ├── lunr.hu.min.js │ │ │ │ │ ├── lunr.it.min.js │ │ │ │ │ ├── lunr.ja.min.js │ │ │ │ │ ├── lunr.jp.min.js │ │ │ │ │ ├── lunr.multi.min.js │ │ │ │ │ ├── lunr.nl.min.js │ │ │ │ │ ├── lunr.no.min.js │ │ │ │ │ ├── lunr.pt.min.js │ │ │ │ │ ├── lunr.ro.min.js │ │ │ │ │ ├── lunr.ru.min.js │ │ │ │ │ ├── lunr.stemmer.support.min.js │ │ │ │ │ ├── lunr.sv.min.js │ │ │ │ │ ├── lunr.th.min.js │ │ │ │ │ ├── lunr.tr.min.js │ │ │ │ │ ├── lunr.vi.min.js │ │ │ │ │ └── lunr.zh.min.js │ │ │ │ ├── tinyseg.js │ │ │ │ └── wordcut.js │ │ │ └── workers │ │ │ │ ├── search.ecf98df9.min.js │ │ │ │ └── search.ecf98df9.min.js.map │ │ └── stylesheets │ │ │ ├── main.69437709.min.css │ │ │ ├── main.69437709.min.css.map │ │ │ ├── palette.cbb835fc.min.css │ │ │ └── palette.cbb835fc.min.css.map │ ├── changelog │ │ └── index.html │ ├── docs │ │ └── 0 │ │ │ └── 0 │ │ │ ├── api │ │ │ ├── gui │ │ │ │ └── index.html │ │ │ ├── index.html │ │ │ └── src │ │ │ │ ├── base │ │ │ │ └── index.html │ │ │ │ ├── cd │ │ │ │ └── index.html │ │ │ │ ├── cfg │ │ │ │ └── index.html │ │ │ │ ├── cli │ │ │ │ └── index.html │ │ │ │ ├── download │ │ │ │ └── index.html │ │ │ │ ├── exceptions │ │ │ │ └── index.html │ │ │ │ ├── globals │ │ │ │ └── index.html │ │ │ │ ├── index.html │ │ │ │ ├── init │ │ │ │ └── index.html │ │ │ │ ├── style │ │ │ │ └── index.html │ │ │ │ └── utils │ │ │ │ └── index.html │ │ │ ├── config │ │ │ └── index.html │ │ │ ├── index.html │ │ │ └── structure │ │ │ └── index.html │ ├── faq │ │ └── index.html │ ├── index.html │ ├── latest-bump │ │ └── index.html │ ├── latest-commit │ │ └── index.html │ ├── latest-release-notes │ │ └── index.html │ ├── license │ │ └── index.html │ ├── notes-to-self │ │ └── index.html │ ├── search │ │ └── search_index.json │ ├── sitemap.xml │ └── sitemap.xml.gz └── vars.yml ├── docs ├── README.md ├── _meta.yml ├── assets │ └── images │ │ └── icons │ │ ├── code.png │ │ ├── contributors.png │ │ ├── discord.png │ │ ├── dl.png │ │ ├── forks.png │ │ ├── icon.png │ │ ├── issues.png │ │ ├── license.png │ │ ├── logo-black.png │ │ ├── logo-black.xcf │ │ ├── logo.png │ │ ├── logo.xcf │ │ ├── read.png │ │ └── stars.png ├── changelog.md ├── docs │ └── 0 │ │ └── 0 │ │ ├── api │ │ ├── gui.md │ │ ├── index.md │ │ ├── src.md │ │ └── src │ │ │ ├── base.md │ │ │ ├── cd.md │ │ │ ├── cfg.md │ │ │ ├── cli.md │ │ │ ├── download.md │ │ │ ├── exceptions.md │ │ │ ├── globals.md │ │ │ ├── init.md │ │ │ ├── style.md │ │ │ └── utils.md │ │ ├── config.md │ │ ├── index.md │ │ └── structure.md ├── faq.md ├── latest-bump.md ├── latest-commit.md ├── latest-release-notes.md ├── license.md └── notes-to-self.md ├── mkdocs.yml ├── package.json ├── requirements.txt ├── source.ps1 ├── source.sh ├── ura ├── __init__.py ├── gui.py ├── gui │ ├── assets │ │ └── images │ │ │ ├── info.svg │ │ │ └── settings.svg │ ├── index.html │ ├── loading.html │ ├── main.js │ ├── preload.js │ ├── renderer.js │ └── style.css └── src │ ├── __init__.py │ ├── __main__.py │ ├── base.py │ ├── cd.py │ ├── cf_tpl.mp │ ├── cfg.py │ ├── cli.py │ ├── cmd.mp │ ├── download.py │ ├── exceptions.py │ ├── globals.py │ ├── hc.yml │ ├── init.py │ ├── style.py │ └── utils.py └── version.yml /.github/workflows/latest bump.yml: -------------------------------------------------------------------------------- 1 | name: Latest Bump Comment 2 | 3 | on: 4 | push: 5 | paths: 6 | - version.yml 7 | workflow_dispatch: 8 | 9 | jobs: 10 | Comment: 11 | name: Comment 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@master 16 | - id: get-comment-body 17 | run: | 18 | body=$(cat "docs/latest-bump.md") 19 | body="${body//'%'/'%25'}" 20 | body="${body//$'\n'/'%0A'}" 21 | body="${body//$'\r'/'%0D'}" 22 | echo ::set-output name=body::$body 23 | - name: Create commit comment 24 | uses: peter-evans/commit-comment@v2 25 | with: 26 | body: ${{ steps.get-comment-body.outputs.body }} -------------------------------------------------------------------------------- /.github/workflows/latest commit comment.yml: -------------------------------------------------------------------------------- 1 | name: Latest Commit Comment 2 | 3 | on: 4 | push: 5 | paths: 6 | - dev/raw_docs/latest-commit.mmd 7 | workflow_dispatch: 8 | 9 | jobs: 10 | Comment: 11 | name: Comment 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@master 16 | - id: get-comment-body 17 | run: | 18 | body=$(cat "docs/latest-commit.md") 19 | body="${body//'%'/'%25'}" 20 | body="${body//$'\n'/'%0A'}" 21 | body="${body//$'\r'/'%0D'}" 22 | echo ::set-output name=body::$body 23 | - name: Create commit comment 24 | uses: peter-evans/commit-comment@v2 25 | with: 26 | body: ${{ steps.get-comment-body.outputs.body }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # User-defined Ignored Folders 2 | .history/ 3 | node_modules/ 4 | squashfs-root/ 5 | **/tmp/ 6 | 7 | # User-defined Ignored Files 8 | *.bak.* 9 | ura.yml 10 | yarn.lock 11 | yarn-error.log 12 | **/*.bak.* 13 | **/t[0-9]*.* 14 | **/*.AppImage 15 | 16 | # Byte-compiled / optimized / DLL files 17 | **/__pycache__/ 18 | *.py[cod] 19 | *$py.class 20 | 21 | # C extensions 22 | *.so 23 | 24 | # Distribution / packaging 25 | .Python 26 | build/ 27 | develop-eggs/ 28 | dist/ 29 | downloads/ 30 | eggs/ 31 | .eggs/ 32 | lib/ 33 | lib64/ 34 | parts/ 35 | sdist/ 36 | var/ 37 | wheels/ 38 | share/python-wheels/ 39 | *.egg-info/ 40 | .installed.cfg 41 | *.egg 42 | MANIFEST 43 | 44 | # PyInstaller 45 | # Usually these files are written by a python script from a template 46 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 47 | *.manifest 48 | *.spec 49 | 50 | # Installer logs 51 | pip-log.txt 52 | pip-delete-this-directory.txt 53 | 54 | # Unit test / coverage reports 55 | htmlcov/ 56 | .tox/ 57 | .nox/ 58 | .coverage 59 | .coverage.* 60 | .cache 61 | nosetests.xml 62 | coverage.xml 63 | *.cover 64 | *.py,cover 65 | .hypothesis/ 66 | .pytest_cache/ 67 | cover/ 68 | 69 | # Translations 70 | *.mo 71 | *.pot 72 | 73 | # Django stuff: 74 | *.log 75 | local_settings.py 76 | db.sqlite3 77 | db.sqlite3-journal 78 | 79 | # Flask stuff: 80 | instance/ 81 | .webassets-cache 82 | 83 | # Scrapy stuff: 84 | .scrapy 85 | 86 | # Sphinx documentation 87 | docs/_build/ 88 | 89 | # PyBuilder 90 | .pybuilder/ 91 | target/ 92 | 93 | # Jupyter Notebook 94 | .ipynb_checkpoints 95 | 96 | # IPython 97 | profile_default/ 98 | ipython_config.py 99 | 100 | # pyenv 101 | # For a library or package, you might want to ignore these files since the code is 102 | # intended to run in multiple environments; otherwise, check them in: 103 | # .python-version 104 | 105 | # pipenv 106 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 107 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 108 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 109 | # install all needed dependencies. 110 | #Pipfile.lock 111 | 112 | # poetry 113 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 114 | # This is especially recommended for binary packages to ensure reproducibility, and is more 115 | # commonly ignored for libraries. 116 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 117 | #poetry.lock 118 | 119 | # pdm 120 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 121 | #pdm.lock 122 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 123 | # in version control. 124 | # https://pdm.fming.dev/#use-with-ide 125 | .pdm.toml 126 | 127 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 128 | __pypackages__/ 129 | 130 | # Celery stuff 131 | celerybeat-schedule 132 | celerybeat.pid 133 | 134 | # SageMath parsed files 135 | *.sage.py 136 | 137 | # Environments 138 | .env 139 | .venv 140 | env/ 141 | venv/ 142 | ENV/ 143 | env.bak/ 144 | venv.bak/ 145 | pyenv/ 146 | 147 | # Spyder project settings 148 | .spyderproject 149 | .spyproject 150 | 151 | # Rope project settings 152 | .ropeproject 153 | 154 | # mypy 155 | .mypy_cache/ 156 | .dmypy.json 157 | dmypy.json 158 | 159 | # Pyre type checker 160 | .pyre/ 161 | 162 | # pytype static type analyzer 163 | .pytype/ 164 | 165 | # Cython debug symbols 166 | cython_debug/ -------------------------------------------------------------------------------- /.markdownlint.yml: -------------------------------------------------------------------------------- 1 | MD004: 2 | - asterisk 3 | - dash 4 | MD007: 5 | indent: 4 6 | MD013: false 7 | MD033: false -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.defaultInterpreterPath": "./pyenv/bin/python", 3 | "python.languageServer": "Pylance", 4 | "autoDocstring.customTemplatePath": "dev/constants/tpl/autodoc.mustache", 5 | "vscode-yaml-sort.useCustomSortRecursively": true, 6 | "yaml.schemas": { 7 | "https://json.schemastore.org/yamllint.json": "file:///home/whine/whi_ne/3/projects/personal/tools/urasunday/.markdownlint.yml" 8 | }, 9 | // "vscode-yaml-sort.customSortKeywords_1": [ 10 | // "phrase", 11 | // "description", 12 | // "spec", 13 | // "link" 14 | // ], 15 | } -------------------------------------------------------------------------------- /dev/constants/dictionary.txt: -------------------------------------------------------------------------------- 1 | Hyaku 2 | bprv 3 | pdoc 4 | vlir 5 | traceback 6 | Mistilteinn 7 | urasunday 8 | cholder 9 | Mysid 10 | Codacy 11 | Wakatime 12 | shellcheck 13 | whinee 14 | MangDL 15 | YAMHL 16 | NEET 17 | animanga 18 | niet 19 | CFLOP 20 | kwargs 21 | builtins 22 | dnrp 23 | bruv 24 | mkdocs 25 | mdformat 26 | shfmt 27 | str_representer 28 | squashfs 29 | -------------------------------------------------------------------------------- /dev/constants/req.txt: -------------------------------------------------------------------------------- 1 | black 2 | isort 3 | mako 4 | mdformat 5 | mdformat-frontmatter 6 | mdformat-footnote 7 | mdformat-gfm 8 | mdformat-shfmt 9 | mkdocs 10 | mkdocs-material 11 | mkdocs-minify-plugin 12 | mkdocs-redirects 13 | msgpack 14 | niet 15 | pdoc3 16 | python-frontmatter -------------------------------------------------------------------------------- /dev/constants/tpl/autodoc.mustache: -------------------------------------------------------------------------------- 1 | {{! Google Docstring Template }} 2 | {{summaryPlaceholder}} 3 | 4 | {{#parametersExist}} 5 | 6 | Args: 7 | {{#args}} 8 | - {{var}} (`{{typePlaceholder}}`): {{descriptionPlaceholder}} 9 | {{/args}} 10 | {{#kwargs}} 11 | - {{var}} (`{{typePlaceholder}}`, optional): {{descriptionPlaceholder}}. Defaults to `{{&default}}`. 12 | {{/kwargs}} 13 | {{/parametersExist}} 14 | {{#exceptionsExist}} 15 | 16 | Raises: 17 | {{#exceptions}} 18 | - `{{type}}`: {{descriptionPlaceholder}} 19 | {{/exceptions}} 20 | {{/exceptionsExist}} 21 | {{#returnsExist}} 22 | 23 | Returns: 24 | {{#returns}} 25 | `{{typePlaceholder}`}: {{descriptionPlaceholder}} 26 | {{/returns}} 27 | {{/returnsExist}} 28 | {{#yieldsExist}} 29 | 30 | Yields: 31 | {{#yields}} 32 | `{{typePlaceholder}}`: {{descriptionPlaceholder}} 33 | {{/yields}} 34 | {{/yieldsExist}} -------------------------------------------------------------------------------- /dev/constants/tpl/pdoc/_lunr_search.inc.mako: -------------------------------------------------------------------------------- 1 |
2 | 4 |
5 | 6 | 7 | 21 | 51 | -------------------------------------------------------------------------------- /dev/constants/tpl/pdoc/config.mako: -------------------------------------------------------------------------------- 1 | <%! 2 | # Template configuration. Copy over in your template directory 3 | # (used with `--template-dir`) and adapt as necessary. 4 | # Note, defaults are loaded from this distribution file, so your 5 | # config.mako only needs to contain values you want overridden. 6 | # You can also run pdoc with `--config KEY=VALUE` to override 7 | # individual values. 8 | 9 | html_lang = 'en' 10 | show_inherited_members = False 11 | extract_module_toc_into_sidebar = True 12 | list_class_variables_in_index = True 13 | sort_identifiers = True 14 | show_type_annotations = True 15 | 16 | # Show collapsed source code block next to each item. 17 | # Disabling this can improve rendering speed of large modules. 18 | show_source_code = True 19 | 20 | # If set, format links to objects in online source code repository 21 | # according to this template. Supported keywords for interpolation 22 | # are: commit, path, start_line, end_line. 23 | #git_link_template = 'https://github.com/USER/PROJECT/blob/{commit}/{path}#L{start_line}-L{end_line}' 24 | #git_link_template = 'https://gitlab.com/USER/PROJECT/blob/{commit}/{path}#L{start_line}-L{end_line}' 25 | #git_link_template = 'https://bitbucket.org/USER/PROJECT/src/{commit}/{path}#lines-{start_line}:{end_line}' 26 | #git_link_template = 'https://CGIT_HOSTNAME/PROJECT/tree/{path}?id={commit}#n{start-line}' 27 | git_link_template = None 28 | 29 | # A prefix to use for every HTML hyperlink in the generated documentation. 30 | # No prefix results in all links being relative. 31 | link_prefix = '' 32 | 33 | # Enable syntax highlighting for code/source blocks by including Highlight.js 34 | syntax_highlighting = True 35 | 36 | # Set the style keyword such as 'atom-one-light' or 'github-gist' 37 | # Options: https://github.com/highlightjs/highlight.js/tree/master/src/styles 38 | # Demo: https://highlightjs.org/static/demo/ 39 | hljs_style = 'github' 40 | 41 | # If set, insert Google Analytics tracking code. Value is GA 42 | # tracking id (UA-XXXXXX-Y). 43 | google_analytics = '' 44 | 45 | # If set, insert Google Custom Search search bar widget above the sidebar index. 46 | # The whitespace-separated tokens represent arbitrary extra queries (at least one 47 | # must match) passed to regular Google search. Example: 48 | #google_search_query = 'inurl:github.com/USER/PROJECT site:PROJECT.github.io site:PROJECT.website' 49 | google_search_query = '' 50 | 51 | # Enable offline search using Lunr.js. For explanation of 'fuzziness' parameter, which is 52 | # added to every query word, see: https://lunrjs.com/guides/searching.html#fuzzy-matches 53 | # If 'index_docstrings' is False, a shorter index is built, indexing only 54 | # the full object reference names. 55 | #lunr_search = {'fuzziness': 1, 'index_docstrings': True} 56 | lunr_search = None 57 | 58 | # If set, render LaTeX math syntax within \(...\) (inline equations), 59 | # or within \[...\] or $$...$$ or `.. math::` (block equations) 60 | # as nicely-formatted math formulas using MathJax. 61 | # Note: in Python docstrings, either all backslashes need to be escaped (\\) 62 | # or you need to use raw r-strings. 63 | latex_math = False 64 | %> 65 | -------------------------------------------------------------------------------- /dev/constants/tpl/pdoc/credits.mako: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/constants/tpl/pdoc/credits.mako -------------------------------------------------------------------------------- /dev/constants/tpl/pdoc/head.mako: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/constants/tpl/pdoc/head.mako -------------------------------------------------------------------------------- /dev/constants/tpl/pdoc/logo.mako: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/constants/tpl/pdoc/logo.mako -------------------------------------------------------------------------------- /dev/constants/tpl/pdoc/text.mako: -------------------------------------------------------------------------------- 1 | ## Define mini-templates for each portion of the doco. 2 | 3 | <%def name="h(hs, s, link=None)" buffered="True"> 4 | <% 5 | if link is None: 6 | link = s 7 | header = f'{s}' 8 | match hs: 9 | case 4: 10 | hs = 3 11 | header = f'{header}' 12 | case 5: 13 | hs = 3 14 | header = f'{header}' 15 | case 6: 16 | hs = 3 17 | case _: 18 | header = f'{header}' 19 | header = f'{header}' 20 | %> 21 | ${header} 22 | 23 | 24 | <%def name="ds(s, hs, link=None)" buffered="True"> 25 | <% 26 | if link is None: 27 | link = "" 28 | for i in ["Args", "Raises", "Returns", "Yields"]: 29 | s = s.replace(f'{i}:', h(hs, i + ':', link + i.lower())) 30 | %> 31 | ${s} 32 | 33 | <%def name="function(func, hs, cls=None)" buffered="True"> 34 | <% 35 | if cls is None: 36 | link = f'func-{func.name}' 37 | else: 38 | link = f'class-{cls}-func-{func.name}' 39 | header = h(hs, func.name, link) 40 | returns = show_type_annotations and func.return_annotation() or '' 41 | if returns: 42 | returns = ' \N{non-breaking hyphen}> ' + returns 43 | %> 44 | 45 | 46 | ${header} 47 | ```python 48 | (${", ".join(func.params(annotate=show_type_annotations))})${returns} 49 | ``` 50 | ${ds(func.docstring, hs + 1, link + '-')} 51 | <%def name="variable(var)" buffered="True"> 52 | <% 53 | annot = show_type_annotations and var.type_annotation() or '' 54 | if annot: 55 | annot = ': ' + annot 56 | %> 57 | `${var.name}${annot}` 58 | ${var.docstring} 59 | 60 | 61 | <%def name="class_(cls)" buffered="True"> 62 | ${h(3, cls.name, f'class-{cls.name}')}```python 63 | (${", ".join(cls.params(annotate=show_type_annotations))}) 64 | ``` 65 | <% 66 | class_vars = cls.class_variables(show_inherited_members, sort=sort_identifiers) 67 | static_methods = cls.functions(show_inherited_members, sort=sort_identifiers) 68 | inst_vars = cls.instance_variables(show_inherited_members, sort=sort_identifiers) 69 | methods = cls.methods(show_inherited_members, sort=sort_identifiers) 70 | mro = cls.mro() 71 | subclasses = cls.subclasses() 72 | link = f'class-{cls.name}-' 73 | %> 74 | ${ds(cls.docstring, 4, link)} 75 | % if mro: 76 | ${h(4, 'Ancestors (in MRO)', link + 'mro')} 77 | % for c in mro: 78 | * ${c.refname} 79 | % endfor 80 | 81 | % endif 82 | % if subclasses: 83 | ${h(4, 'Descendants', link + 'sub')} 84 | % for c in subclasses: 85 | * ${c.refname} 86 | % endfor 87 | 88 | % endif 89 | % if class_vars: 90 | ${h(4, 'Class variables', link + 'cvar')} 91 | % for v in class_vars: 92 | ${variable(v)} 93 | 94 | % endfor 95 | % endif 96 | % if static_methods: 97 | ${h(4, 'Static methods', link + 'sfunc')} 98 | % for f in static_methods: 99 | ${function(f, 5, cls.name)} 100 | 101 | % endfor 102 | % endif 103 | % if inst_vars: 104 | ${h(4, 'Instance variables', link + 'var')} 105 | % for v in inst_vars: 106 | ${variable(v)} 107 | 108 | % endfor 109 | % endif 110 | % if methods: 111 | ${h(4, 'Methods', link + 'func')} 112 | % for m in methods: 113 | ${function(m, 5, cls.name)} 114 | 115 | % endfor 116 | % endif 117 | 118 | 119 | ## Start the output logic for an entire module. 120 | 121 | <% 122 | variables = module.variables(sort=sort_identifiers) 123 | classes = module.classes(sort=sort_identifiers) 124 | functions = module.functions(sort=sort_identifiers) 125 | submodules = module.submodules() 126 | 127 | header = [] 128 | m, *ls = module.name.split(".") 129 | for idx, i in enumerate(ls[::-1]): 130 | header.append(f'[{i}]({"../" * idx}{i}.md)') 131 | 132 | header = '.'.join([f'[{m}](' + '../' * (len(ls) - 1) + 'index.md)'] + header[::-1]) 133 | %> 134 | 135 | # **${header}** 136 | ${ds(module.docstring, 2)} 137 | 138 | % if submodules: 139 | **Sub-modules** 140 | --------------- 141 | % for m in submodules: 142 | * ${m.name} 143 | % endfor 144 | % endif 145 | 146 | % if variables: 147 | **Variables** 148 | ------------- 149 | % for v in variables: 150 | ${variable(v)} 151 | 152 | % endfor 153 | % endif 154 | 155 | % if functions: 156 | **Functions** 157 | ------------- 158 | % for f in functions: 159 | ${function(f, 3)} 160 | 161 | % endfor 162 | % endif 163 | 164 | % if classes: 165 | **Classes** 166 | ----------- 167 | % for c in classes: 168 | ${class_(c)} 169 | 170 | % endfor 171 | % endif 172 | -------------------------------------------------------------------------------- /dev/constants/tpl/scripts/AppRun: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1087,SC1091,SC2001,SC2025,SC2045,SC2059,SC2119,SC2120,SC2162,SC2148,SC2154,SC2155,SC2195,SC2210 3 | 4 | set -e 5 | 6 | if [ -n "$DEBUG" ]; then 7 | env 8 | set -x 9 | fi 10 | 11 | THIS="$0" 12 | 13 | if [ -z "$APPDIR" ]; then 14 | path="$(dirname "$(readlink -f "${THIS}")")" 15 | while [[ "$path" != "" && ! -e "$path" ]]; do 16 | path=${path%/*} 17 | done 18 | APPDIR="$path" 19 | fi 20 | 21 | if [ -z "$APPIMAGE" ]; then 22 | APPIMAGE="$APPDIR/AppRun" 23 | fi 24 | 25 | arg0=$(basename "$0" .sh) 26 | blnk=$(echo "$arg0" | sed "s/./ /g") 27 | 28 | usage_info() { 29 | echo "Usage: $arg0 [-g|--gui] \\" 30 | echo " $blnk [-h|--help] \\" 31 | } 32 | 33 | help() { 34 | usage_info 35 | echo 36 | echo " [-g|--gui] -- Run GUI" 37 | echo " [-h|--help] -- Print this help message and exit" 38 | } 39 | 40 | gui() { 41 | exec "$APPDIR/ura" 42 | exit 0 43 | } 44 | 45 | cli() { 46 | "$APPDIR/resources/app/tmp/python/opt/python3.10/bin/python3.10" "$APPDIR/resources/app/tmp/src" $@ 47 | } 48 | 49 | if [ $# -eq 0 ]; then 50 | gui 51 | else 52 | case "$1" in 53 | gui) gui ;; 54 | cli) 55 | shift 56 | cli $@ 57 | ;; 58 | help) 59 | help 60 | exit 0 61 | ;; 62 | *) 63 | cli $@ 64 | exit 1 65 | ;; 66 | esac 67 | fi -------------------------------------------------------------------------------- /dev/constants/version/0/0/_meta.yml: -------------------------------------------------------------------------------- 1 | cp: 2 | cmd: 3 | dir: ura/src/cmd -------------------------------------------------------------------------------- /dev/constants/version/0/0/cmd.yml: -------------------------------------------------------------------------------- 1 | main: 2 | args: 3 | kwargs: 4 | arguments: 5 | options: 6 | cmd: 7 | dl: 8 | args: 9 | kwargs: 10 | help: 11 | - download manga 12 | - |- 13 | Download chapter from https://urasunday.com 14 | arguments: 15 | url: 16 | args: 17 | kwargs: 18 | help: 19 | - str 20 | - |- 21 | URL of the chapter to download. 22 | options: 23 | d: 24 | args: 25 | - directory 26 | kwargs: 27 | metavar: '' 28 | help: 29 | - str 30 | - |- 31 | Directory to download the chapter at. Defaults to ~/Manga for Linux-based operating systems and Desktop/Manga for Windows. 32 | o: 33 | args: 34 | - overwrite 35 | - overwrite 36 | kwargs: 37 | default: true 38 | flag_value: true 39 | metavar: '' 40 | help: 41 | - N/A (flag) 42 | - |- 43 | Overwrite the chapter if it is already downloaded. 44 | 'on': 45 | args: 46 | - overwrite_not 47 | - overwrite 48 | kwargs: 49 | flag_value: false 50 | metavar: '' 51 | help: 52 | - N/A (flag) 53 | - |- 54 | Do not overwrite the chapter if it is already downloaded. 55 | shit me naught 56 | op: 57 | args: 58 | - overwrite_prompt 59 | - overwrite_prompt 60 | kwargs: 61 | default: false 62 | flag_value: true 63 | metavar: '' 64 | help: 65 | - N/A (flag) 66 | - |- 67 | Prompt user to overwrite the chapter if it is already downloaded. 68 | opn: 69 | args: 70 | - overwrite_prompt_not 71 | - overwrite_prompt 72 | kwargs: 73 | flag_value: false 74 | metavar: '' 75 | help: 76 | - N/A (flag) 77 | - |- 78 | Do not prompt user to overwrite the chapter if it is already downloaded. 79 | # op: 80 | # args: 81 | # - overwrite 82 | # kwargs: 83 | # default: true 84 | # is_flag: true 85 | # metavar: '' 86 | # help: 87 | # - N/A (flag) 88 | # - |- 89 | # Determines if the app prompts you to overwrite if the chapter is already downloaded. Only applicable if Defaults to False. 90 | # (True | False). 91 | credits: 92 | args: 93 | kwargs: 94 | help: 95 | - credits 96 | - |- 97 | It's the credits, whaddya expect? 98 | arguments: 99 | options: 100 | version: 101 | args: 102 | kwargs: 103 | help: 104 | - Print version. 105 | - |- 106 | Print version of the program. 107 | arguments: 108 | options: -------------------------------------------------------------------------------- /dev/constants/version/0/0/config.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.0 2 | config: 3 | download_dir: 4 | req: false 5 | type: str 6 | abbr: Download Directory 7 | desc: |- 8 | Directory to download the chapter at. 9 | overwrite: 10 | req: false 11 | type: bool 12 | default: true 13 | desc: |- 14 | Determines if the program overwrites the chapter if it is already downloaded. 15 | overwrite_prompt: 16 | req: false 17 | type: bool 18 | default: false 19 | desc: |- 20 | Determines if the program prompts the user to overwrite the chapter if it is already downloaded. -------------------------------------------------------------------------------- /dev/constants/version/0/0/naming conventions.yml: -------------------------------------------------------------------------------- 1 | general: 2 | idx: 3 | abbr: index 4 | urel: 5 | abbr: relative URL 6 | usi: 7 | abbr: url_slug_idx 8 | expd: URL slug index 9 | XCH: 10 | abbr: XDG_CONFIG_HOME 11 | XDG: 12 | abbr: X Development Group -------------------------------------------------------------------------------- /dev/raw_docs/changelog.mako: -------------------------------------------------------------------------------- 1 | <% 2 | import re 3 | from os import path 4 | 5 | RE_H1 = re.compile(r"# ([^\n]*)(.*?)(?=\n#\s|$)", re.DOTALL) 6 | RE_DESC = re.compile(r'^(?!## )(.+?)\n\n## ', re.DOTALL) 7 | RE_H2 = re.compile(r"## ([^\n]*)\s*(.*?)(?=\n##\s|$)", re.DOTALL) 8 | RE_LC = re.compile(r"- (.*?)(?=- |$)", re.DOTALL) 9 | 10 | PR = ["alpha", "beta", "rc"] 11 | 12 | def rv(vls: list[str | int]): 13 | pr = "" 14 | vls = [int(i) for i in vls] 15 | if vls[4] <= 2: 16 | pr = f'-{PR[vls[4]]}.{vls[5]}' 17 | return ".".join([str(i) for i in vls[0:4]]) + pr 18 | 19 | with open(path.join(cwd, "changelog.mmd"), "r") as f: 20 | CL = f.read() 21 | 22 | d_op = {} 23 | for vb in RE_H1.findall(CL): 24 | ver, dtls = vb 25 | vls = ver.split(" ") 26 | if desc := RE_DESC.match(dtls): 27 | desc = desc.group(1) 28 | else: 29 | desc = '' 30 | d_op[rv(vls)] = ov = { 31 | "vls": vls, 32 | "anchor": ver.replace(" ", "-"), 33 | "desc": desc.strip(), 34 | "changes": {} 35 | } 36 | for tch in RE_H2.findall(dtls): 37 | t, chls = tch 38 | ov["changes"][t] = ovt = [] 39 | for ch in RE_LC.findall(chls): 40 | ovt.append(ch) 41 | 42 | md_op = "" 43 | for k, v in d_op.items(): 44 | md_op += f'\n\n

{k}

' 45 | if desc:=v["desc"]: 46 | md_op += f'\n\n{desc}\n\n' 47 | else: 48 | md_op += '' 49 | for t, chls in v["changes"].items(): 50 | md_op += f'\n\n

{t}

\n' 51 | for ch in chls: 52 | md_op += f'\n- {ch}' 53 | %> 54 |

55 | Changelog 56 |

${md_op} -------------------------------------------------------------------------------- /dev/raw_docs/changelog.mmd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 27 | 28 | # 0 0 0 0 2 0 29 | 30 | ## Added 31 | 32 | - `-on`/`--overwrite_not`, `-op`/`--overwrite_prompt`, and `-opn`/`--overwrite_prompt_not` flags for the `dl` subcommand. 33 | 34 | ## Changed 35 | 36 | - Made the app log the `log path` even when loading, so that the user will know where to find the said file when it gets stuck while loading. 37 | - .AppImage so that you can run the cli by appending the `cli` subcommand to the command for running the said AppImage. For example, `./ura.AppImage cli [flags]`. 38 | 39 | ## Fixed 40 | 41 | - `overwrite` settings not being followed (i.e. `overwrite` set to False, yet the chapter that is already downloaded is being overwritten). 42 | - Once and for all, the fucking python imports, for fuck's sake. 43 | - Improved documentation! 44 | 45 | # 0 0 0 0 1 1 46 | 47 | ## Added 48 | 49 | - Dynamic version and copyright information 50 | 51 | ## Changed 52 | 53 | - Improved logging 54 | 55 | ## Fixed 56 | 57 | - Incorrect python library importing that causes the app to crash outright 58 | 59 | # 0 0 0 0 1 0 60 | 61 | YANKED! 62 | 63 | ## Added 64 | 65 | - Icon for .AppImage distribution of that app 66 | - Logging information to help debug the application 67 | - The app now reflects changes made on the configuration file on the app 68 | 69 | ## Changed 70 | 71 | - Improved loading of the app, so that when the loading page is removed, the app is totally usable 72 | - Uses parts of private project (`whinee/snippets.py`) for the configuration of the app, and others 73 | 74 | # 0 0 0 0 0 5 75 | 76 | ## Added 77 | 78 | - Loading screen for app initialization 79 | 80 | ## Fixed 81 | 82 | - AppImages to be marked as AppImages (means that the config now goes on the config folder instead of the same directory as the AppImage) 83 | 84 | # 0 0 0 0 0 4 85 | 86 | YANKED! 87 | 88 | ## Added 89 | 90 | - Initialization of configuration file 91 | 92 | # 0 0 0 0 0 3 93 | 94 | YANKED! 95 | 96 | ## Fixed 97 | 98 | - `vls` string on `ura/__init__.py` to `[0, 0, 0, 0, 0, 3]` 99 | 100 | # 0 0 0 0 0 2 101 | 102 | YANKED! 103 | 104 | ## Fixed 105 | 106 | - Unquoted `__version__` string on `ura/__init__.py` 107 | 108 | # 0 0 0 0 0 1 109 | 110 | ## Removed 111 | 112 | - Useless imports 113 | 114 | # 0 0 0 0 0 0 115 | 116 | YANKED! Initial release of the application 117 | -------------------------------------------------------------------------------- /dev/raw_docs/docs/0/0/config.mako: -------------------------------------------------------------------------------- 1 |

2 | Config 3 |

<% 4 | import yaml 5 | from os import path 6 | with open(path.join('dev/constants/version', '/'.join(cwd.split('/')[-2:]), 'config.yml')) as f: 7 | yml = yaml.safe_load(f.read()) 8 | 9 | md_op = "" 10 | for k, v in yml["config"].items(): 11 | md_op += f'\n\n### **{k}**: `{v["type"]}`' 12 | if v.get("req", False): 13 | md_op += '*' 14 | 15 | if de:=v.get("default", None): 16 | md_op += f'\n\nDefaults to {de}.' 17 | 18 | if desc:=v.get("desc", None): 19 | md_op += '\n\n' + desc 20 | %> 21 | <%text> 22 | ## **Configurations**${md_op} 23 | <%text> 24 | ## **Config File** 25 | 26 | ### **Config File Lookup Order of Precedence (CFLOP)** 27 | 28 | Hyaku is a cross-platform project, which means that it could be ran in different OS. 29 | There is however a lack of unity in the standardization on the location of config files in this OSes. 30 | And such, I have devised a precedence order for Hyaku's config file in different platforms. 31 | 32 | The following are the CFLOP for different OSes: 33 | 34 | ```mermaid 35 | flowchart TD 36 | A([CFLOP]) --> L[--config argument] 37 | L --> B{OS?} 38 | B --> |*nix| C[./ura.yml] 39 | subgraph
40 | C --> D{"XDG
CONFIG
HOME
(XCH)?"} 41 | D --> |true| E["${XCH}/ura/config.yml"] --> F 42 | D --> |false| F["~/.config/ura/config.yml"] 43 | F --> G["~/.ura"] 44 | end 45 | B --> |Windows| J[.\ura.yml] 46 | subgraph

47 | J --> K["${boot drive}:\\
Users\${username}\
AppData\Roaming\ura\
config.yml"] 48 | end 49 | ``` 50 | -------------------------------------------------------------------------------- /dev/raw_docs/docs/0/0/index.mako: -------------------------------------------------------------------------------- 1 |

2 | ${'/'.join(cwd.split('/')[:-2])} 3 |

4 | 5 | <%text> 6 | - [How to configure the program, and how it works](config.md) 7 | - [Structure of the program](Structure.md) 8 | - [Further documentation](api/index.md) 9 | -------------------------------------------------------------------------------- /dev/raw_docs/docs/0/0/structure.ymd: -------------------------------------------------------------------------------- 1 | --- 2 | title: ura's Structure 3 | --- 4 | 5 | ura is a very basic application, yet it grew to a large size. As a one-man army, it is necessary for me to write this, as to not get lost in this chaos that I have created. 6 | 7 | I, however, procrastinated in writing this, and thus, is completely empty at the moment. 8 | 9 | 10 | 11 | 22 | -------------------------------------------------------------------------------- /dev/raw_docs/faq.ymd: -------------------------------------------------------------------------------- 1 |

2 | FAQ 3 |

4 | 5 | ## **Is this application safe?** 6 | 7 |
8 | TL;DR: First of all, safe from what aspect, bruv? Considering that you are asking this, probably not. 9 | 10 |

Am I safe from authorities?

11 | 12 |
13 | TL;DR: No, what you are doing right now most probably is illegal. 14 | 15 | Really, you're asking me this? To be fair, it is a genuine concern. But like, assuming that you are 2-4 links deep on this website that only appeals to animanga pirates alike, you probably know what you are doing. Right? Right? 16 | 17 | Okay, right. This is an FAQ, and I have to answer it... Fine... Look, you're not, and you will never be. They are watching your every move. Read the legalese of the app from here Please be careful out there, kind stranger. I'm not (last line written by Github Copilot). 18 |
19 | 20 |

Is this application safe for my computer?

21 | 22 |
23 | TL;DR: Yes, but not really. Safe enough to put a 99.99% safety guarantee on it, air commercials of it, and not get sued on the grounds of false advertisement. 24 | 25 | No software is ever safe, and there will never be. Unless if we, for some mysterious and divine reason, gain the ability to prove if a program halts or not, which in this universe is impossible (relevant link: Halting problem). 26 | 27 | Enough of explaining the philosophical implications of this problematic question, and let us go to the real meat of the discussion. No, I can not assure you, as the developer of this application, that this application is safe. It is like asking if I poisoned your food; regardless of if I did it or not, I will dutifully deny the allegation, duh. Make of that what you will, but I am here to chase clout and make money out of it, not to compromise machines. 28 | 29 | Well, with all that said, I also made it for personal use. And for that, I have to make it at the very least usable to the extent that it would not compromise the host machine that it is running on. 30 | 31 | Don't trust me? The application is open-sourced. Every packaged application downloaded from the official site and Github repository is built from the same source as available on the official Github repository. If you know how to read the source code, you are free to do so, and inspect it. If you did do so, please hunt down some bugs for me. They haunt me at night, whenever I'm with my friends at the mall, just wherever I am. Please, I'm scared, I will very much appreciate it if you do. 32 | 33 | To end this answer, well... I mean, you could run the thing on a virus checker. Although, what might be an innocuous yet insecure system API call might be flagged as a suspicious activity. Not that I am aware of anything of that sort in my application, but I think that that will suffice as an example. 34 |
35 |
36 | 37 | ## **What are your intentions in making this application?** 38 | 39 |
40 | 41 | TL;DR: I've been commissioned for this project. Otherwise, it's a hobby of mine. It is not driven by any ill intentions. You asked me, trust me. 42 | 43 | I have been commissioned by @HappyPurple(Discord, Mistilteinn#4793), owner of Ultralight Manga Translation Group to make a downloader for a raws manga site provider called urasunday.com. 44 | 45 | My intentions however are still the same as it was months ago. However, I have a side goal in mind right now: to attain popularity in the animanga piracy scene, enough to get me enough freelancing work and earn money. 46 | 47 | Yes, that is it, really. I am in it for the money. Anyways, I would very much appreciate it if you could donate money or a little bit of your time to ths endeavour of mine, or commission me to do some work for you. 48 |
49 | 50 | ## **Who are you?** 51 | 52 |
53 | 54 | TL;DR: That's a creepy thing to ask dude, I'm a teenager. \s 55 | 56 | Hello, I am whi_ne, short for whitespace_negative. 17 at the time of writing. I am a python and a web developer, albeit shitty at both of them. I also do some freelance work. Nice to meet ya! 57 | 58 | Yes, I use an alias; personal branding is dead. I also want to stay anonymous. However, my pics on multiple guys' DMs suggests otherwise. And yes, please do not dig up dirt on me, I will let you know everything there is to know about me. 59 |
60 | -------------------------------------------------------------------------------- /dev/raw_docs/latest-bump.mako: -------------------------------------------------------------------------------- 1 | <% 2 | import re 3 | from os import path 4 | 5 | RE_H1 = r"# ([^\n]*)(\n[^#]+)(.*?)(?=\n#\s|$)" 6 | RE_H2 = r"## ([^\n]*)\s*(.*?)(?=\n##\s|$)" 7 | RE_LC = r"- (.*?)(?=- |$)" 8 | 9 | PR = ["alpha", "beta", "rc"] 10 | 11 | VERSIONS_NAME = [ 12 | "User", 13 | "Dev", 14 | "Minor", 15 | "Patch", 16 | "Pre-release identifier", 17 | "Pre-release version", 18 | ] 19 | 20 | def compare(x, y): 21 | for idx, i in enumerate(VERSIONS_NAME): 22 | if int(y[idx]) == (int(x[idx]) + 1): 23 | return i + " bump" 24 | 25 | return None 26 | 27 | def rv(vls: list[str | int]): 28 | pr = "" 29 | vls = [int(i) for i in vls] 30 | if vls[4] <= 2: 31 | pr = f'-{PR[vls[4]]}.{vls[5]}' 32 | return ".".join([str(i) for i in vls[0:4]]) + pr 33 | 34 | with open(path.join(cwd, "changelog.mmd"), "r") as f: 35 | CL = f.read() 36 | 37 | changes = {} 38 | md_op = "" 39 | comp = "" 40 | 41 | vbls = re.findall(RE_H1, CL, re.DOTALL) 42 | vb = vbls[0] 43 | ver, desc, tls = vb 44 | vls = ver.split(" ") 45 | anchor = ver.replace(" ", "-") 46 | desc = desc.strip() 47 | 48 | for tch in re.findall(RE_H2, tls, re.DOTALL): 49 | t, chls = tch 50 | changes[t] = ovt = [] 51 | for ch in re.findall(RE_LC, chls, re.DOTALL): 52 | ovt.append(ch) 53 | 54 | if len(vbls) != 1: 55 | comp = f"{compare(vbls[1][0].split(), vls)}. " 56 | md_op += f'## {rv(vls)}' 57 | if (desc != "") or (comp != ""): 58 | md_op += f'\n\n{comp}{desc}' 59 | else: 60 | md_op += '' 61 | for t, chls in changes.items(): 62 | href = t.lower() 63 | md_op += f'\n\n### {t}\n' 64 | for ch in chls: 65 | md_op += f'\n- {ch}' 66 | %> 67 |

68 | Latest Version Bump 69 |

70 | 71 | ${md_op} 72 | -------------------------------------------------------------------------------- /dev/raw_docs/latest-commit.mako: -------------------------------------------------------------------------------- 1 | <% 2 | import re 3 | from os import path 4 | 5 | RE_SUM = "(## \*\*Summary\*\*)\s*(.*?)(?=\n##\s|$)" 6 | RE_H3 = r"(### [^\n]*)\s*(?:)*(.*?)(?=\n###\s|$)" 7 | 8 | changes = "" 9 | 10 | with open(path.join(cwd, "latest-commit.mmd"), "r") as f: 11 | TXT = f.read() 12 | 13 | x, y = re.search(RE_SUM, TXT, re.DOTALL).span() 14 | sum = f"{TXT[x:y]}\n".strip() 15 | 16 | for tc in re.findall(RE_H3, TXT, re.DOTALL): 17 | t, c = tc 18 | c = c.strip() 19 | if c != "": 20 | changes += f"{t}\n\n{c}\n\n" 21 | 22 | changes = changes.strip() + '\n' 23 | %> 24 |

25 | Latest Commit 26 |

27 | 28 | ${sum} 29 | <%text> 30 | ## **Changes** 31 | 32 | ${changes} -------------------------------------------------------------------------------- /dev/raw_docs/latest-commit.mmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: Latest Commit 3 | --- 4 | 5 | ## **Summary** 6 | 7 | 8 | Yet 'nother fucking oopsies... 9 | 10 | ## **Changes** 11 | 12 | 28 | 29 | ### **Added** 30 | 31 | 34 | 35 | ### **Changed** 36 | 37 | 40 | 41 | ### **Deprecated** 42 | 43 | 46 | 47 | ### **Removed** 48 | 49 | 52 | 53 | ### **Fixed** 54 | 55 | 58 | 59 | - `dev/scripts/py/main.py`'s `push` function to call `docs` function. GAAAAAAAAAAAAHH! 60 | 61 | ### **Security** 62 | 63 | -------------------------------------------------------------------------------- /dev/raw_docs/latest-release-notes.mako: -------------------------------------------------------------------------------- 1 | <% 2 | import re 3 | from os import path 4 | 5 | RE_H1 = r"# ([^\n]*)(\n[^#]+)(.*?)(?=\n#\s|$)" 6 | RE_H2 = r"## ([^\n]*)\s*(.*?)(?=\n##\s|$)" 7 | RE_LC = r"- (.*?)(?=- |$)" 8 | 9 | PR = ["alpha", "beta", "rc"] 10 | 11 | VERSIONS_NAME = [ 12 | "User", 13 | "Dev", 14 | "Minor", 15 | "Patch", 16 | "Pre-release identifier", 17 | "Pre-release version", 18 | ] 19 | 20 | def compare(x, y): 21 | for idx, i in enumerate(VERSIONS_NAME): 22 | if int(y[idx]) == (int(x[idx]) + 1): 23 | return i + " bump" 24 | 25 | return None 26 | 27 | def rv(vls: list[str | int]): 28 | pr = "" 29 | vls = [int(i) for i in vls] 30 | if vls[4] <= 2: 31 | pr = f'-{PR[vls[4]]}.{vls[5]}' 32 | return ".".join([str(i) for i in vls[0:4]]) + pr 33 | 34 | with open(path.join(cwd, "changelog.mmd"), "r") as f: 35 | CL = f.read() 36 | 37 | changes = {} 38 | md_op = "" 39 | comp = "" 40 | 41 | vbls = re.findall(RE_H1, CL, re.DOTALL) 42 | vb = vbls[0] 43 | ver, desc, tls = vb 44 | vls = ver.split(" ") 45 | ver_str = rv(vls) 46 | anchor = ver.replace(" ", "-") 47 | desc = desc.strip() 48 | 49 | for tch in re.findall(RE_H2, tls, re.DOTALL): 50 | t, chls = tch 51 | changes[t] = ovt = [] 52 | for ch in re.findall(RE_LC, chls, re.DOTALL): 53 | ovt.append(ch) 54 | 55 | if len(vbls) != 1: 56 | comp = f"{compare(vbls[1][0].split(), vls)}. " 57 | 58 | if (desc != "") or (comp != ""): 59 | md_op += f'## **Description**\n\n{comp}{desc}' 60 | else: 61 | md_op += '' 62 | for t, chls in changes.items(): 63 | href = f'{anchor}-{t.lower()}' 64 | md_op += f'\n\n## **{t}**\n' 65 | for ch in chls: 66 | md_op += f'\n- {ch}' 67 | %>

68 | ${ver_str} 69 |

70 | 71 | ${md_op} 72 | -------------------------------------------------------------------------------- /dev/raw_docs/license.ymd: -------------------------------------------------------------------------------- 1 | --- 2 | title: MIT LICENSE 3 | link: https://choosealicense.com/licenses/mit/ 4 | --- 5 | 6 | ${cholder} 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | -------------------------------------------------------------------------------- /dev/raw_docs/notes-to-self.ymd: -------------------------------------------------------------------------------- 1 | --- 2 | title: Notes to Self 3 | --- 4 | 5 | Look, whi_ne, I have written this for you. 6 | 7 | Please, do I humbly plead you, do not ever forgot to read this before pushing changes to Github. 8 | 9 | ## Versioning System 10 | 11 | Look, you have made your own versioning system based off semver 2.0.0. Use it properly. 12 | 13 | Given a version number `user.dev.minor.patch`, increment the: 14 | 15 | - `user` version when you make any changes to the user interface/experience. This does not include improvements on loading times, despite being well within the user experience umbrella. 16 | - `dev` version when you make incompatible API changes, 17 | - `minor` version when you add functionality in a backwards compatible manner, and 18 | - `patch` version when you make backwards compatible bug fixes. 19 | 20 | If in doubt, please **DO** visit [semver.org](https://semver.org/). 21 | 22 | ### Version Bump Guides 23 | 24 | - **ANY** change in the user interface/experience SHALL induce a `user` version bump. 25 | - **ANY** change in the schema shall induce a `dev` version bump. 26 | - **ANY** change in the documentation SHALL NOT induce any version bump. 27 | 28 | ```mermaid 29 | flowchart TD 30 | VB([Version Bump]) 31 | VB --> |"prerelease identifier (pi)"| e_pr{existing `pi`} 32 | e_pr --> |none| bprv("bump prerelease version (pv)") 33 | bprv --> ba(bump `pi` to `alpha`) 34 | ba --> bp([bump `patch`]) 35 | e_pr --> |alpha| bb(bump to `beta`) 36 | bb --> r0([reset version/s below it to `0` or `none`]) 37 | e_pr --> |beta| br(bump to `rc`) --> r0 38 | e_pr --> |rc| rn(reset to `none`) --> r0 39 | VB --> |others| bsv(bump specified version) --> r0 40 | ``` 41 | 42 | ## Changelog 43 | 44 | As used in the changelog, the following types of changes shall have the following implications, of which, their allowed version bumps should be everything, unless explicably stated otherwise: 45 | 46 | - `Added` for new features. 47 | - user 48 | - dev 49 | - minor 50 | - `Changed` for changes in existing functionality. 51 | - user 52 | - dev 53 | - `Deprecated` for soon-to-be removed features. 54 | - patch 55 | - `Removed` for now removed features. 56 | - user 57 | - dev 58 | - `Fixed` for any bug fixes. 59 | - `Security` in case of vulnerabilities. 60 | 61 | Mind the human as you do with the robot. Format the changelog properly. Example format: 62 | 63 | ```md 64 | ## 69.4.2.0 (minor bump) 65 | 66 | Sprinkle a description here. 67 | 68 | ### Added 69 | 70 | - I added a cool feature. 71 | 72 | ### Deprecated 73 | 74 | - This feature will be depracated 'cuz I can't maintain it anymore. 75 | 76 | ### Security 77 | 78 | - Fixed stuff where the anilist token is leaked to everyone using this app. 79 | ``` 80 | 81 | ## Documentation 82 | 83 | The documentation system is a custom solution. 84 | 85 | If the documentation generator fails, check the traceback. It is commonly due to errors in the code and not the generator itself. 86 | 87 | Do not blame the shitty generator you wrote. You might just have written a faulty code. 88 | -------------------------------------------------------------------------------- /dev/raw_docs/todo.yml: -------------------------------------------------------------------------------- 1 | 0: 2 | 0: 3 | - Configeurable color theme 4 | - Responsive TUI 5 | 1: 6 | 1: 7 | 0: 8 | 1: 9 | 2: 10 | 0: 11 | - global --config option 12 | 1: 13 | 3: 14 | 0: 15 | 1: 16 | 4: 17 | 0: 18 | - Auto-update 19 | 1: 20 | - |- 21 | Detect the windows boot drive, for ura to be installed at. 22 | Currently, ura will be installed at Drive C:. 23 | 5: 24 | 0: 25 | - Update script 26 | 1: 27 | - GUI -------------------------------------------------------------------------------- /dev/scripts/ps1/fmt.ps1: -------------------------------------------------------------------------------- 1 | function tmp{python -m black -q .};t "Python Files Formatted" "Formatting Python Files Failed." tmp 2 | function tmp{python -m isort -q --gitignore .};t "Sorting Python Imports" "Sorting Python Imports Failed." tmp -------------------------------------------------------------------------------- /dev/scripts/ps1/req.ps1: -------------------------------------------------------------------------------- 1 | function main 2 | { 3 | pip install --upgrade pip 4 | foreach ( $i in (python -m niet development.venv.requirements dev\vars.yml) ) { 5 | python -m pip install -r $(python -m niet requirements.$i dev\vars.yml) 6 | } 7 | } 8 | t "Installing Requirements" "Installing Requirements Failed." main -------------------------------------------------------------------------------- /dev/scripts/ps1/start.ps1: -------------------------------------------------------------------------------- 1 | $env:NODE_ENV = "development" 2 | electron --trace-warnings . -------------------------------------------------------------------------------- /dev/scripts/py/cfg.py: -------------------------------------------------------------------------------- 1 | import json 2 | from typing import Any 3 | 4 | import msgpack 5 | import yaml 6 | 7 | from .cd import CustomDict 8 | from .exceptions import c_exc_str 9 | 10 | TYPES = { 11 | "r": [ 12 | [["yaml", "yml"], ["r", lambda x: yaml.safe_load(x)]], 13 | [["mp"], ["rb", lambda x: msgpack.unpackb(x, raw=False, use_list=True)]], 14 | [["json"], ["r", lambda x: json.loads(x)]], 15 | ], 16 | "w": [ 17 | [["yaml", "yml"], ["w", lambda x: yaml.dump(x, indent=2)]], 18 | [["mp"], ["wb", lambda x: msgpack.packb(x, use_bin_type=True)]], 19 | [["json"], ["w", lambda x: json.dumps(x, indent=4, sort_keys=False)]], 20 | ], 21 | } 22 | 23 | 24 | def str_presenter(dumper, data): 25 | if len(data.splitlines()) > 1: # check for multiline string 26 | return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|") 27 | return dumper.represent_scalar("tag:yaml.org,2002:str", data) 28 | 29 | 30 | yaml.add_representer(str, str_presenter) 31 | 32 | 33 | @c_exc_str 34 | class ExtensionNotSupported(NotImplementedError): 35 | def __init__(self, ext: str) -> None: 36 | self.message = f"Extension `{ext}` is not supported." 37 | super().__init__(self.message) 38 | 39 | 40 | def pcfg(d: str, type: str) -> CustomDict: 41 | """Parse the given string as the given type. 42 | 43 | Args: 44 | d (str): String to parse. 45 | type (str): Type to parse the string as. 46 | 47 | Returns: 48 | CustomDict: The parsed string. 49 | """ 50 | 51 | for k, v in TYPES["r"]: 52 | if type in k: 53 | return CustomDict(v[1](d)) 54 | raise ExtensionNotSupported(type) 55 | 56 | 57 | def dcfg(value: dict, ext: str) -> str: 58 | """Dump the given value to a string with the given extension. 59 | 60 | Args: 61 | value (dict): Value to dump to a string. 62 | ext (str): Extension to dump the value to. 63 | 64 | Returns: 65 | str: The dumped value. 66 | """ 67 | 68 | for k, v in TYPES["w"]: 69 | if ext in k: 70 | return v[1](value) 71 | raise ExtensionNotSupported(ext) 72 | 73 | 74 | def rcfg(file: str) -> CustomDict: 75 | """Read the contents of a file with the given file name. 76 | 77 | Args: 78 | file (str): File name of the file to read the contents of. 79 | 80 | Returns: 81 | CustomDict: The contents of the file. 82 | """ 83 | 84 | ext = file.split(".")[-1] 85 | for k, v in TYPES["r"]: 86 | if ext in k: 87 | with open(file, v[0]) as f: 88 | return CustomDict(v[1](f.read())) 89 | raise ExtensionNotSupported(ext) 90 | 91 | 92 | def wcfg(file: str, value: dict[Any, Any] | list[Any]) -> None: 93 | """Write the given value to a file with the given file name. 94 | 95 | Args: 96 | file (str): File name of the file to write the value to. 97 | value (dict[Any, Any] | list[Any]): Value to write to the file. 98 | """ 99 | ext = file.split(".")[-1] 100 | for k, v in TYPES["w"]: 101 | if ext in k: 102 | with open(file, v[0]) as f: 103 | if value.__class__.__mro__[-2] is dict: 104 | value = dict(value) 105 | f.write(v[1](value)) 106 | -------------------------------------------------------------------------------- /dev/scripts/py/eb.py: -------------------------------------------------------------------------------- 1 | from .cfg import rcfg, wcfg 2 | from .utils import ivnd 3 | 4 | 5 | def merge_dict(dict1, dict2): 6 | for key, val in dict1.items(): 7 | if isinstance(val, dict): 8 | if key in dict2 and type(dict2[key] == dict): 9 | merge_dict(dict1[key], dict2[key]) 10 | elif key in dict2: 11 | dict1[key] = dict2[key] 12 | 13 | for key, val in dict2.items(): 14 | if not key in dict1: 15 | dict1[key] = val 16 | 17 | return dict1 18 | 19 | 20 | def main(fmt: str, op: str, override: dict = None): 21 | override = ivnd(override, {}) 22 | cfg = rcfg("dev/vars.yml")["build"] 23 | wcfg(op, dict(merge_dict(merge_dict(cfg["base"], cfg[fmt]), override))) 24 | -------------------------------------------------------------------------------- /dev/scripts/py/exceptions.py: -------------------------------------------------------------------------------- 1 | def c_exc_str(cls: Exception) -> Exception: 2 | """Decorator to add the __str__ method to an exception. 3 | 4 | Args: 5 | cls (BaseException): The exception to add the __str__ method to. 6 | 7 | Returns: 8 | BaseException: The exception to raise. 9 | """ 10 | cls.__str__ = lambda self: self.message 11 | return cls 12 | 13 | 14 | def c_exc(cls: Exception | object) -> Exception: 15 | """Decorator to raise a custom exception. 16 | 17 | This function gives the class an __init__ function that raises the exception. 18 | If the class does not inherit from any Exception, it will be automatically inherit from Exception. 19 | This function also wraps the Exception with `c_exc_str` method, for adding the `__str__` method. 20 | 21 | Args: 22 | cls (BaseException | Object): The exception to modify. 23 | 24 | Returns: 25 | BaseException: The exception to raise. 26 | """ 27 | if cls.__mro__[-2] is BaseException: 28 | exc = cls.__mro__[1] 29 | else: 30 | exc = Exception 31 | 32 | def __init__(self, message: str) -> None: 33 | self.message = message 34 | exc.__init__(self.message) 35 | 36 | cls.__init__ = __init__ 37 | return c_exc_str(cls) 38 | -------------------------------------------------------------------------------- /dev/scripts/py/inst_mods/whine_md_fmt/main.py: -------------------------------------------------------------------------------- 1 | from markdown_it import MarkdownIt 2 | from mdformat.renderer import RenderContext, RenderTreeNode 3 | from mdformat.renderer._util import get_list_marker_type, is_tight_list 4 | 5 | 6 | def update_mdit(mdit: MarkdownIt) -> None: 7 | pass 8 | 9 | 10 | def bullet_list(node: RenderTreeNode, context: RenderContext) -> str: 11 | marker_type = get_list_marker_type(node) 12 | first_line_indent = " " 13 | indent = " " * len(marker_type + first_line_indent) 14 | block_separator = "\n" if is_tight_list(node) else "\n\n" 15 | 16 | with context.indented(len(indent)): 17 | text = "" 18 | for child_idx, child in enumerate(node.children): 19 | list_item = child.render(context) 20 | formatted_lines = [] 21 | line_iterator = iter(list_item.split("\n")) 22 | first_line = next(line_iterator) 23 | formatted_lines.append( 24 | f"{marker_type}{first_line_indent}{first_line}" 25 | if first_line 26 | else marker_type 27 | ) 28 | for line in line_iterator: 29 | formatted_lines.append(f"{indent}{line}" if line else "") 30 | 31 | text += "\n".join(formatted_lines) 32 | if child_idx != len(node.children) - 1: 33 | text += block_separator 34 | 35 | return text 36 | 37 | 38 | RENDERERS = {"bullet_list": bullet_list} 39 | -------------------------------------------------------------------------------- /dev/scripts/py/inst_mods/whine_md_fmt/setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | setuptools.setup( 4 | name="whine_md_fmt", 5 | entry_points={"mdformat.parser_extension": ["whine_md_fmt = main"]}, 6 | ) 7 | -------------------------------------------------------------------------------- /dev/scripts/py/md_vars.py: -------------------------------------------------------------------------------- 1 | import base64 2 | from datetime import date 3 | 4 | from .cfg import rcfg 5 | 6 | # Constants 7 | ICONS = ["issues", "forks", "stars", "contributors", "license", "code"] 8 | LANGS = ["python", "html", "yaml"] 9 | OS = ["linux", "win"] 10 | 11 | OP_CHOLDER_TPL = """by [{cholder}, Github account {user} owner, {year}] as part of project 13 | {project}""" 14 | 15 | M_CHOLDER_TPL = """Copyright for portions of project {project} are held {mc}. 17 | 18 | All other copyright for project {project} are held by [Github 20 | Account {user} Owner, {year}].""" 21 | 22 | S_CHOLDER_TPL = """Copyright (c) {year} Github Account {user} Owner""" 24 | 25 | # Derived Constants 26 | BYML = rcfg(".github/workflows/build.yml") 27 | VYML = rcfg("version.yml") 28 | YML = rcfg("dev/vars.yml") 29 | 30 | JOBS = BYML["jobs"] 31 | VLS = VYML["ls"] 32 | LICENSE = YML["license"] 33 | MD_VARS = YML["md_vars"] 34 | 35 | GLOBAL = MD_VARS["global"] 36 | 37 | PN = GLOBAL["project_name"] 38 | ORG = GLOBAL["organization"] 39 | USER = GLOBAL["user"] 40 | 41 | # Initialize 42 | copyright = [] 43 | 44 | # Functions 45 | def b64(name: str): 46 | with open(f"./docs/assets/images/icons/{name}", "rb") as f: 47 | return base64.b64encode(f.read()).decode("utf-8") 48 | 49 | 50 | if LICENSE["cholder"]: 51 | for c, mp in LICENSE["cholder"].items(): 52 | user = mp["user"] 53 | for org, projects in mp["projects"].items(): 54 | for project, pm in projects.items(): 55 | copyright.append( 56 | OP_CHOLDER_TPL.format( 57 | cholder=c, 58 | org=org, 59 | project=project, 60 | user=user, 61 | year=pm["year"], 62 | ) 63 | ) 64 | if len(copyright) > 1: 65 | copyright[-2] += f", and {copyright[-1]}" 66 | del copyright[-1] 67 | cholder = M_CHOLDER_TPL.format( 68 | mc=", ".join(copyright), org=ORG, project=PN, user=USER, year=LICENSE["year"] 69 | ) 70 | else: 71 | cholder = S_CHOLDER_TPL.format(user=USER, year=LICENSE["year"]) 72 | 73 | 74 | global_append = { 75 | "year": str(date.today().year), 76 | "cholder": cholder, 77 | } 78 | 79 | for i in OS: 80 | for j in JOBS[i]["steps"]: 81 | if j["name"] == "Build": 82 | global_append[f"build_{i}"] = j["run"] 83 | pass 84 | 85 | for idx, i in enumerate(["user", "dev", "minor", "patch", "pri", "prv"]): 86 | global_append[f"ver_{i}"] = str(VLS[idx]) 87 | 88 | for i in ICONS: 89 | global_append[f"{i}_b64"] = b64(f"{i}.png") 90 | 91 | 92 | MD_VARS["global"] = { 93 | **GLOBAL, 94 | **global_append, 95 | } 96 | 97 | RMDV = {"rules": YML["rules"], "md_vars": MD_VARS} 98 | -------------------------------------------------------------------------------- /dev/scripts/py/rn_md.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | with open("docs/latest-release-notes.md", "r") as f: 4 | op = re.sub(r"

.+<\/h1>", "", f.read(), 0, re.DOTALL).strip() 5 | with open(".md", "w") as f: 6 | f.write(op) 7 | -------------------------------------------------------------------------------- /dev/scripts/py/schema.py: -------------------------------------------------------------------------------- 1 | import re 2 | from os import path 3 | from os.path import abspath as ap 4 | 5 | from .cfg import wcfg 6 | from .exceptions import c_exc_str 7 | from .utils import dnn 8 | 9 | # Constants 10 | TD = { 11 | "str": "", 12 | "int": -1, 13 | "float": -1.0, 14 | "bool": False, 15 | "list": [], 16 | "dict": {}, 17 | } 18 | 19 | # Derived Constants 20 | UT_RE = re.compile(r"(\w+)(?:\[)?") 21 | UT = lambda x: UT_RE.match(x).group(1) 22 | 23 | 24 | @c_exc_str 25 | class VersionNotFound(ValueError): 26 | def __init__(self, name: str, v: str): 27 | self.name = name 28 | self.v = v 29 | self.msg = f"Version {v} not found in {name}" 30 | 31 | 32 | def __init__(self, v: str): 33 | try: 34 | self.u, self.d, *_ = v.split(".") 35 | except AttributeError: 36 | raise VersionNotFound(self.__name__, v) 37 | 38 | 39 | def __call__(self, *args, **kwargs): 40 | return getattr(getattr(self, f"u{self.u}"), f"d{self.d}")(*args, **kwargs) 41 | 42 | 43 | def c_schema(cls: object) -> object: 44 | cls.__init__ = __init__ 45 | cls.__call__ = __call__ 46 | return cls 47 | 48 | 49 | @c_schema 50 | class Schema: 51 | class u1: 52 | def d0(yml: dict[str, dict[str, str | int | float]]): 53 | content = "" 54 | for k, v in yml.items(): 55 | content += f"## **{k}**" 56 | for vk, vv in v.items(): 57 | content += f'\n\n- ### **{vk}**\n\n\t`{vv["type"]}`' 58 | if de := vv.get("default", None): 59 | content += f", defaults to `{de}`" 60 | if abbr := vv.get("abbr", None): 61 | content += f"\n\n\t*{abbr}*" 62 | content += "\n\n\t{}".format(vv["desc"].replace("\n", "\n\t")) 63 | return content.replace("\t", " ") 64 | 65 | 66 | @c_schema 67 | class Config: 68 | class u1: 69 | def d0(yml: dict[str, dict[str, str | int | float]]): 70 | op = {} 71 | for k, v in yml.items(): 72 | op[k] = v.get("default", TD.get(UT(v["type"]), None)) 73 | wcfg(path.join(dnn(ap(__file__), 4), "ura/src/cf_tpl.mp"), op) 74 | -------------------------------------------------------------------------------- /dev/scripts/py/scripts.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | import re 3 | 4 | from .cfg import dcfg, pcfg, rcfg 5 | from .utils import inmd 6 | 7 | RE_MX = r"(?<=\{matrix.)[a-zA-Z0-9-_]+?(?=\})" 8 | 9 | 10 | def cd(*k: list[str]): 11 | op = [] 12 | dls = [MATRIX[i] for i in k] 13 | for i in itertools.product(*dls): 14 | op.append(dict(zip(k, i))) 15 | return op 16 | 17 | 18 | def repl(key: str, fn: str, contents: str): 19 | s, c = fn, contents 20 | lv = SCRIPTS.dir(f"variables/local/{key}", {}) 21 | rmvg = {**GLOBAL, **lv} 22 | 23 | for k, v in rmvg.items(): 24 | c = c.replace(f"${{{k}}}", v) 25 | s = s.replace(f"${{{k}}}", v) 26 | 27 | return s, c 28 | 29 | 30 | def mr(k: str, v: dict[str, str]): 31 | s, c = repl(k, v["path"], v["contents"]) 32 | if mx_match := re.findall(RE_MX, s): 33 | op = [] 34 | for i in cd(*mx_match): 35 | _s = s 36 | _c = c 37 | for k, v in i.items(): 38 | _s = _s.replace(f"${{matrix.{k}}}", v) 39 | _c = _c.replace(f"${{matrix.{k}}}", v) 40 | op.append([_s, _c]) 41 | return op 42 | else: 43 | return [[s, c]] 44 | 45 | 46 | def main(): 47 | global GLOBAL, MATRIX, VLS, VYML, YML, SCRIPTS 48 | SCRIPTS = rcfg("dev/constants/scripts.yml") 49 | MD_VARS = rcfg("dev/vars.yml")["md_vars"] 50 | VER = rcfg("version.yml") 51 | 52 | MATRIX = {} 53 | for k, v in SCRIPTS["matrix"].items(): 54 | MATRIX[k] = [str(i) for i in v] 55 | 56 | with open("requirements.txt", "r") as f: 57 | REQ = f.read().split("\n") 58 | 59 | PG = { 60 | "req": [i for i in REQ if i], 61 | "ver": VER["str"], 62 | "hver": VER["sv"], 63 | "prerel": not (VER["ls"][-2] == 3), 64 | **{"ver_" + k: v for k, v in zip(["u", "d", "m", "p", "pi", "pv"], VER["ls"])}, 65 | } 66 | GLOBAL = {} 67 | for k, v in dict(MD_VARS["global"], **SCRIPTS["variables"]["global"], **PG).items(): 68 | GLOBAL[k] = str(v) 69 | 70 | PL = { 71 | "req": [i for i in REQ if i], 72 | } 73 | LOCAL = {} 74 | for k, v in dict(MD_VARS["local"], **SCRIPTS["variables"]["local"], **PL).items(): 75 | LOCAL[k] = str(v) 76 | 77 | for k, v in SCRIPTS["scripts"].items(): 78 | for p, c in mr(k, v): 79 | with open(inmd(p), "w") as f: 80 | if og_ext := v.get("og_ext"): 81 | if ext := v.get("ext"): 82 | c = dcfg(pcfg(c, og_ext), ext) 83 | f.write(c) 84 | -------------------------------------------------------------------------------- /dev/scripts/py/utils.py: -------------------------------------------------------------------------------- 1 | import shlex 2 | from os import makedirs, path 3 | from subprocess import call 4 | from typing import Any 5 | 6 | # Constants 7 | 8 | PR = ["alpha", "beta", "rc"] 9 | 10 | # Functions 11 | def inmd(p: str, ls: list[str] = None): 12 | """ 13 | "If Not `path.isdir`, Make Directories" 14 | 15 | Args: 16 | p (str): [description] 17 | """ 18 | 19 | pd = path.dirname(p) 20 | if (pd) and (not path.isdir(pd)): 21 | makedirs(pd) 22 | if ls: 23 | ls.append(pd) 24 | return p 25 | 26 | 27 | def ivnd(var: Any, de: Any) -> Any: 28 | """If Var is None, return Default else var. 29 | 30 | Args: 31 | var (Any): Variable to check if it is None. 32 | de (Any): Default value to return if var is None. 33 | 34 | Returns: 35 | Any: var if var is not None else de. 36 | """ 37 | if var is None: 38 | return de 39 | return var 40 | 41 | 42 | def repl(s: str, repl_dict: dict[str, list[str]]) -> str: 43 | op = s 44 | for k, v in repl_dict.items(): 45 | for i in v: 46 | op = op.replace(i, k) 47 | return op 48 | 49 | 50 | def dnn(fn: str, n: str) -> str: 51 | op = fn 52 | for _ in range(n): 53 | op = path.dirname(op) 54 | return op 55 | 56 | 57 | def run(s: str): 58 | call(shlex.split(s)) 59 | -------------------------------------------------------------------------------- /dev/scripts/sh/source.sh: -------------------------------------------------------------------------------- 1 | # shellcheck disable=SC1087,SC1091,SC2025,SC2045,SC2059,SC2119,SC2120,SC2162,SC2148,SC2154,SC2155,SC2195 2 | 3 | # Source 4 | . "$XDG_CONFIG_HOME"/bash/source.sh 5 | 6 | # commands 7 | 8 | fmt() { ( 9 | t " Python Imports Sorted" "Sorting Python Imports Failed." isort -q --gitignore . & 10 | t " Markdown Formatted" "Formatting Markdown Failed." mdformat docs & 11 | t "Python Files Formatted" "Formatting Python Files Failed." black -q . & 12 | wait 13 | ); } 14 | 15 | req() { 16 | pip install --upgrade pip niet 17 | for i in $( 18 | for j in $(niet development.venv.requirements dev/vars.yml); do 19 | niet requirements."$j" dev/vars.yml 20 | done 21 | ); do 22 | python -m pip install -r "$i" 23 | done 24 | for i in $(ls -d dev/scripts/py/inst_mods/*/); do 25 | case $i in 26 | *"__pycache__"*) ;; 27 | *) 28 | pip install -e "${i%%/}" 29 | ;; 30 | esac 31 | done 32 | } 33 | 34 | tb() { 35 | local tmp 36 | t "Generate Scripts" "Failed generating scripts." menu gs && 37 | tmp="$(niet "jobs.linux.steps[?name=='Build'].run" .github/workflows/build.yml)" && 38 | python -c "import re;print(re.sub('NODE_ENV=production','NODE_ENV=development','''$tmp''', 0, re.MULTILINE))" | sh 39 | } 40 | 41 | test() { 42 | python <"dev/scripts/py/test/$1.py" 43 | } 44 | 45 | # main 46 | 47 | if type "$1" >/dev/null 2>&1; then 48 | cmd=$1 49 | shift 50 | "$cmd" "$@" 51 | else 52 | echo "menu: $1 is not in the menu." 53 | fi 54 | -------------------------------------------------------------------------------- /dev/site/_meta.yml: -------------------------------------------------------------------------------- 1 | generated: 2 | docs: 3 | files: 4 | - docs/notes to self.md 5 | - docs/docs/0/0/setup.md 6 | - docs/docs/0/0/config.md 7 | - docs/README.md 8 | - docs/notes.md 9 | - docs/docs/0/0/structure.md 10 | - docs/license.md 11 | folders: [] 12 | mako: 13 | files: 14 | - docs/docs/0/0/index.md 15 | - docs/changelog.md 16 | folders: [] 17 | pdoc: 18 | files: 19 | - docs/docs/0/0/api/base.md 20 | - docs/docs/0/0/api/index.md 21 | - docs/docs/0/0/api/style.md 22 | - docs/docs/0/0/api/init.md 23 | - docs/docs/0/0/api/settings.md 24 | - docs/docs/0/0/api/globals.md 25 | - docs/docs/0/0/api/utils.md 26 | - docs/docs/0/0/api/main.md 27 | - docs/docs/0/0/api/cli.md 28 | - docs/docs/0/0/api/download.md 29 | folders: [] 30 | -------------------------------------------------------------------------------- /dev/site/assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/assets/images/favicon.png -------------------------------------------------------------------------------- /dev/site/assets/images/icons/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/assets/images/icons/code.png -------------------------------------------------------------------------------- /dev/site/assets/images/icons/contributors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/assets/images/icons/contributors.png -------------------------------------------------------------------------------- /dev/site/assets/images/icons/discord.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/assets/images/icons/discord.png -------------------------------------------------------------------------------- /dev/site/assets/images/icons/dl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/assets/images/icons/dl.png -------------------------------------------------------------------------------- /dev/site/assets/images/icons/forks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/assets/images/icons/forks.png -------------------------------------------------------------------------------- /dev/site/assets/images/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/assets/images/icons/icon.png -------------------------------------------------------------------------------- /dev/site/assets/images/icons/issues.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/assets/images/icons/issues.png -------------------------------------------------------------------------------- /dev/site/assets/images/icons/license.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/assets/images/icons/license.png -------------------------------------------------------------------------------- /dev/site/assets/images/icons/logo-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/assets/images/icons/logo-black.png -------------------------------------------------------------------------------- /dev/site/assets/images/icons/logo-black.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/assets/images/icons/logo-black.xcf -------------------------------------------------------------------------------- /dev/site/assets/images/icons/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/assets/images/icons/logo.png -------------------------------------------------------------------------------- /dev/site/assets/images/icons/logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/assets/images/icons/logo.xcf -------------------------------------------------------------------------------- /dev/site/assets/images/icons/read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/assets/images/icons/read.png -------------------------------------------------------------------------------- /dev/site/assets/images/icons/stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/assets/images/icons/stars.png -------------------------------------------------------------------------------- /dev/site/assets/javascripts/lunr/min/lunr.da.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Danish` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.da=function(){this.pipeline.reset(),this.pipeline.add(e.da.trimmer,e.da.stopWordFilter,e.da.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.da.stemmer))},e.da.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.da.trimmer=e.trimmerSupport.generateTrimmer(e.da.wordCharacters),e.Pipeline.registerFunction(e.da.trimmer,"trimmer-da"),e.da.stemmer=function(){var r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){function e(){var e,r=f.cursor+3;if(d=f.limit,0<=r&&r<=f.limit){for(a=r;;){if(e=f.cursor,f.in_grouping(w,97,248)){f.cursor=e;break}if(f.cursor=e,e>=f.limit)return;f.cursor++}for(;!f.out_grouping(w,97,248);){if(f.cursor>=f.limit)return;f.cursor++}d=f.cursor,d=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(c,32),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del();break;case 2:f.in_grouping_b(p,97,229)&&f.slice_del()}}function t(){var e,r=f.limit-f.cursor;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.find_among_b(l,4)?(f.bra=f.cursor,f.limit_backward=e,f.cursor=f.limit-r,f.cursor>f.limit_backward&&(f.cursor--,f.bra=f.cursor,f.slice_del())):f.limit_backward=e)}function s(){var e,r,i,n=f.limit-f.cursor;if(f.ket=f.cursor,f.eq_s_b(2,"st")&&(f.bra=f.cursor,f.eq_s_b(2,"ig")&&f.slice_del()),f.cursor=f.limit-n,f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(m,5),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del(),i=f.limit-f.cursor,t(),f.cursor=f.limit-i;break;case 2:f.slice_from("løs")}}function o(){var e;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.out_grouping_b(w,97,248)?(f.bra=f.cursor,u=f.slice_to(u),f.limit_backward=e,f.eq_v_b(u)&&f.slice_del()):f.limit_backward=e)}var a,d,u,c=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],l=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],w=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],p=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],f=new i;this.setCurrent=function(e){f.setCurrent(e)},this.getCurrent=function(){return f.getCurrent()},this.stem=function(){var r=f.cursor;return e(),f.limit_backward=r,f.cursor=f.limit,n(),f.cursor=f.limit,t(),f.cursor=f.limit,s(),f.cursor=f.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}}); -------------------------------------------------------------------------------- /dev/site/assets/javascripts/lunr/min/lunr.hi.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hi=function(){this.pipeline.reset(),this.pipeline.add(e.hi.trimmer,e.hi.stopWordFilter,e.hi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hi.stemmer))},e.hi.wordCharacters="ऀ-ःऄ-एऐ-टठ-यर-िी-ॏॐ-य़ॠ-९॰-ॿa-zA-Za-zA-Z0-90-9",e.hi.trimmer=e.trimmerSupport.generateTrimmer(e.hi.wordCharacters),e.Pipeline.registerFunction(e.hi.trimmer,"trimmer-hi"),e.hi.stopWordFilter=e.generateStopWordFilter("अत अपना अपनी अपने अभी अंदर आदि आप इत्यादि इन इनका इन्हीं इन्हें इन्हों इस इसका इसकी इसके इसमें इसी इसे उन उनका उनकी उनके उनको उन्हीं उन्हें उन्हों उस उसके उसी उसे एक एवं एस ऐसे और कई कर करता करते करना करने करें कहते कहा का काफ़ी कि कितना किन्हें किन्हों किया किर किस किसी किसे की कुछ कुल के को कोई कौन कौनसा गया घर जब जहाँ जा जितना जिन जिन्हें जिन्हों जिस जिसे जीधर जैसा जैसे जो तक तब तरह तिन तिन्हें तिन्हों तिस तिसे तो था थी थे दबारा दिया दुसरा दूसरे दो द्वारा न नके नहीं ना निहायत नीचे ने पर पहले पूरा पे फिर बनी बही बहुत बाद बाला बिलकुल भी भीतर मगर मानो मे में यदि यह यहाँ यही या यिह ये रखें रहा रहे ऱ्वासा लिए लिये लेकिन व वग़ैरह वर्ग वह वहाँ वहीं वाले वुह वे वो सकता सकते सबसे सभी साथ साबुत साभ सारा से सो संग ही हुआ हुई हुए है हैं हो होता होती होते होना होने".split(" ")),e.hi.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var r=e.wordcut;r.init(),e.hi.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(r){return isLunr2?new e.Token(r.toLowerCase()):r.toLowerCase()});var t=i.toString().toLowerCase().replace(/^\s+/,"");return r.cut(t).split("|")},e.Pipeline.registerFunction(e.hi.stemmer,"stemmer-hi"),e.Pipeline.registerFunction(e.hi.stopWordFilter,"stopWordFilter-hi")}}); -------------------------------------------------------------------------------- /dev/site/assets/javascripts/lunr/min/lunr.ja.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.ja=function(){this.pipeline.reset(),this.pipeline.add(e.ja.trimmer,e.ja.stopWordFilter,e.ja.stemmer),r?this.tokenizer=e.ja.tokenizer:(e.tokenizer&&(e.tokenizer=e.ja.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.ja.tokenizer))};var t=new e.TinySegmenter;e.ja.tokenizer=function(i){var n,o,s,p,a,u,m,l,c,f;if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t.toLowerCase()):t.toLowerCase()});for(o=i.toString().toLowerCase().replace(/^\s+/,""),n=o.length-1;n>=0;n--)if(/\S/.test(o.charAt(n))){o=o.substring(0,n+1);break}for(a=[],s=o.length,c=0,l=0;c<=s;c++)if(u=o.charAt(c),m=c-l,u.match(/\s/)||c==s){if(m>0)for(p=t.segment(o.slice(l,c)).filter(function(e){return!!e}),f=l,n=0;n=C.limit)break;C.cursor++;continue}break}for(C.cursor=o,C.bra=o,C.eq_s(1,"y")?(C.ket=C.cursor,C.slice_from("Y")):C.cursor=o;;)if(e=C.cursor,C.in_grouping(q,97,232)){if(i=C.cursor,C.bra=i,C.eq_s(1,"i"))C.ket=C.cursor,C.in_grouping(q,97,232)&&(C.slice_from("I"),C.cursor=e);else if(C.cursor=i,C.eq_s(1,"y"))C.ket=C.cursor,C.slice_from("Y"),C.cursor=e;else if(n(e))break}else if(n(e))break}function n(r){return C.cursor=r,r>=C.limit||(C.cursor++,!1)}function o(){_=C.limit,d=_,t()||(_=C.cursor,_<3&&(_=3),t()||(d=C.cursor))}function t(){for(;!C.in_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}for(;!C.out_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}return!1}function s(){for(var r;;)if(C.bra=C.cursor,r=C.find_among(p,3))switch(C.ket=C.cursor,r){case 1:C.slice_from("y");break;case 2:C.slice_from("i");break;case 3:if(C.cursor>=C.limit)return;C.cursor++}}function u(){return _<=C.cursor}function c(){return d<=C.cursor}function a(){var r=C.limit-C.cursor;C.find_among_b(g,3)&&(C.cursor=C.limit-r,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del()))}function l(){var r;w=!1,C.ket=C.cursor,C.eq_s_b(1,"e")&&(C.bra=C.cursor,u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.slice_del(),w=!0,a())))}function m(){var r;u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.eq_s_b(3,"gem")||(C.cursor=C.limit-r,C.slice_del(),a())))}function f(){var r,e,i,n,o,t,s=C.limit-C.cursor;if(C.ket=C.cursor,r=C.find_among_b(h,5))switch(C.bra=C.cursor,r){case 1:u()&&C.slice_from("heid");break;case 2:m();break;case 3:u()&&C.out_grouping_b(j,97,232)&&C.slice_del()}if(C.cursor=C.limit-s,l(),C.cursor=C.limit-s,C.ket=C.cursor,C.eq_s_b(4,"heid")&&(C.bra=C.cursor,c()&&(e=C.limit-C.cursor,C.eq_s_b(1,"c")||(C.cursor=C.limit-e,C.slice_del(),C.ket=C.cursor,C.eq_s_b(2,"en")&&(C.bra=C.cursor,m())))),C.cursor=C.limit-s,C.ket=C.cursor,r=C.find_among_b(k,6))switch(C.bra=C.cursor,r){case 1:if(c()){if(C.slice_del(),i=C.limit-C.cursor,C.ket=C.cursor,C.eq_s_b(2,"ig")&&(C.bra=C.cursor,c()&&(n=C.limit-C.cursor,!C.eq_s_b(1,"e")))){C.cursor=C.limit-n,C.slice_del();break}C.cursor=C.limit-i,a()}break;case 2:c()&&(o=C.limit-C.cursor,C.eq_s_b(1,"e")||(C.cursor=C.limit-o,C.slice_del()));break;case 3:c()&&(C.slice_del(),l());break;case 4:c()&&C.slice_del();break;case 5:c()&&w&&C.slice_del()}C.cursor=C.limit-s,C.out_grouping_b(z,73,232)&&(t=C.limit-C.cursor,C.find_among_b(v,4)&&C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-t,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del())))}var d,_,w,b=[new e("",-1,6),new e("á",0,1),new e("ä",0,1),new e("é",0,2),new e("ë",0,2),new e("í",0,3),new e("ï",0,3),new e("ó",0,4),new e("ö",0,4),new e("ú",0,5),new e("ü",0,5)],p=[new e("",-1,3),new e("I",0,2),new e("Y",0,1)],g=[new e("dd",-1,-1),new e("kk",-1,-1),new e("tt",-1,-1)],h=[new e("ene",-1,2),new e("se",-1,3),new e("en",-1,2),new e("heden",2,1),new e("s",-1,3)],k=[new e("end",-1,1),new e("ig",-1,2),new e("ing",-1,1),new e("lijk",-1,3),new e("baar",-1,4),new e("bar",-1,5)],v=[new e("aa",-1,-1),new e("ee",-1,-1),new e("oo",-1,-1),new e("uu",-1,-1)],q=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],z=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],j=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],C=new i;this.setCurrent=function(r){C.setCurrent(r)},this.getCurrent=function(){return C.getCurrent()},this.stem=function(){var e=C.cursor;return r(),C.cursor=e,o(),C.limit_backward=e,C.cursor=C.limit,f(),C.cursor=C.limit_backward,s(),!0}};return function(r){return"function"==typeof r.update?r.update(function(r){return n.setCurrent(r),n.stem(),n.getCurrent()}):(n.setCurrent(r),n.stem(),n.getCurrent())}}(),r.Pipeline.registerFunction(r.nl.stemmer,"stemmer-nl"),r.nl.stopWordFilter=r.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),r.Pipeline.registerFunction(r.nl.stopWordFilter,"stopWordFilter-nl")}}); -------------------------------------------------------------------------------- /dev/site/assets/javascripts/lunr/min/lunr.no.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Norwegian` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,r=w.cursor+3;if(a=w.limit,0<=r||r<=w.limit){for(s=r;;){if(e=w.cursor,w.in_grouping(d,97,248)){w.cursor=e;break}if(e>=w.limit)return;w.cursor=e+1}for(;!w.out_grouping(d,97,248);){if(w.cursor>=w.limit)return;w.cursor++}a=w.cursor,a=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(m,29),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:n=w.limit-w.cursor,w.in_grouping_b(c,98,122)?w.slice_del():(w.cursor=w.limit-n,w.eq_s_b(1,"k")&&w.out_grouping_b(d,97,248)&&w.slice_del());break;case 3:w.slice_from("er")}}function t(){var e,r=w.limit-w.cursor;w.cursor>=a&&(e=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,w.find_among_b(u,2)?(w.bra=w.cursor,w.limit_backward=e,w.cursor=w.limit-r,w.cursor>w.limit_backward&&(w.cursor--,w.bra=w.cursor,w.slice_del())):w.limit_backward=e)}function o(){var e,r;w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(l,11),e?(w.bra=w.cursor,w.limit_backward=r,1==e&&w.slice_del()):w.limit_backward=r)}var s,a,m=[new r("a",-1,1),new r("e",-1,1),new r("ede",1,1),new r("ande",1,1),new r("ende",1,1),new r("ane",1,1),new r("ene",1,1),new r("hetene",6,1),new r("erte",1,3),new r("en",-1,1),new r("heten",9,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",12,1),new r("s",-1,2),new r("as",14,1),new r("es",14,1),new r("edes",16,1),new r("endes",16,1),new r("enes",16,1),new r("hetenes",19,1),new r("ens",14,1),new r("hetens",21,1),new r("ers",14,1),new r("ets",14,1),new r("et",-1,1),new r("het",25,1),new r("ert",-1,3),new r("ast",-1,1)],u=[new r("dt",-1,-1),new r("vt",-1,-1)],l=[new r("leg",-1,1),new r("eleg",0,1),new r("ig",-1,1),new r("eig",2,1),new r("lig",2,1),new r("elig",4,1),new r("els",-1,1),new r("lov",-1,1),new r("elov",7,1),new r("slov",7,1),new r("hetslov",9,1)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],c=[119,125,149,1],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,i(),w.cursor=w.limit,t(),w.cursor=w.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}}); -------------------------------------------------------------------------------- /dev/site/assets/javascripts/lunr/min/lunr.stemmer.support.min.js: -------------------------------------------------------------------------------- 1 | !function(r,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(r.lunr)}(this,function(){return function(r){r.stemmerSupport={Among:function(r,t,i,s){if(this.toCharArray=function(r){for(var t=r.length,i=new Array(t),s=0;s=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor++,!0}return!1},in_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e<=s&&e>=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor--,!0}return!1},out_grouping:function(t,i,s){if(this.cursors||e>3]&1<<(7&e)))return this.cursor++,!0}return!1},out_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e>s||e>3]&1<<(7&e)))return this.cursor--,!0}return!1},eq_s:function(t,i){if(this.limit-this.cursor>1),f=0,l=o0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n+_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n+_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},find_among_b:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit_backward,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o=0;m--){if(n-l==u){f=-1;break}if(f=r.charCodeAt(n-1-l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n-_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n-_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},replace_s:function(t,i,s){var e=s.length-(i-t),n=r.substring(0,t),u=r.substring(i);return r=n+s+u,this.limit+=e,this.cursor>=i?this.cursor+=e:this.cursor>t&&(this.cursor=t),e},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>r.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),r.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}}); -------------------------------------------------------------------------------- /dev/site/assets/javascripts/lunr/min/lunr.sv.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Swedish` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=new function(){function e(){var e,r=w.cursor+3;if(o=w.limit,0<=r||r<=w.limit){for(a=r;;){if(e=w.cursor,w.in_grouping(l,97,246)){w.cursor=e;break}if(w.cursor=e,w.cursor>=w.limit)return;w.cursor++}for(;!w.out_grouping(l,97,246);){if(w.cursor>=w.limit)return;w.cursor++}o=w.cursor,o=o&&(w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(u,37),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.in_grouping_b(d,98,121)&&w.slice_del()}}function i(){var e=w.limit_backward;w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.find_among_b(c,7)&&(w.cursor=w.limit,w.ket=w.cursor,w.cursor>w.limit_backward&&(w.bra=--w.cursor,w.slice_del())),w.limit_backward=e)}function s(){var e,r;if(w.cursor>=o){if(r=w.limit_backward,w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(m,5))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.slice_from("lös");break;case 3:w.slice_from("full")}w.limit_backward=r}}var a,o,u=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],c=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],l=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],d=[119,127,149],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,t(),w.cursor=w.limit,i(),w.cursor=w.limit,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return t.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}}(),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}}); -------------------------------------------------------------------------------- /dev/site/assets/javascripts/lunr/min/lunr.th.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.th=function(){this.pipeline.reset(),this.pipeline.add(e.th.trimmer),r?this.tokenizer=e.th.tokenizer:(e.tokenizer&&(e.tokenizer=e.th.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.th.tokenizer))},e.th.wordCharacters="[฀-๿]",e.th.trimmer=e.trimmerSupport.generateTrimmer(e.th.wordCharacters),e.Pipeline.registerFunction(e.th.trimmer,"trimmer-th");var t=e.wordcut;t.init(),e.th.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t):t});var n=i.toString().replace(/^\s+/,"");return t.cut(n).split("|")}}}); -------------------------------------------------------------------------------- /dev/site/assets/javascripts/lunr/min/lunr.vi.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.vi=function(){this.pipeline.reset(),this.pipeline.add(e.vi.stopWordFilter,e.vi.trimmer)},e.vi.wordCharacters="[A-Za-ẓ̀͐́͑̉̃̓ÂâÊêÔôĂ-ăĐ-đƠ-ơƯ-ư]",e.vi.trimmer=e.trimmerSupport.generateTrimmer(e.vi.wordCharacters),e.Pipeline.registerFunction(e.vi.trimmer,"trimmer-vi"),e.vi.stopWordFilter=e.generateStopWordFilter("là cái nhưng mà".split(" "))}}); -------------------------------------------------------------------------------- /dev/site/assets/javascripts/lunr/min/lunr.zh.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r(require("nodejieba")):r()(e.lunr)}(this,function(e){return function(r,t){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i="2"==r.version[0];r.zh=function(){this.pipeline.reset(),this.pipeline.add(r.zh.trimmer,r.zh.stopWordFilter,r.zh.stemmer),i?this.tokenizer=r.zh.tokenizer:(r.tokenizer&&(r.tokenizer=r.zh.tokenizer),this.tokenizerFn&&(this.tokenizerFn=r.zh.tokenizer))},r.zh.tokenizer=function(n){if(!arguments.length||null==n||void 0==n)return[];if(Array.isArray(n))return n.map(function(e){return i?new r.Token(e.toLowerCase()):e.toLowerCase()});t&&e.load(t);var o=n.toString().trim().toLowerCase(),s=[];e.cut(o,!0).forEach(function(e){s=s.concat(e.split(" "))}),s=s.filter(function(e){return!!e});var u=0;return s.map(function(e,t){if(i){var n=o.indexOf(e,u),s={};return s.position=[n,e.length],s.index=t,u=n,new r.Token(e,s)}return e})},r.zh.wordCharacters="\\w一-龥",r.zh.trimmer=r.trimmerSupport.generateTrimmer(r.zh.wordCharacters),r.Pipeline.registerFunction(r.zh.trimmer,"trimmer-zh"),r.zh.stemmer=function(){return function(e){return e}}(),r.Pipeline.registerFunction(r.zh.stemmer,"stemmer-zh"),r.zh.stopWordFilter=r.generateStopWordFilter("的 一 不 在 人 有 是 为 以 于 上 他 而 后 之 来 及 了 因 下 可 到 由 这 与 也 此 但 并 个 其 已 无 小 我 们 起 最 再 今 去 好 只 又 或 很 亦 某 把 那 你 乃 它 吧 被 比 别 趁 当 从 到 得 打 凡 儿 尔 该 各 给 跟 和 何 还 即 几 既 看 据 距 靠 啦 了 另 么 每 们 嘛 拿 哪 那 您 凭 且 却 让 仍 啥 如 若 使 谁 虽 随 同 所 她 哇 嗡 往 哪 些 向 沿 哟 用 于 咱 则 怎 曾 至 致 着 诸 自".split(" ")),r.Pipeline.registerFunction(r.zh.stopWordFilter,"stopWordFilter-zh")}}); -------------------------------------------------------------------------------- /dev/site/assets/stylesheets/palette.cbb835fc.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["src/assets/stylesheets/palette/_scheme.scss","../../../src/assets/stylesheets/palette.scss","src/assets/stylesheets/palette/_accent.scss","src/assets/stylesheets/palette/_primary.scss","src/assets/stylesheets/utilities/_break.scss"],"names":[],"mappings":"AA2BA,cAGE,6BAKE,YAAA,CAGA,mDAAA,CACA,6DAAA,CACA,+DAAA,CACA,gEAAA,CACA,mDAAA,CACA,6DAAA,CACA,+DAAA,CACA,gEAAA,CAGA,gDAAA,CACA,gDAAA,CAGA,uCAAA,CACA,iCAAA,CACA,kCAAA,CACA,mCAAA,CACA,mCAAA,CACA,kCAAA,CACA,iCAAA,CACA,+CAAA,CACA,6DAAA,CACA,gEAAA,CACA,4DAAA,CACA,4DAAA,CACA,6DAAA,CAGA,6CAAA,CAGA,+CAAA,CAGA,2CAAA,CAGA,uDAAA,CACA,6DAAA,CACA,2DAAA,CAGA,yDAAA,CAGA,mDAAA,CACA,mDAAA,CAGA,qDAAA,CACA,wDAAA,CAGA,wEAAA,CAKA,yEAAA,CAKA,yECxDF,CD6DE,kHAEE,YC3DJ,CD+DE,gHAEE,eC7DJ,CDoFE,yDACE,4BClFJ,CDiFE,2DACE,4BC/EJ,CD8EE,gEACE,4BC5EJ,CD2EE,2DACE,4BCzEJ,CDwEE,yDACE,4BCtEJ,CDqEE,0DACE,4BCnEJ,CDkEE,gEACE,4BChEJ,CD+DE,0DACE,4BC7DJ,CD4DE,2OACE,4BCjDJ,CDwDA,+FAGE,iCCtDF,CACF,CCjDE,2BACE,4BAAA,CACA,oDAAA,CAOE,yBAAA,CACA,8CD6CN,CCvDE,4BACE,4BAAA,CACA,mDAAA,CAOE,yBAAA,CACA,8CDoDN,CC9DE,8BACE,4BAAA,CACA,qDAAA,CAOE,yBAAA,CACA,8CD2DN,CCrEE,mCACE,4BAAA,CACA,qDAAA,CAOE,yBAAA,CACA,8CDkEN,CC5EE,8BACE,4BAAA,CACA,qDAAA,CAOE,yBAAA,CACA,8CDyEN,CCnFE,4BACE,4BAAA,CACA,qDAAA,CAOE,yBAAA,CACA,8CDgFN,CC1FE,kCACE,4BAAA,CACA,oDAAA,CAOE,yBAAA,CACA,8CDuFN,CCjGE,4BACE,4BAAA,CACA,oDAAA,CAOE,yBAAA,CACA,8CD8FN,CCxGE,4BACE,4BAAA,CACA,oDAAA,CAOE,yBAAA,CACA,8CDqGN,CC/GE,6BACE,4BAAA,CACA,mDAAA,CAOE,yBAAA,CACA,8CD4GN,CCtHE,mCACE,4BAAA,CACA,oDAAA,CAOE,yBAAA,CACA,8CDmHN,CC7HE,4BACE,4BAAA,CACA,oDAAA,CAIE,oCAAA,CACA,2CD6HN,CCpIE,8BACE,4BAAA,CACA,oDAAA,CAIE,oCAAA,CACA,2CDoIN,CC3IE,6BACE,yBAAA,CACA,oDAAA,CAIE,oCAAA,CACA,2CD2IN,CClJE,8BACE,4BAAA,CACA,oDAAA,CAIE,oCAAA,CACA,2CDkJN,CCzJE,mCACE,4BAAA,CACA,qDAAA,CAOE,yBAAA,CACA,8CDsJN,CE3JE,4BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFwJN,CEnKE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFgKN,CE3KE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFwKN,CEnLE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFgLN,CE3LE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFwLN,CEnME,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFgMN,CE3ME,mCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFwMN,CEnNE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFgNN,CE3NE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFwNN,CEnOE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFgON,CE3OE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFwON,CEnPE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,qCAAA,CACA,4CFmPN,CE3PE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,qCAAA,CACA,4CF2PN,CEnQE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,qCAAA,CACA,4CFmQN,CE3QE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,qCAAA,CACA,4CF2QN,CEnRE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFgRN,CE3RE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFwRN,CEnSE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CAAA,CAKA,4BF4RN,CE5SE,kCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CAAA,CAKA,4BFqSN,CEtRE,sEACE,4BFyRJ,CE1RE,+DACE,4BF6RJ,CE9RE,iEACE,4BFiSJ,CElSE,gEACE,4BFqSJ,CEtSE,iEACE,4BFySJ,CEhSA,8BACE,0BAAA,CACA,+CAAA,CACA,2CAAA,CACA,qCAAA,CACA,4CAAA,CAGA,4BFiSF,CGrMI,mCDtFA,+CACE,gCF8RJ,CE3RI,qDACE,gCF6RN,CExRE,iEACE,qBF0RJ,CACF,CGhNI,sCDnEA,uCACE,0CFsRJ,CACF,CE7QA,8BACE,0BAAA,CACA,4CAAA,CACA,gCAAA,CACA,0BAAA,CACA,+CAAA,CAGA,4BF8QF,CE3QE,yCACE,qBF6QJ,CG9MI,wCDxDA,8CACE,gCFyQJ,CACF,CGtOI,mCD5BA,+CACE,oCFqQJ,CElQI,qDACE,mCFoQN,CACF,CG3NI,wCDjCA,iFACE,qBF+PJ,CACF,CGnPI,sCDLA,uCACE,qBF2PJ,CACF","file":"palette.css"} -------------------------------------------------------------------------------- /dev/site/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | https://ura.hyaku.download/ 5 | 2022-09-05 6 | daily 7 | 8 | 9 | https://ura.hyaku.download/changelog/ 10 | 2022-09-05 11 | daily 12 | 13 | 14 | https://ura.hyaku.download/faq/ 15 | 2022-09-05 16 | daily 17 | 18 | 19 | https://ura.hyaku.download/latest-bump/ 20 | 2022-09-05 21 | daily 22 | 23 | 24 | https://ura.hyaku.download/latest-commit/ 25 | 2022-09-05 26 | daily 27 | 28 | 29 | https://ura.hyaku.download/latest-release-notes/ 30 | 2022-09-05 31 | daily 32 | 33 | 34 | https://ura.hyaku.download/license/ 35 | 2022-09-05 36 | daily 37 | 38 | 39 | https://ura.hyaku.download/notes-to-self/ 40 | 2022-09-05 41 | daily 42 | 43 | 44 | https://ura.hyaku.download/docs/0/0/ 45 | 2022-09-05 46 | daily 47 | 48 | 49 | https://ura.hyaku.download/docs/0/0/config/ 50 | 2022-09-05 51 | daily 52 | 53 | 54 | https://ura.hyaku.download/docs/0/0/structure/ 55 | 2022-09-05 56 | daily 57 | 58 | 59 | https://ura.hyaku.download/docs/0/0/api/ 60 | 2022-09-05 61 | daily 62 | 63 | 64 | https://ura.hyaku.download/docs/0/0/api/gui/ 65 | 2022-09-05 66 | daily 67 | 68 | 69 | https://ura.hyaku.download/docs/0/0/api/src/ 70 | 2022-09-05 71 | daily 72 | 73 | 74 | https://ura.hyaku.download/docs/0/0/api/src/base/ 75 | 2022-09-05 76 | daily 77 | 78 | 79 | https://ura.hyaku.download/docs/0/0/api/src/cd/ 80 | 2022-09-05 81 | daily 82 | 83 | 84 | https://ura.hyaku.download/docs/0/0/api/src/cfg/ 85 | 2022-09-05 86 | daily 87 | 88 | 89 | https://ura.hyaku.download/docs/0/0/api/src/cli/ 90 | 2022-09-05 91 | daily 92 | 93 | 94 | https://ura.hyaku.download/docs/0/0/api/src/download/ 95 | 2022-09-05 96 | daily 97 | 98 | 99 | https://ura.hyaku.download/docs/0/0/api/src/exceptions/ 100 | 2022-09-05 101 | daily 102 | 103 | 104 | https://ura.hyaku.download/docs/0/0/api/src/globals/ 105 | 2022-09-05 106 | daily 107 | 108 | 109 | https://ura.hyaku.download/docs/0/0/api/src/init/ 110 | 2022-09-05 111 | daily 112 | 113 | 114 | https://ura.hyaku.download/docs/0/0/api/src/style/ 115 | 2022-09-05 116 | daily 117 | 118 | 119 | https://ura.hyaku.download/docs/0/0/api/src/utils/ 120 | 2022-09-05 121 | daily 122 | 123 | -------------------------------------------------------------------------------- /dev/site/sitemap.xml.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/dev/site/sitemap.xml.gz -------------------------------------------------------------------------------- /dev/vars.yml: -------------------------------------------------------------------------------- 1 | docs: 2 | input: dev/raw_docs 3 | op: docs 4 | 5 | pdoc: 6 | project: ura 7 | op: docs 8 | tpl: dev/constants/tpl/pdoc 9 | 10 | mako: 11 | gen: 12 | path: 13 | - changelog.mako 14 | - latest-bump.mako 15 | - latest-commit.mako 16 | - latest-release-notes.mako 17 | glob: 18 | - docs/**/**/config.mako 19 | - docs/**/**/index.mako 20 | 21 | md_vars: 22 | global: 23 | project_name: ura 24 | repo_name: urasunday 25 | site: ura.hyaku.download 26 | organization: hyaku-dl 27 | author: whi~nyaan! 28 | user: whinee 29 | year: 2022 30 | codacy_id: 385ceb2d55424256a93f9ad6f8007f91 31 | wakatime: urasunday 32 | dc_acc: whi_ne | whinyaan.xyz#5135 33 | dc_link: https://discord.com/users/867696753434951732 34 | dc_inv: JbAtUxGcJZ 35 | mail_acc: whinyaan@pm.me 36 | mail_link: mailto:whinyaan@pm.me 37 | desc: |- 38 | A Basic Urasunday Scraper 39 | long_desc: |- 40 | A no-nonsense, simple and easy to use scraper for urasunday.com 41 | long_desc_md: |- 42 | A no-nonsense, simple and easy to use scraper for urasunday 43 | 44 | local: 45 | README: 46 | title: ura 47 | 48 | rules: 49 | del: {} 50 | repl: 51 | 'src="https://${site}/assets': 52 | - 'src="./assets' 53 | "src='https://${site}/assets": 54 | - "src='./assets" 55 | '](https://${site}/assets': 56 | - '](./assets' 57 | 58 | requirements: 59 | dev: dev/constants/req.txt 60 | prod: requirements.txt 61 | 62 | development: 63 | venv: 64 | requirements: 65 | - prod 66 | - dev 67 | 68 | license: 69 | year: 2022 70 | type: MIT 71 | cholder: 72 | whi_ne: 73 | user: whinee 74 | projects: 75 | hyaku-dl: 76 | hyaku: 77 | year: 2022 78 | platform: Github 79 | MangDL: 80 | MangDL: 81 | year: 2021-2022 82 | platform: Github 83 | Pirate-Kings: 84 | YAMHL: 85 | year: 2022 86 | platform: Github 87 | whinee: 88 | snippets.py: 89 | year: 2022 90 | platform: Github 91 | 92 | build: 93 | base: 94 | directories: 95 | output: dist 96 | buildResources: build 97 | appId: download.hyaku.ura 98 | productName: ura 99 | copyright: Copyright © 2022 whinee 100 | compression: store 101 | artifactName: ${productName}.${ext} 102 | asar: false 103 | win: 104 | win: 105 | target: 106 | - nsis 107 | icon: docs\assets\images\icons\icon.png 108 | nsis: 109 | oneClick: false 110 | perMachine: false 111 | allowElevation: true 112 | license: dev\site\license\index.html 113 | files: 114 | - filter: 115 | - node_modules\**\* 116 | - tmp\**\* 117 | linux: 118 | linux: 119 | target: 120 | - appimage 121 | synopsis: A Basic Urasunday Scraper 122 | description: A no-nonsense, simple and easy to use scraper for urasunday.com 123 | category: Graphics 124 | icon: docs/assets/images/icons/icon.png 125 | files: 126 | - filter: 127 | - node_modules/**/* 128 | - tmp/**/* 129 | 130 | fetch: 131 | project_name: urasunday 132 | system: |- 133 | PF_INFO="os host kernel uptime pkgs memory" PF_COL1=69 PF_COL2=70 PF_SEP=": " pfetch 134 | project: |- 135 | onefetch --no-palette --no-bots -d languages lines_of_code size --show-logo never -a emacs-lisp 136 | types: 137 | Project Source: |- 138 | onefetch --no-palette --no-bots --show-logo never -e "*.ps1" "*.sh" dev/ docs/ -d git_info project head pending version created dependencies authors last_change contributors repo commits size license 139 | Core: |- 140 | onefetch --no-palette --no-bots --show-logo never -e "*.ps1" "*.sh" dev/ ura/gui/ -d git_info project head pending version created dependencies authors last_change contributors repo commits size license 141 | GUI: |- 142 | onefetch --no-palette --no-bots --show-logo never -e "*.ps1" "*.sh" dev/ ura/src/ -d git_info project head pending version created dependencies authors last_change contributors repo commits size license 143 | Docs: |- 144 | onefetch --no-palette --no-bots --show-logo never -e dev/constants/ dev/scripts/ dev/site ura/ "*.ps1" "*.sh" "*.xml" -T programming markup prose data -d git_info project head pending version created dependencies authors last_change contributors repo commits size license 145 | Site: |- 146 | onefetch --no-palette --no-bots --show-logo never -e dev/constants/ dev/raw_docs/ dev/scripts/ docs/ ura/ "*.ps1" "*.sh" "*.xml" -T programming markup prose data -d git_info project head pending version created dependencies authors last_change contributors repo commits size license 147 | -------------------------------------------------------------------------------- /docs/_meta.yml: -------------------------------------------------------------------------------- 1 | generated: 2 | docs: 3 | files: 4 | - docs/notes to self.md 5 | - docs/docs/0/0/setup.md 6 | - docs/docs/0/0/config.md 7 | - docs/README.md 8 | - docs/notes.md 9 | - docs/docs/0/0/structure.md 10 | - docs/license.md 11 | folders: [] 12 | mako: 13 | files: 14 | - docs/docs/0/0/index.md 15 | - docs/changelog.md 16 | folders: [] 17 | pdoc: 18 | files: 19 | - docs/docs/0/0/api/base.md 20 | - docs/docs/0/0/api/index.md 21 | - docs/docs/0/0/api/style.md 22 | - docs/docs/0/0/api/init.md 23 | - docs/docs/0/0/api/settings.md 24 | - docs/docs/0/0/api/globals.md 25 | - docs/docs/0/0/api/utils.md 26 | - docs/docs/0/0/api/main.md 27 | - docs/docs/0/0/api/cli.md 28 | - docs/docs/0/0/api/download.md 29 | folders: [] 30 | -------------------------------------------------------------------------------- /docs/assets/images/icons/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/docs/assets/images/icons/code.png -------------------------------------------------------------------------------- /docs/assets/images/icons/contributors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/docs/assets/images/icons/contributors.png -------------------------------------------------------------------------------- /docs/assets/images/icons/discord.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/docs/assets/images/icons/discord.png -------------------------------------------------------------------------------- /docs/assets/images/icons/dl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/docs/assets/images/icons/dl.png -------------------------------------------------------------------------------- /docs/assets/images/icons/forks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/docs/assets/images/icons/forks.png -------------------------------------------------------------------------------- /docs/assets/images/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/docs/assets/images/icons/icon.png -------------------------------------------------------------------------------- /docs/assets/images/icons/issues.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/docs/assets/images/icons/issues.png -------------------------------------------------------------------------------- /docs/assets/images/icons/license.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/docs/assets/images/icons/license.png -------------------------------------------------------------------------------- /docs/assets/images/icons/logo-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/docs/assets/images/icons/logo-black.png -------------------------------------------------------------------------------- /docs/assets/images/icons/logo-black.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/docs/assets/images/icons/logo-black.xcf -------------------------------------------------------------------------------- /docs/assets/images/icons/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/docs/assets/images/icons/logo.png -------------------------------------------------------------------------------- /docs/assets/images/icons/logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/docs/assets/images/icons/logo.xcf -------------------------------------------------------------------------------- /docs/assets/images/icons/read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/docs/assets/images/icons/read.png -------------------------------------------------------------------------------- /docs/assets/images/icons/stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/docs/assets/images/icons/stars.png -------------------------------------------------------------------------------- /docs/changelog.md: -------------------------------------------------------------------------------- 1 |

2 | Changelog 3 |

4 | 5 |

0.0.0.0-rc.0

6 | 7 | ## Added 8 | 9 | - `-on`/`--overwrite_not`, `-op`/`--overwrite_prompt`, and `-opn`/`--overwrite_prompt_not` flags for the `dl` subcommand. 10 | 11 |

Added

12 | 13 | - `-on`/`--overwrite_not`, `-op`/`--overwrite_prompt`, and `-opn`/`--overwrite_prompt_not` flags for the `dl` subcommand. 14 | 15 |

Changed

16 | 17 | - Made the app log the `log path` even when loading, so that the user will know where to find the said file when it gets stuck while loading. 18 | 19 | - .AppImage so that you can run the cli by appending the `cli` subcommand to the command for running the said AppImage. For example, `./ura.AppImage cli [flags]`. 20 | 21 |

Fixed

22 | 23 | - `overwrite` settings not being followed (i.e. `overwrite` set to False, yet the chapter that is already downloaded is being overwritten). 24 | 25 | - Once and for all, the fucking python imports, for fuck's sake. 26 | 27 | - Improved documentation! 28 | 29 |

0.0.0.0-beta.1

30 | 31 | ## Added 32 | 33 | - Dynamic version and copyright information 34 | 35 |

Added

36 | 37 | - Dynamic version and copyright information 38 | 39 |

Changed

40 | 41 | - Improved logging 42 | 43 |

Fixed

44 | 45 | - Incorrect python library importing that causes the app to crash outright 46 | 47 |

0.0.0.0-beta.0

48 | 49 | YANKED! 50 | 51 |

Added

52 | 53 | - Icon for .AppImage distribution of that app 54 | 55 | - Logging information to help debug the application 56 | 57 | - The app now reflects changes made on the configuration file on the app 58 | 59 |

Changed

60 | 61 | - Improved loading of the app, so that when the loading page is removed, the app is totally usable 62 | 63 | - Uses parts of private project (`whinee/snippets.py`) for the configuration of the app, and others 64 | 65 |

0.0.0.0-alpha.5

66 | 67 | ## Added 68 | 69 | - Loading screen for app initialization 70 | 71 |

Added

72 | 73 | - Loading screen for app initialization 74 | 75 |

Fixed

76 | 77 | - AppImages to be marked as AppImages (means that the config now goes on the config folder instead of the same directory as the AppImage) 78 | 79 |

0.0.0.0-alpha.4

80 | 81 | YANKED! 82 | 83 |

Added

84 | 85 | - Initialization of configuration file 86 | 87 |

0.0.0.0-alpha.3

88 | 89 | YANKED! 90 | 91 |

Fixed

92 | 93 | - `vls` string on `ura/__init__.py` to `[0, 0, 0, 0, 0, 3]` 94 | 95 |

0.0.0.0-alpha.2

96 | 97 | YANKED! 98 | 99 |

Fixed

100 | 101 | - Unquoted `__version__` string on `ura/__init__.py` 102 | 103 |

0.0.0.0-alpha.1

104 | 105 |

Removed

106 | 107 | - Useless imports 108 | 109 |

0.0.0.0-alpha.0

110 | -------------------------------------------------------------------------------- /docs/docs/0/0/api/gui.md: -------------------------------------------------------------------------------- 1 | # **[ura](index.md).[gui](gui.md)** 2 | 3 | ## **Functions** 4 | 5 |

connect

6 | 7 | ```python 8 | (sid, environ) 9 | ``` 10 | 11 |

connect_error

12 | 13 | ```python 14 | (data) 15 | ``` 16 | 17 |

disconnect

18 | 19 | ```python 20 | (sid) 21 | ``` 22 | 23 |

exp_log

24 | 25 | ```python 26 | (sid, name: str, *msg) ‑> None 27 | ``` 28 | 29 |

ifn

30 | 31 | ```python 32 | (*args, **kwargs) 33 | ``` 34 | 35 |

log

36 | 37 | ```python 38 | (name: str, *msg) ‑> None 39 | ``` 40 | 41 | Log message to console. 42 | 43 |

Args:

44 | 45 | - msg (`str`): Message to be logged. 46 | 47 |

log_path_fn

48 | 49 | ```python 50 | (sid, data) 51 | ``` 52 | 53 |

rbn

54 | 55 | ```python 56 | (func: Callable[[Any], bool]) ‑> Callable[[Any], tuple[bool, None]] 57 | ``` 58 | 59 | Return bool, None 60 | 61 |

Args:

62 | 63 | - func (`Callable[[Any], bool]`): Function to be wrapped. 64 | 65 |

Returns:

66 | 67 | `Callable[[Any], tuple[bool, None]]`: Wrapped function. 68 | 69 |

rta

70 | 71 | ```python 72 | (func: Callable[[Any], Any]) ‑> Callable[[Any], tuple[True, Any]] 73 | ``` 74 | 75 | Return True, Any 76 | 77 |

Args:

78 | 79 | - func (Callable\[\[Any\], Any\]): Function to be wrapped. 80 | 81 |

Returns:

82 | 83 | Callable\[\[Any\], tuple\[True, Any\]\]: Wrapped function. 84 | 85 |

rtn

86 | 87 | ```python 88 | (func: Callable[[Any], None]) ‑> Callable[[Any], tuple[True, None]] 89 | ``` 90 | 91 | Return True, None 92 | 93 |

Args:

94 | 95 | - func (`Callable[[Any], None]`): Function to be wrapped. 96 | 97 |

Returns:

98 | 99 | `Callable[[Any], tuple[True, None]]`: Wrapped function. 100 | 101 |

tex

102 | 103 | ```python 104 | (func: Callable[[Any], Any]) ‑> Callable[[Any], tuple[bool, Any]] 105 | ``` 106 | 107 | Try except wrapper 108 | 109 |

Args:

110 | 111 | - func (Callable\[\[Any\], Any\]): Function to be wrapped. 112 | 113 |

Returns:

114 | 115 | Callable\[\[Any\], Any\]: Wrapped function. 116 | 117 | ## **Classes** 118 | 119 |

Expose

120 | 121 | ```python 122 | () 123 | ``` 124 | 125 |

Methods

126 | 127 |

config

128 | 129 | ```python 130 | (*args, **kwargs) 131 | ``` 132 | 133 |

dl

134 | 135 | ```python 136 | (*args, **kwargs) 137 | ``` 138 | 139 |

info

140 | 141 | ```python 142 | (*args, **kwargs) 143 | ``` 144 | 145 |

write_config

146 | 147 | ```python 148 | (*args, **kwargs) 149 | ``` 150 | -------------------------------------------------------------------------------- /docs/docs/0/0/api/index.md: -------------------------------------------------------------------------------- 1 | # **[ura](index.md)** 2 | 3 | ## **Sub-modules** 4 | 5 | - [ura.gui](gui.md) 6 | - [ura.src](src.md) 7 | -------------------------------------------------------------------------------- /docs/docs/0/0/api/src.md: -------------------------------------------------------------------------------- 1 | # **[ura](index.md).[src](src.md)** 2 | 3 | ## **Super-module** 4 | 5 | - [ura](index.md) 6 | 7 | ## **Sub-modules** 8 | 9 | - [ura.src.base](src/base.md) 10 | - [ura.src.cd](src/cd.md) 11 | - [ura.src.cfg](src/cfg.md) 12 | - [ura.src.cli](src/cli.md) 13 | - [ura.src.download](src/download.md) 14 | - [ura.src.exceptions](src/exceptions.md) 15 | - [ura.src.globals](src/globals.md) 16 | - [ura.src.init](src/init.md) 17 | - [ura.src.style](src/style.md) 18 | - [ura.src.utils](src/utils.md) 19 | -------------------------------------------------------------------------------- /docs/docs/0/0/api/src/base.md: -------------------------------------------------------------------------------- 1 | # **[ura](../index.md).[src](../src.md).[base](base.md)** 2 | 3 | ## **Functions** 4 | 5 |

class_usi

6 | 7 | ```python 8 | (dict_usi: dict[str, int]) 9 | ``` 10 | 11 | From the given key-value pairs of slug name and slug index, return a class with attributes for each slug, passed to url_slug_idx. 12 | 13 |

Args:

14 | 15 | ``` 16 | dict_usi (`dict[str, int]`): The dictionary to get the slug name-index pairs from. 17 | ``` 18 | 19 |

soup

20 | 21 | ```python 22 | (url: str, req: Type[ura.src.base.req] = ura.src.base.req, method: str = 'get', **kwargs: Dict[str, Any]) ‑> bs4.BeautifulSoup 23 | ``` 24 | 25 | Returns a soup from the given url. 26 | 27 |

Args:

28 | 29 | - url (`str`): URL to get the soup from. 30 | - req (`Type[req]`, optional): Object to call the methods from. Defaults to req. 31 | 32 |

Returns:

33 | 34 | `BeautifulSoup`: the soup 35 | 36 |

urel_fn

37 | 38 | ```python 39 | (url: str) ‑> str 40 | ``` 41 | 42 | Turn an absolute URL to a relative one. If the given URL is already a 43 | relative one, a URL object from the url will be returned. 44 | 45 |

Args:

46 | 47 | - url (`str`): The URL to turn into a relative one. 48 | 49 |

Returns:

50 | 51 | `str`: The relative URL. 52 | 53 |

url_slug_idx

54 | 55 | ```python 56 | (idx: int) ‑> Callable[[str], str] 57 | ``` 58 | 59 | From an index, get the slug from a URL whether it is a relative or an absolute URL. 60 | 61 |

Args:

62 | 63 | - idx (`int`): The index of the slug from. 64 | 65 |

Returns:

66 | 67 | `Callable[[str], str]`: Method to input the URL to and get the slug. 68 | -------------------------------------------------------------------------------- /docs/docs/0/0/api/src/cd.md: -------------------------------------------------------------------------------- 1 | # **[ura](../index.md).[src](../src.md).[cd](cd.md)** 2 | 3 | ## **Classes** 4 | 5 |

CDInsTypeError

6 | 7 | ```python 8 | (og_path: str, idx: int, type: type) 9 | ``` 10 | 11 | Inappropriate argument type. 12 | 13 |

Ancestors (in MRO)

14 | 15 | - builtins.TypeError 16 | - builtins.Exception 17 | - builtins.BaseException 18 | 19 |

CDKeyError

20 | 21 | ```python 22 | (message: str) 23 | ``` 24 | 25 | Mapping key not found. 26 | 27 |

Ancestors (in MRO)

28 | 29 | - builtins.KeyError 30 | - builtins.LookupError 31 | - builtins.Exception 32 | - builtins.BaseException 33 | 34 |

CDTypeError

35 | 36 | ```python 37 | (message: str) 38 | ``` 39 | 40 | Inappropriate argument type. 41 | 42 |

Ancestors (in MRO)

43 | 44 | - builtins.TypeError 45 | - builtins.Exception 46 | - builtins.BaseException 47 | 48 |

CustomDict

49 | 50 | ```python 51 | (*args, **kwargs) 52 | ``` 53 | 54 | Custom dictionary. 55 | 56 |

Ancestors (in MRO)

57 | 58 | - builtins.dict 59 | 60 |

Methods

61 | 62 |

dir

63 | 64 | ```python 65 | (self, path: str, de: Any = None) ‑> Any 66 | ``` 67 | 68 |

insert

69 | 70 | ```python 71 | (self, path: str, value: Any) ‑> None 72 | ``` 73 | 74 | Insert a value into a dictionary or list. 75 | 76 |

Args:

77 | 78 | - path (`str`): The path to the value. 79 | - value (`Any`): The value to insert. 80 | 81 |

modify

82 | 83 | ```python 84 | (self, path: str, value: Any) ‑> None 85 | ``` 86 | 87 | Insert a value into a dictionary or list. 88 | 89 |

Args:

90 | 91 | - path (`str`): The path to the value. 92 | - value (`Any`): The value to insert. 93 | -------------------------------------------------------------------------------- /docs/docs/0/0/api/src/cfg.md: -------------------------------------------------------------------------------- 1 | # **[ura](../index.md).[src](../src.md).[cfg](cfg.md)** 2 | 3 | ## **Functions** 4 | 5 |

dcfg

6 | 7 | ```python 8 | (value: dict, ext: str) ‑> str 9 | ``` 10 | 11 | Dump the given value to a string with the given extension. 12 | 13 |

Args:

14 | 15 | - value (`dict`): Value to dump to a string. 16 | - ext (`str`): Extension to dump the value to. 17 | 18 |

Returns:

19 | 20 | `str`: The dumped value. 21 | 22 |

de_rcfg

23 | 24 | ```python 25 | () 26 | ``` 27 | 28 |

de_wcfg

29 | 30 | ```python 31 | (value: dict[typing.Any, typing.Any] | list[typing.Any]) 32 | ``` 33 | 34 |

pcfg

35 | 36 | ```python 37 | (d: str, type: str) ‑> ura.src.cd.CustomDict 38 | ``` 39 | 40 | Parse the given string as the given type. 41 | 42 |

Args:

43 | 44 | - d (`str`): String to parse. 45 | - type (`str`): Type to parse the string as. 46 | 47 |

Returns:

48 | 49 | `CustomDict`: The parsed string. 50 | 51 |

rcfg

52 | 53 | ```python 54 | (file: str) ‑> ura.src.cd.CustomDict 55 | ``` 56 | 57 | Read the contents of a file with the given file name. 58 | 59 |

Args:

60 | 61 | - file (`str`): File name of the file to read the contents of. 62 | 63 |

Returns:

64 | 65 | `CustomDict`: The contents of the file. 66 | 67 |

wcfg

68 | 69 | ```python 70 | (file: str, value: dict[typing.Any, typing.Any] | list[typing.Any]) ‑> None 71 | ``` 72 | 73 | Write the given value to a file with the given file name. 74 | 75 |

Args:

76 | 77 | - file (`str`): File name of the file to write the value to. 78 | - value (`dict[Any, Any] | list[Any])`: Value to write to the file. 79 | 80 | ## **Classes** 81 | 82 |

ExtensionNotSupported

83 | 84 | ```python 85 | (ext: str) 86 | ``` 87 | 88 | Method or function hasn't been implemented yet. 89 | 90 |

Ancestors (in MRO)

91 | 92 | - builtins.NotImplementedError 93 | - builtins.RuntimeError 94 | - builtins.Exception 95 | - builtins.BaseException 96 | -------------------------------------------------------------------------------- /docs/docs/0/0/api/src/cli.md: -------------------------------------------------------------------------------- 1 | # **[ura](../index.md).[src](../src.md).[cli](cli.md)** 2 | 3 | ## **Functions** 4 | 5 |

command

6 | 7 | ```python 8 | (group) ‑> Callable[[Callable[[Any], Any]], Callable[[Any], Any]] 9 | ``` 10 | 11 | Wrapper for click commands. 12 | 13 |

Args:

14 | 15 | - group (`click.group`): Command group of the command to be under. 16 | 17 |

Returns:

18 | 19 | - `Callable[[Callable[[Any], Any]], Callable[[Any], Any]]` 20 | 21 | ## **Classes** 22 | 23 |

cao

24 | 25 | ```python 26 | (group, cmd: str) 27 | ``` 28 | 29 | Returns wrappers for a click command evaluated from the given arguments. 30 | 31 |

Class variables

32 | 33 | `arguments` 34 | 35 | `cmd` 36 | 37 | `group` 38 | 39 |

Methods

40 | 41 |

a

42 | 43 | ```python 44 | (self, f: Callable[[Any], Any]) ‑> Callable[[Callable[[Any], Any]], Callable[[Any], Any]] 45 | ``` 46 | 47 | The arguments wrapper. 48 | 49 |

Args:

50 | 51 | - f (`Callable[[Any], Any]`): The command function to be decorated. 52 | 53 |

Returns:

54 | 55 | `Callable[[Callable[[Any], Any]], Callable[[Any], Any]]` 56 | 57 |

c

58 | 59 | ```python 60 | (self, f: Callable[[Any], Any]) ‑> Callable[[Callable[[Any], Any]], Callable[[Any], Any]] 61 | ``` 62 | 63 | The command wrapper. 64 | 65 |

Args:

66 | 67 | - f (`Callable[[Any], Any]`): The command function to be decorated. 68 | 69 |

Returns:

70 | 71 | `Callable[[Callable[[Any], Any]], Callable[[Any], Any]]` 72 | 73 |

o

74 | 75 | ```python 76 | (self, f: Callable[[Any], Any]) ‑> Callable[[Callable[[Any], Any]], Callable[[Any], Any]] 77 | ``` 78 | 79 | The options wrapper. 80 | My God in heaven, I'm agnostic, but please save me from all evil. Amen. 81 | 82 |

Args:

83 | 84 | - f (`Callable[[Any], Any]`): The command function to be decorated. 85 | 86 |

Returns:

87 | 88 | `Callable[[Callable[[Any], Any]], Callable[[Any], Any]]` 89 | -------------------------------------------------------------------------------- /docs/docs/0/0/api/src/download.md: -------------------------------------------------------------------------------- 1 | # **[ura](../index.md).[src](../src.md).[download](download.md)** 2 | 3 | ## **Functions** 4 | 5 |

get_extension

6 | 7 | ```python 8 | (filename: str) ‑> str 9 | ``` 10 | 11 | Get the file extension of a file from the given filename. 12 | 13 |

Args:

14 | 15 | - filename (`str`): The filename to get the file extension from. 16 | 17 |

Returns:

18 | 19 | `str`: The file extension from the given filename. 20 | 21 |

get_stg

22 | 23 | ```python 24 | (path: str, de: Any = None) 25 | ``` 26 | 27 |

sanitize_filename

28 | 29 | ```python 30 | (filename: str) ‑> str 31 | ``` 32 | 33 | Sanitize the given filename. 34 | 35 |

Args:

36 | 37 | - filename (`str`): The filename to be sanitized. 38 | 39 |

Returns:

40 | 41 | `str`: Sanitized filename. 42 | 43 | ## **Classes** 44 | 45 |

Downloader

46 | 47 | ```python 48 | (directory: str = None, overwrite: bool = None, **kwargs: Dict[str, Any]) 49 | ``` 50 | 51 |

Methods

52 | 53 |

dlch

54 | 55 | ```python 56 | (self, url: str) 57 | ``` 58 | 59 |

dlf

60 | 61 | ```python 62 | (self, file: List[str]) 63 | ``` 64 | 65 | Individual image downloader. 66 | 67 |

Args:

68 | 69 | - file (`str`): List containing the filename and the url of the file. 70 | -------------------------------------------------------------------------------- /docs/docs/0/0/api/src/exceptions.md: -------------------------------------------------------------------------------- 1 | # **[ura](../index.md).[src](../src.md).[exceptions](exceptions.md)** 2 | 3 | ## **Functions** 4 | 5 |

c_exc

6 | 7 | ```python 8 | (cls: Exception | object) ‑> Exception 9 | ``` 10 | 11 | Decorator to raise a custom exception. 12 | 13 | This function gives the class an __init__ function that raises the exception. 14 | If the class does not inherit from any Exception, it will be automatically inherit from Exception. 15 | This function also wraps the Exception with `c_exc_str` method, for adding the `__str__` method. 16 | 17 |

Args:

18 | 19 | - cls (`BaseException | Object`): The exception to modify. 20 | 21 |

Returns:

22 | 23 | `BaseException`: The exception to raise. 24 | 25 |

c_exc_str

26 | 27 | ```python 28 | (cls: Exception) ‑> Exception 29 | ``` 30 | 31 | Decorator to add the __str__ method to an exception. 32 | 33 |

Args:

34 | 35 | - cls (`BaseException`): The exception to add the __str__ method to. 36 | 37 |

Returns:

38 | 39 | `BaseException`: The exception to raise. 40 | -------------------------------------------------------------------------------- /docs/docs/0/0/api/src/globals.md: -------------------------------------------------------------------------------- 1 | # **[ura](../index.md).[src](../src.md).[globals](globals.md)** 2 | 3 | ## **Variables** 4 | 5 | `CFLOP` 6 | 7 | ```mermaid 8 | flowchart LR 9 | A([Config]) --> B[Grab CFLOP] 10 | B --> C{Last item} 11 | C --> |false| D{File exists?} 12 | D --> |true| E([Read config file]) 13 | D --> |false| C 14 | C --> |true| F{OS?} 15 | F --> |Windows| G[Initialize config file
at first lookup path] --> E 16 | F --> |*nix| H{.AppImage?} 17 | H --> |true| I[Initialize config file
at second lookup path] --> E 18 | H --> |false| G 19 | ``` 20 | 21 | ## **Functions** 22 | 23 |

init

24 | 25 | ```python 26 | (idx: int) ‑> None 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/docs/0/0/api/src/init.md: -------------------------------------------------------------------------------- 1 | # **[ura](../index.md).[src](../src.md).[init](init.md)** 2 | -------------------------------------------------------------------------------- /docs/docs/0/0/api/src/style.md: -------------------------------------------------------------------------------- 1 | # **[ura](../index.md).[src](../src.md).[style](style.md)** 2 | 3 | ## **Functions** 4 | 5 |

pp

6 | 7 | ```python 8 | (t: Any) 9 | ``` 10 | 11 | ## **Classes** 12 | 13 |

C

14 | 15 | ```python 16 | () 17 | ``` 18 | 19 |

Class variables

20 | 21 | `h0` 22 | 23 | `h1` 24 | 25 | `h2` 26 | 27 | `s0` 28 | 29 | `s1` 30 | 31 | `s2` 32 | 33 |

S

34 | 35 | ```python 36 | () 37 | ``` 38 | 39 |

Class variables

40 | 41 | `p0` 42 | 43 | `p1` 44 | 45 | `t0` 46 | 47 | `t1` 48 | 49 | `t2` 50 | 51 | `t_critical` 52 | 53 | `t_error` 54 | 55 | `t_warning` 56 | 57 |

ct

58 | 59 | ```python 60 | () 61 | ``` 62 | 63 |

Methods

64 | 65 |

group

66 | 67 | ```python 68 | (*ls: list[typing.Any]) ‑> rich.console.Group 69 | ``` 70 | 71 |

table

72 | 73 | ```python 74 | (cols: list[str], rows: list[list[str]]) 75 | ``` 76 | -------------------------------------------------------------------------------- /docs/docs/0/0/api/src/utils.md: -------------------------------------------------------------------------------- 1 | # **[ura](../index.md).[src](../src.md).[utils](utils.md)** 2 | 3 | ## **Functions** 4 | 5 |

dnrp

6 | 7 | ```python 8 | (file: str, n: int = 1) ‑> str 9 | ``` 10 | 11 | Get the directory component of a pathname by n times recursively then return it. 12 | 13 |

Args:

14 | 15 | - file (`str`): File to get the directory of. 16 | - n (`int`, optional): Number of times to get up the directory???? Defaults to 1. 17 | 18 |

Returns:

19 | 20 | `str`: The directory component got recursively by n times from the given pathname 21 | 22 |

dpop

23 | 24 | ```python 25 | (d: dict[typing.Any, typing.Any], pop: list[int | tuple[str | int | tuple] | str], de: Any = None) ‑> Any 26 | ``` 27 | 28 | Iterate through the preferred order of precedence (`pop`) and see if the value exists in the dictionary. If it does, return it. If not, return `de`. 29 | 30 |

Args:

31 | 32 | - d (`Dict[Any, Any]`): Dictionary to retrieve the value from. 33 | - pop (`list[int | tuple[str | int | tuple] | str]`): List of keys to iterate through. 34 | - de (`Any`, optional): Default object to be returned. Defaults to None. 35 | 36 |

Returns:

37 | 38 | `Any`: Retrieved value. 39 | 40 |

dt

41 | 42 | ```python 43 | (dt: str, format: str) ‑> str 44 | ``` 45 | 46 | Remove timezone from datetime and format it to ISO 8601 format. 47 | 48 |

Args:

49 | 50 | - dt (`str`): Unformatted datetime string to be formatted to ISO 8601 format 51 | - format (`str`): The initial format of the datetime string 52 | 53 |

Returns:

54 | 55 | `str`: Formatted datetime string 56 | 57 |

dt_ts

58 | 59 | ```python 60 | (ts: str) ‑> str 61 | ``` 62 | 63 | Convert the given unix timestamp to ISO 8601 format. 64 | 65 |

Args:

66 | 67 | ``` 68 | ts (str): unix timestamp to be converted to ISO 8601 format 69 | ``` 70 | 71 |

Returns:

72 | 73 | ``` 74 | str: Formatted datetime string 75 | ``` 76 | 77 |

inmd

78 | 79 | ```python 80 | (p: str, ls: list[str] = None) ‑> str 81 | ``` 82 | 83 | "If Not `path.isdir`, Make Directories" 84 | 85 |

Args:

86 | 87 | - p (`str`): The path to be created, if it does not exist. 88 | 89 |

Returns:

90 | 91 | `str`: The path given. 92 | 93 |

ivnd

94 | 95 | ```python 96 | (var: Any, de: Any) ‑> Any 97 | ``` 98 | 99 | If Var is None, return Default else var. 100 | 101 |

Args:

102 | 103 | - var (`Any`): Variable to check if it is None. 104 | - de (`Any`): Default value to return if var is None. 105 | 106 |

Returns:

107 | 108 | `Any`: var if var is not None else de. 109 | 110 |

le

111 | 112 | ```python 113 | (expr: str) ‑> Any 114 | ``` 115 | 116 |

repl

117 | 118 | ```python 119 | (s: str, repl_dict: dict[str, list[str]]) ‑> str 120 | ``` 121 | 122 |

run

123 | 124 | ```python 125 | (s: str) 126 | ``` 127 | 128 |

sanitize_text

129 | 130 | ```python 131 | (s: str) 132 | ``` 133 | -------------------------------------------------------------------------------- /docs/docs/0/0/config.md: -------------------------------------------------------------------------------- 1 |

2 | Config 3 |

4 | 5 | ## **Configurations** 6 | 7 | ### **download_dir**: `str` 8 | 9 | Directory to download the chapter at. 10 | 11 | ### **overwrite**: `bool` 12 | 13 | Defaults to True. 14 | 15 | Determines if the program overwrites the chapter if it is already downloaded. 16 | 17 | ### **overwrite_prompt**: `bool` 18 | 19 | Determines if the program prompts the user to overwrite the chapter if it is already downloaded. 20 | 21 | ## **Config File** 22 | 23 | ### **Config File Lookup Order of Precedence (CFLOP)** 24 | 25 | Hyaku is a cross-platform project, which means that it could be ran in different OS. 26 | There is however a lack of unity in the standardization on the location of config files in this OSes. 27 | And such, I have devised a precedence order for Hyaku's config file in different platforms. 28 | 29 | The following are the CFLOP for different OSes: 30 | 31 | ```mermaid 32 | flowchart TD 33 | A([CFLOP]) --> L[--config argument] 34 | L --> B{OS?} 35 | B --> |*nix| C[./ura.yml] 36 | subgraph
37 | C --> D{"XDG
CONFIG
HOME
(XCH)?"} 38 | D --> |true| E["${XCH}/ura/config.yml"] --> F 39 | D --> |false| F["~/.config/ura/config.yml"] 40 | F --> G["~/.ura"] 41 | end 42 | B --> |Windows| J[.\ura.yml] 43 | subgraph

44 | J --> K["${boot drive}:\\
Users\${username}\
AppData\Roaming\ura\
config.yml"] 45 | end 46 | ``` 47 | -------------------------------------------------------------------------------- /docs/docs/0/0/index.md: -------------------------------------------------------------------------------- 1 |

2 | dev/raw_docs/docs 3 |

4 | 5 | - [How to configure the program, and how it works](config.md) 6 | - [Structure of the program](Structure.md) 7 | - [Further documentation](api/index.md) 8 | -------------------------------------------------------------------------------- /docs/docs/0/0/structure.md: -------------------------------------------------------------------------------- 1 |

2 | ura's Structure 3 |

4 | 5 | ura is a very basic application, yet it grew to a large size. As a one-man army, it is necessary for me to write this, as to not get lost in this chaos that I have created. 6 | 7 | I, however, procrastinated in writing this, and thus, is completely empty at the moment. 8 | 9 | 10 | 11 | 22 | -------------------------------------------------------------------------------- /docs/faq.md: -------------------------------------------------------------------------------- 1 |

2 | FAQ 3 |

4 | 5 | ## **Is this application safe?** 6 | 7 |
8 | TL;DR: First of all, safe from what aspect, bruv? Considering that you are asking this, probably not. 9 | 10 |

Am I safe from authorities?

11 | 12 |
13 | TL;DR: No, what you are doing right now most probably is illegal. 14 | 15 | Really, you're asking me this? To be fair, it is a genuine concern. But like, assuming that you are 2-4 links deep on this website that only appeals to animanga pirates alike, you probably know what you are doing. Right? Right? 16 | 17 | Okay, right. This is an FAQ, and I have to answer it... Fine... Look, you're not, and you will never be. They are watching your every move. Read the legalese of the app from here Please be careful out there, kind stranger. I'm not (last line written by Github Copilot). 18 | 19 |
20 | 21 |

Is this application safe for my computer?

22 | 23 |
24 | TL;DR: Yes, but not really. Safe enough to put a 99.99% safety guarantee on it, air commercials of it, and not get sued on the grounds of false advertisement. 25 | 26 | No software is ever safe, and there will never be. Unless if we, for some mysterious and divine reason, gain the ability to prove if a program halts or not, which in this universe is impossible (relevant link: Halting problem). 27 | 28 | Enough of explaining the philosophical implications of this problematic question, and let us go to the real meat of the discussion. No, I can not assure you, as the developer of this application, that this application is safe. It is like asking if I poisoned your food; regardless of if I did it or not, I will dutifully deny the allegation, duh. Make of that what you will, but I am here to chase clout and make money out of it, not to compromise machines. 29 | 30 | Well, with all that said, I also made it for personal use. And for that, I have to make it at the very least usable to the extent that it would not compromise the host machine that it is running on. 31 | 32 | Don't trust me? The application is open-sourced. Every packaged application downloaded from the official site and Github repository is built from the same source as available on the official Github repository. If you know how to read the source code, you are free to do so, and inspect it. If you did do so, please hunt down some bugs for me. They haunt me at night, whenever I'm with my friends at the mall, just wherever I am. Please, I'm scared, I will very much appreciate it if you do. 33 | 34 | To end this answer, well... I mean, you could run the thing on a virus checker. Although, what might be an innocuous yet insecure system API call might be flagged as a suspicious activity. Not that I am aware of anything of that sort in my application, but I think that that will suffice as an example. 35 | 36 |
37 |
38 | 39 | ## **What are your intentions in making this application?** 40 | 41 |
42 | 43 | TL;DR: I've been commissioned for this project. Otherwise, it's a hobby of mine. It is not driven by any ill intentions. You asked me, trust me. 44 | 45 | I have been commissioned by @HappyPurple(Discord, Mistilteinn#4793), owner of Ultralight Manga Translation Group to make a downloader for a raws manga site provider called urasunday.com. 46 | 47 | My intentions however are still the same as it was months ago. However, I have a side goal in mind right now: to attain popularity in the animanga piracy scene, enough to get me enough freelancing work and earn money. 48 | 49 | Yes, that is it, really. I am in it for the money. Anyways, I would very much appreciate it if you could donate money or a little bit of your time to ths endeavour of mine, or commission me to do some work for you. 50 | 51 |
52 | 53 | ## **Who are you?** 54 | 55 |
56 | 57 | TL;DR: That's a creepy thing to ask dude, I'm a teenager. \s 58 | 59 | Hello, I am whi_ne, short for whitespace_negative. 17 at the time of writing. I am a python and a web developer, albeit shitty at both of them. I also do some freelance work. Nice to meet ya! 60 | 61 | Yes, I use an alias; personal branding is dead. I also want to stay anonymous. However, my pics on multiple guys' DMs suggests otherwise. And yes, please do not dig up dirt on me, I will let you know everything there is to know about me. 62 | 63 |
64 | -------------------------------------------------------------------------------- /docs/latest-bump.md: -------------------------------------------------------------------------------- 1 |

2 | Latest Version Bump 3 |

4 | 5 | ## 0.0.0.0-rc.0 6 | 7 | Pre-release identifier bump. 8 | 9 | ### Added 10 | 11 | - `-on`/`--overwrite_not`, `-op`/`--overwrite_prompt`, and `-opn`/`--overwrite_prompt_not` flags for the `dl` subcommand. 12 | 13 | ### Changed 14 | 15 | - Made the app log the `log path` even when loading, so that the user will know where to find the said file when it gets stuck while loading. 16 | 17 | - .AppImage so that you can run the cli by appending the `cli` subcommand to the command for running the said AppImage. For example, `./ura.AppImage cli [flags]`. 18 | 19 | ### Fixed 20 | 21 | - `overwrite` settings not being followed (i.e. `overwrite` set to False, yet the chapter that is already downloaded is being overwritten). 22 | 23 | - Once and for all, the fucking python imports, for fuck's sake. 24 | 25 | - Improved documentation! 26 | -------------------------------------------------------------------------------- /docs/latest-commit.md: -------------------------------------------------------------------------------- 1 |

2 | Latest Commit 3 |

4 | 5 | ## **Summary** 6 | 7 | 8 | 9 | Yet 'nother fucking oopsies... 10 | 11 | ## **Changes** 12 | 13 | ### **Fixed** 14 | 15 | - `dev/scripts/py/main.py`'s `push` function to call `docs` function. GAAAAAAAAAAAAHH! 16 | -------------------------------------------------------------------------------- /docs/latest-release-notes.md: -------------------------------------------------------------------------------- 1 |

2 | 0.0.0.0-rc.0 3 |

4 | 5 | ## **Description** 6 | 7 | Pre-release identifier bump. 8 | 9 | ## **Added** 10 | 11 | - `-on`/`--overwrite_not`, `-op`/`--overwrite_prompt`, and `-opn`/`--overwrite_prompt_not` flags for the `dl` subcommand. 12 | 13 | ## **Changed** 14 | 15 | - Made the app log the `log path` even when loading, so that the user will know where to find the said file when it gets stuck while loading. 16 | 17 | - .AppImage so that you can run the cli by appending the `cli` subcommand to the command for running the said AppImage. For example, `./ura.AppImage cli [flags]`. 18 | 19 | ## **Fixed** 20 | 21 | - `overwrite` settings not being followed (i.e. `overwrite` set to False, yet the chapter that is already downloaded is being overwritten). 22 | 23 | - Once and for all, the fucking python imports, for fuck's sake. 24 | 25 | - Improved documentation! 26 | -------------------------------------------------------------------------------- /docs/license.md: -------------------------------------------------------------------------------- 1 |

2 | MIT LICENSE 3 |

4 | 5 | Copyright for portions of project ura are held by \[whi_ne, Github account whinee owner, 2022\] as part of project 8 | hyaku, by \[whi_ne, Github account whinee owner, 2021-2022\] as part of project 10 | MangDL, by \[whi_ne, Github account whinee owner, 2022\] as part of project 12 | YAMHL, and by \[whi_ne, Github account whinee owner, 2022\] as part of project 14 | snippets.py. 15 | 16 | All other copyright for project ura are held by \[Github 18 | Account whinee Owner, 2022\]. 19 | 20 | Permission is hereby granted, free of charge, to any person obtaining a copy 21 | of this software and associated documentation files (the "Software"), to deal 22 | in the Software without restriction, including without limitation the rights 23 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 24 | copies of the Software, and to permit persons to whom the Software is 25 | furnished to do so, subject to the following conditions: 26 | 27 | The above copyright notice and this permission notice shall be included in all 28 | copies or substantial portions of the Software. 29 | 30 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 33 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 34 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 35 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 36 | SOFTWARE. 37 | -------------------------------------------------------------------------------- /docs/notes-to-self.md: -------------------------------------------------------------------------------- 1 |

2 | Notes to Self 3 |

4 | 5 | Look, whi_ne, I have written this for you. 6 | 7 | Please, do I humbly plead you, do not ever forgot to read this before pushing changes to Github. 8 | 9 | ## Versioning System 10 | 11 | Look, you have made your own versioning system based off semver 2.0.0. Use it properly. 12 | 13 | Given a version number `user.dev.minor.patch`, increment the: 14 | 15 | - `user` version when you make any changes to the user interface/experience. This does not include improvements on loading times, despite being well within the user experience umbrella. 16 | - `dev` version when you make incompatible API changes, 17 | - `minor` version when you add functionality in a backwards compatible manner, and 18 | - `patch` version when you make backwards compatible bug fixes. 19 | 20 | If in doubt, please **DO** visit [semver.org](https://semver.org/). 21 | 22 | ### Version Bump Guides 23 | 24 | - **ANY** change in the user interface/experience SHALL induce a `user` version bump. 25 | - **ANY** change in the schema shall induce a `dev` version bump. 26 | - **ANY** change in the documentation SHALL NOT induce any version bump. 27 | 28 | ```mermaid 29 | flowchart TD 30 | VB([Version Bump]) 31 | VB --> |"prerelease identifier (pi)"| e_pr{existing `pi`} 32 | e_pr --> |none| bprv("bump prerelease version (pv)") 33 | bprv --> ba(bump `pi` to `alpha`) 34 | ba --> bp([bump `patch`]) 35 | e_pr --> |alpha| bb(bump to `beta`) 36 | bb --> r0([reset version/s below it to `0` or `none`]) 37 | e_pr --> |beta| br(bump to `rc`) --> r0 38 | e_pr --> |rc| rn(reset to `none`) --> r0 39 | VB --> |others| bsv(bump specified version) --> r0 40 | ``` 41 | 42 | ## Changelog 43 | 44 | As used in the changelog, the following types of changes shall have the following implications, of which, their allowed version bumps should be everything, unless explicably stated otherwise: 45 | 46 | - `Added` for new features. 47 | - user 48 | - dev 49 | - minor 50 | - `Changed` for changes in existing functionality. 51 | - user 52 | - dev 53 | - `Deprecated` for soon-to-be removed features. 54 | - patch 55 | - `Removed` for now removed features. 56 | - user 57 | - dev 58 | - `Fixed` for any bug fixes. 59 | - `Security` in case of vulnerabilities. 60 | 61 | Mind the human as you do with the robot. Format the changelog properly. Example format: 62 | 63 | ```md 64 | ## 69.4.2.0 (minor bump) 65 | 66 | Sprinkle a description here. 67 | 68 | ### Added 69 | 70 | - I added a cool feature. 71 | 72 | ### Deprecated 73 | 74 | - This feature will be depracated 'cuz I can't maintain it anymore. 75 | 76 | ### Security 77 | 78 | - Fixed stuff where the anilist token is leaked to everyone using this app. 79 | ``` 80 | 81 | ## Documentation 82 | 83 | The documentation system is a custom solution. 84 | 85 | If the documentation generator fails, check the traceback. It is commonly due to errors in the code and not the generator itself. 86 | 87 | Do not blame the shitty generator you wrote. You might just have written a faulty code. 88 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | # Do Not Modify! 2 | # info start 3 | site_name: ura 4 | site_url: https://ura.hyaku.download 5 | repo_url: https://github.com/hyaku-dl/urasunday 6 | site_description: A no-nonsense, simple and easy to use scraper for urasunday.com 7 | site_author: whi~nyaan! 8 | copyright: Copyright © 2022 whi~nyaan! 9 | 10 | # info end 11 | 12 | theme: 13 | name: material 14 | locale: en 15 | include_search_page: false 16 | search_index_only: true 17 | language: en 18 | favicon: assets/favicon.png 19 | logo: images/icons/logo.svg 20 | 21 | font: 22 | text: Roboto 23 | code: Roboto Mono 24 | 25 | static_templates: 26 | - 404.html 27 | 28 | features: 29 | - navigation.instant 30 | - navigation.tracking 31 | - navigation.tabs 32 | - navigation.sections 33 | - navigation.indexes 34 | 35 | palette: 36 | - 37 | scheme: slate 38 | primary: deep purple 39 | accent: deep purple 40 | toggle: 41 | icon: material/toggle-switch 42 | name: Switch to light mode 43 | - 44 | scheme: default 45 | primary: deep purple 46 | accent: deep purple 47 | toggle: 48 | icon: material/toggle-switch-off-outline 49 | name: Switch to dark mode 50 | 51 | markdown_extensions: 52 | - 53 | pymdownx.superfences: 54 | custom_fences: 55 | - 56 | name: mermaid 57 | class: mermaid 58 | 59 | extra: 60 | social: 61 | - 62 | icon: fontawesome/brands/github 63 | link: https://github.com/hyaku-dl/urasunday 64 | - 65 | icon: fontawesome/brands/python 66 | link: https://pypi.org/project/ura/ 67 | - 68 | icon: fontawesome/brands/twitter 69 | link: https://twitter.com/whi_nyaan 70 | 71 | plugins: 72 | - search 73 | - minify: 74 | minify_html: true 75 | minify_css: true 76 | minify_js: true 77 | 78 | nav: 79 | - Home: / 80 | - Frequently Asked Questions: /faq 81 | - License Agreement: /license 82 | - Changelog: /changelog 83 | - Latest Bump: /latest-bump 84 | - Latest Commit: /latest-commit 85 | - Notes to self: /notes-to-self 86 | 87 | # Do Not Modify! 88 | - Documentation: 89 | # nav docs start 90 | - 0.0 (Current): docs/0/0/ 91 | # nav docs end -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ura", 3 | "version": "0.0.1-rc.0", 4 | "description": "A Basic Urasunday Scraper", 5 | "main": "tmp/gui/main.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development electron --trace-warnings ura/gui/main.js" 8 | }, 9 | "repository": "https://github.com/hyaku-dl/urasunday", 10 | "keywords": [ 11 | "Electron" 12 | ], 13 | "author": "whinee", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "electron": "^19.0.3", 17 | "electron-builder": "^23.0.3" 18 | }, 19 | "dependencies": { 20 | "python-shell": "^3.0.0", 21 | "socket.io-client": "^4.5.0" 22 | } 23 | } -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | rich 2 | 3 | aiofiles 4 | arrow 5 | bs4 6 | click 7 | eventlet 8 | httpx 9 | inquirer 10 | lxml 11 | msgpack 12 | patool 13 | python-socketio 14 | pyyaml 15 | tabulate 16 | toml 17 | tqdm 18 | yachalk 19 | yarl -------------------------------------------------------------------------------- /source.ps1: -------------------------------------------------------------------------------- 1 | if ( Test-Path -Path pyenv\ ) 2 | { 3 | . .\pyenv\Scripts\Activate.ps1 4 | } 5 | 6 | function dev 7 | { 8 | param( 9 | $Command 10 | ) 11 | 12 | if (!$Command) { 13 | foreach($_ in Get-ChildItem $PSScriptRoot\dev\scripts\ps1\ -Name) { 14 | [System.IO.Path]::GetFileNameWithoutExtension($_) 15 | } 16 | return 17 | } 18 | 19 | & "$PSScriptRoot\dev\scripts\ps1\$Command.ps1" @args 20 | } 21 | -------------------------------------------------------------------------------- /source.sh: -------------------------------------------------------------------------------- 1 | menu() { 2 | if [[ $# != 0 ]]; then 3 | python -c "from dev.scripts.py.main import main;main('$1')" 4 | else 5 | python -c "from dev.scripts.py.main import main;main()" 6 | fi 7 | } -------------------------------------------------------------------------------- /ura/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/ura/__init__.py -------------------------------------------------------------------------------- /ura/gui.py: -------------------------------------------------------------------------------- 1 | import traceback 2 | from datetime import datetime 3 | from typing import Any, Callable 4 | 5 | import eventlet 6 | import socketio 7 | 8 | try: 9 | from src import __version__, cholder 10 | from src.cfg import de_rcfg, de_wcfg 11 | from src.download import Downloader 12 | from src.globals import CFG_PATH 13 | except ImportError: 14 | from .src import __version__, cholder 15 | from .src.cfg import de_rcfg, de_wcfg 16 | from .src.download import Downloader 17 | from .src.globals import CFG_PATH 18 | 19 | 20 | sio = socketio.Server() 21 | app = socketio.WSGIApp(sio) 22 | 23 | 24 | @sio.event 25 | def connect(sid, environ): 26 | print("c0VjUmVUX2NPZEUgYnkgd2hpX25l: Connected") 27 | 28 | 29 | @sio.event 30 | def connect_error(data): 31 | print("Connection failed.") 32 | 33 | 34 | @sio.event 35 | def disconnect(sid): 36 | print("Disconnected") 37 | 38 | 39 | @sio.on("log_path") 40 | def log_path_fn(sid, data): 41 | global log_path 42 | log_path = data 43 | return True, None 44 | 45 | 46 | @sio.on("log") 47 | def log(name: str, *msg) -> None: 48 | """Log message to console. 49 | 50 | Args: 51 | - msg (`str`): Message to be logged. 52 | """ 53 | if len(msg) == 1: 54 | msg = msg[0] 55 | else: 56 | msg = " ".join(msg) 57 | op = "[{}] {}: {}\n".format( 58 | datetime.now().strftime("%Y/%m/%d %H:%M:%S.%f"), 59 | name, 60 | msg, 61 | ) 62 | print(op) 63 | with open(log_path, "a") as f: 64 | f.write(op) 65 | 66 | return True, None 67 | 68 | 69 | @sio.on("log") 70 | def exp_log(sid, name: str, *msg) -> None: 71 | return True, log(name, msg) 72 | 73 | 74 | def tex(func: Callable[[Any], Any]) -> Callable[[Any], tuple[bool, Any]]: 75 | """Try except wrapper 76 | 77 | Args: 78 | - func (Callable[[Any], Any]): Function to be wrapped. 79 | 80 | Returns: 81 | Callable[[Any], Any]: Wrapped function. 82 | """ 83 | 84 | def inner(*args, **kwargs) -> tuple[bool, Any]: 85 | """If function raises an exception, return a tuple consisting of False and the exception message. 86 | 87 | Returns: 88 | `tuple[bool, Any]`: err, res. 89 | """ 90 | try: 91 | op = func(*args, **kwargs) 92 | except Exception as e: 93 | op = False, "\n ".join(traceback.format_exc().strip().split("\n")) 94 | for i in op: 95 | log(func.__name__, i) 96 | return op 97 | 98 | return inner 99 | 100 | 101 | def rta(func: Callable[[Any], Any]) -> Callable[[Any], tuple[True, Any]]: 102 | """Return True, Any 103 | 104 | Args: 105 | - func (Callable[[Any], Any]): Function to be wrapped. 106 | 107 | Returns: 108 | Callable[[Any], tuple[True, Any]]: Wrapped function. 109 | """ 110 | 111 | def inner(*args, **kwargs): 112 | return True, func(*args, **kwargs) 113 | 114 | inner.__name__ = func.__name__ 115 | return inner 116 | 117 | 118 | def rbn(func: Callable[[Any], bool]) -> Callable[[Any], tuple[bool, None]]: 119 | """Return bool, None 120 | 121 | Args: 122 | - func (`Callable[[Any], bool]`): Function to be wrapped. 123 | 124 | Returns: 125 | `Callable[[Any], tuple[bool, None]]`: Wrapped function. 126 | """ 127 | 128 | def inner(*args, **kwargs): 129 | return func(*args, **kwargs), None 130 | 131 | inner.__name__ = func.__name__ 132 | return inner 133 | 134 | 135 | def rtn(func: Callable[[Any], None]) -> Callable[[Any], tuple[True, None]]: 136 | """Return True, None 137 | 138 | Args: 139 | - func (`Callable[[Any], None]`): Function to be wrapped. 140 | 141 | Returns: 142 | `Callable[[Any], tuple[True, None]]`: Wrapped function. 143 | """ 144 | 145 | def inner(*args, **kwargs): 146 | func(*args, **kwargs) 147 | return True, None 148 | 149 | inner.__name__ = func.__name__ 150 | return inner 151 | 152 | 153 | class Expose: 154 | @rta 155 | def info(*args, **kwargs) -> dict[str, str]: 156 | op = { 157 | "cfg_path": CFG_PATH, 158 | "cholder": cholder, 159 | "version": __version__, 160 | } 161 | return op 162 | 163 | @rta 164 | def config(*args, **kwargs) -> dict[str, Any]: 165 | return de_rcfg() 166 | 167 | @rtn 168 | def write_config(sid, stg, value) -> None: 169 | op = de_rcfg() 170 | op.modify(stg, value) 171 | de_wcfg(op) 172 | 173 | @rta 174 | def dl(sid, url) -> str: 175 | return Downloader().dlch(url) 176 | 177 | 178 | expose = [] 179 | 180 | for i in dir(Expose): 181 | ifn = getattr(Expose, i) 182 | if callable(ifn) and not i.startswith("__"): 183 | sio.on(i, tex(ifn)) 184 | 185 | if __name__ == "__main__": 186 | eventlet.wsgi.server(eventlet.listen(("", 9173)), app) 187 | -------------------------------------------------------------------------------- /ura/gui/assets/images/info.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | -------------------------------------------------------------------------------- /ura/gui/assets/images/settings.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 8 | 9 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ura/gui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ura 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 31 | 32 | 33 | 34 | 40 |
41 |
42 |

hyaku-dl/urasunday

43 |

Enter an urasunday chapter URL:

44 |
45 | 48 | 49 |
50 | 51 |
52 | 53 |
54 |
55 |
56 |
57 |
58 |

Settings

59 |

Download

60 |

Download Directory:

61 |

Please wait...

62 | 63 |

Overwrite:

64 | 66 |
67 |
68 |

Info

69 |

Version

70 |

71 |

Author

72 |

whi_ne (whinyaan@protonmail.com)

73 | Github, 74 | Twitter 75 |

Commissioned by

76 |

HappyPurple(Discord, 78 | Mistilteinn#4793), owner of Ultralight Manga 80 | Translation Group. 81 |

82 | Want something like this too? Inquire through Discord(whi_ne 85 | (w17e) | whinyaan.xyz#5135) or through 86 | e-mail(whinyaan@protonmail.com). Price starts at 50 USD. 87 | For commissioning project, price starts at 30 USD. 88 |

Copyright

89 |

MIT LICENSE 92 |

93 |
94 |

Debug

95 |

Log Path:

96 |

Please wait...

97 |
98 |
99 | × 100 |
101 |
102 |
103 |
104 | 105 | -------------------------------------------------------------------------------- /ura/gui/loading.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ura 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 82 | 83 | 85 | 86 | 94 | 95 | 96 | 97 | 98 |
100 | 101 | 102 | 103 | 104 |
105 | -------------------------------------------------------------------------------- /ura/gui/main.js: -------------------------------------------------------------------------------- 1 | // Imports 2 | const { app, BrowserWindow, dialog, ipcMain } = require("electron"); 3 | const { PythonShell } = require('python-shell'); 4 | const path = require("path"); 5 | const EventEmitter = require('events'); 6 | const fs = require('fs'); 7 | 8 | // Constants 9 | const secretRe = /c0VjUmVUX2NPZEUgYnkgd2hpX25l: (.+)/msg; 10 | const pythonPath = "" 11 | const scriptPath = "ura" 12 | const po = { 13 | mode: 'text', 14 | pythonPath: pythonPath, 15 | pythonOptions: ['-u'], 16 | scriptPath: scriptPath, 17 | args: [] 18 | }; 19 | 20 | // Modal Functions 21 | Date.prototype.timeNow = function () { 22 | return ((this.getHours() < 10) ? "0" : "") + this.getHours() + ":" + ((this.getMinutes() < 10) ? "0" : "") + this.getMinutes() + ":" + ((this.getSeconds() < 10) ? "0" : "") + this.getSeconds() + "." + ((this.getMilliseconds() < 10) ? "00" : ((this.getMilliseconds() < 100) ? "0" : "")) + this.getMilliseconds(); 23 | } 24 | 25 | // Derived Constants 26 | const env = process.env.NODE_ENV || "production"; 27 | const loadingEvents = new EventEmitter() 28 | const userDataPath = app.getPath('userData') 29 | const logPath = path.join(userDataPath, 'log.txt'); 30 | const pyshell = new PythonShell('gui.py', po); 31 | 32 | // Variable Init 33 | var init = false; 34 | 35 | // Functions 36 | 37 | function log(...args) { 38 | console.log(...args) 39 | } 40 | 41 | function quit() { 42 | pyshell.childProcess.kill('SIGINT'); 43 | } 44 | 45 | // App Init 46 | app.whenReady().then(() => { 47 | // Init 48 | const mainWindow = new BrowserWindow({ 49 | width: 800, 50 | height: 600, 51 | webPreferences: { 52 | preload: path.join(__dirname, "preload.js"), 53 | nodeIntegration: true, 54 | contextIsolation: false, 55 | }, 56 | autoHideMenuBar: true, 57 | backgroundColor: '#151723', 58 | }); 59 | 60 | mainWindow.loadFile(path.join(__dirname, "loading.html")); 61 | 62 | if (env === 'development') { 63 | mainWindow.webContents.openDevTools() 64 | } 65 | 66 | // Event Listeners 67 | loadingEvents.on('finished', () => { 68 | mainWindow.loadFile(path.join(__dirname, "index.html")); 69 | }) 70 | 71 | mainWindow.webContents.on('new-window', (event, url) => { 72 | event.preventDefault(); 73 | require('electron').shell.openExternal(url); 74 | }) 75 | 76 | ipcMain.on('logPath', function (event, arg) { 77 | event.sender.send('logPath', logPath); 78 | }); 79 | 80 | ipcMain.on('cds', function (event, arg) { 81 | dialog.showOpenDialog(mainWindow, { 82 | properties: ['openDirectory'] 83 | }).then(result => { 84 | if (!result.canceled) { 85 | event.sender.send('cdr', result.filePaths[0]); 86 | } 87 | }).catch(err => { 88 | log(err) 89 | }) 90 | }); 91 | }); 92 | 93 | // Event Listeners 94 | /// Python Shell 95 | pyshell.on('message', function (message) { 96 | if (init == false) { 97 | var m = secretRe.exec(message) 98 | if (m !== null && m[1] === "Connected") { 99 | init = true; 100 | loadingEvents.emit('finished') 101 | log(m[1]); 102 | return; 103 | } 104 | } 105 | log(message); 106 | }); 107 | 108 | pyshell.on('stderr', function (stderr) { 109 | log(stderr); 110 | }); 111 | 112 | /// Electron 113 | app.on("window-all-closed", function () { 114 | quit(); 115 | app.quit(); 116 | }); 117 | 118 | app.on("quit", function () { 119 | quit(); 120 | app.quit(); 121 | }); -------------------------------------------------------------------------------- /ura/gui/preload.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/ura/gui/preload.js -------------------------------------------------------------------------------- /ura/src/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.0.0.0-rc.0" 2 | hver = "0.0.1-rc.0" 3 | vls = [0, 0, 0, 0, 2, 0] 4 | appimage = False 5 | cholder = """Copyright for portions of project ura are held by [whi_ne, Github account whinee owner, 2022] as part of project 8 | hyaku, by [whi_ne, Github account whinee owner, 2021-2022] as part of project 10 | MangDL, by [whi_ne, Github account whinee owner, 2022] as part of project 12 | YAMHL, and by [whi_ne, Github account whinee owner, 2022] as part of project 14 | snippets.py. 15 | 16 | All other copyright for project ura are held by [Github 18 | Account whinee Owner, 2022].""" 19 | -------------------------------------------------------------------------------- /ura/src/__main__.py: -------------------------------------------------------------------------------- 1 | try: 2 | from .cli import cli 3 | except ImportError: 4 | from cli import cli 5 | 6 | cli() 7 | -------------------------------------------------------------------------------- /ura/src/base.py: -------------------------------------------------------------------------------- 1 | import time 2 | from functools import partial 3 | from typing import Any, Callable, Dict, List, Type 4 | 5 | import httpx 6 | from bs4 import BeautifulSoup 7 | from yarl import URL 8 | 9 | # Constants 10 | __pdoc__ = {"r": False, "req": False} 11 | METHODS = ["get", "options", "head", "post", "put", "patch", "delete"] 12 | 13 | # Derived Constants 14 | SESSION = httpx.Client() 15 | 16 | 17 | def urel_fn(url: str) -> str: 18 | """Turn an absolute URL to a relative one. If the given URL is already a 19 | relative one, a URL object from the url will be returned. 20 | 21 | Args: 22 | - url (`str`): The URL to turn into a relative one. 23 | 24 | Returns: 25 | `str`: The relative URL. 26 | """ 27 | url = URL(url) 28 | if url.is_absolute(): 29 | url = url.relative() 30 | return url 31 | 32 | 33 | def url_slug_idx(idx: int) -> Callable[[str], str]: 34 | """From an index, get the slug from a URL whether it is a relative or an absolute URL. 35 | 36 | Args: 37 | - idx (`int`): The index of the slug from. 38 | 39 | Returns: 40 | `Callable[[str], str]`: Method to input the URL to and get the slug. 41 | """ 42 | 43 | def _inner(url: str) -> str: 44 | """The returned method where to input the URL to and get the slug from. 45 | 46 | Args: 47 | - url (`str`): The URL to get the slug from. 48 | 49 | Returns: 50 | `str`: The slug. 51 | """ 52 | urel = urel_fn(url) 53 | return urel.parts[idx + 1] 54 | 55 | return _inner 56 | 57 | 58 | def class_usi(dict_usi: dict[str, int]): 59 | """From the given key-value pairs of slug name and slug index, return a class with attributes for each slug, passed to url_slug_idx. 60 | 61 | Args: 62 | dict_usi (`dict[str, int]`): The dictionary to get the slug name-index pairs from. 63 | """ 64 | 65 | class _class: 66 | """The class to return.""" 67 | 68 | for k, v in dict_usi.items(): 69 | setattr(_class, k, url_slug_idx(v)) 70 | return _class 71 | 72 | 73 | def _req( 74 | url: str, 75 | ra: Callable[[httpx.Response], int] = None, 76 | method: str = "get", 77 | session: httpx.Client = SESSION, 78 | *args: List[Any], 79 | **kwargs: Dict[str, Any] 80 | ) -> httpx.Response: 81 | """Custom request function with retry after capabilities for 429s. 82 | 83 | Args: 84 | - url (`str`): URL to send the request to. 85 | - ra (`Callable[[httpx.Response], int]`, optional): Retry after function, receives the Response object and returns the seconds before retrying. Defaults to None. 86 | - method (`str`, optional): The request method. Defaults to "get". 87 | - session (`httpx.Client`, optional): Session client. Defaults to SESSION. 88 | 89 | Returns: 90 | `httpx.Response`: Response object. 91 | """ 92 | resp = getattr(session, method)(url, follow_redirects=True, *args, **kwargs) 93 | if resp.status_code == 429: 94 | if ra is not None: 95 | time.sleep(ra(resp)) 96 | return _req(url, ra, method, session, *args, **kwargs) 97 | return resp 98 | 99 | 100 | class req: 101 | pass 102 | 103 | 104 | req_dict = { 105 | req: {}, 106 | } 107 | 108 | for r, kw in req_dict.items(): 109 | for i in METHODS: 110 | setattr(r, i, partial(_req, method=i, **kw)) 111 | 112 | 113 | def soup( 114 | url: str, req: Type[req] = req, method: str = "get", **kwargs: Dict[str, Any] 115 | ) -> BeautifulSoup: 116 | """Returns a soup from the given url. 117 | 118 | Args: 119 | - url (`str`): URL to get the soup from. 120 | - req (`Type[req]`, optional): Object to call the methods from. Defaults to req. 121 | 122 | Returns: 123 | `BeautifulSoup`: the soup 124 | """ 125 | return BeautifulSoup(getattr(req, method)(url, **kwargs).text, "lxml") 126 | -------------------------------------------------------------------------------- /ura/src/cf_tpl.mp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/ura/src/cf_tpl.mp -------------------------------------------------------------------------------- /ura/src/cfg.py: -------------------------------------------------------------------------------- 1 | import json 2 | from typing import Any 3 | 4 | import msgpack 5 | import yaml 6 | 7 | try: 8 | from .cd import CustomDict 9 | from .exceptions import c_exc_str 10 | from .globals import CFG_PATH 11 | except ImportError: 12 | from cd import CustomDict 13 | from exceptions import c_exc_str 14 | from globals import CFG_PATH 15 | 16 | TYPES = { 17 | "r": [ 18 | [["yaml", "yml"], ["r", lambda x: yaml.safe_load(x)]], 19 | [["mp"], ["rb", lambda x: msgpack.unpackb(x, raw=False, use_list=True)]], 20 | [["json"], ["r", lambda x: json.loads(x)]], 21 | ], 22 | "w": [ 23 | [["yaml", "yml"], ["w", lambda x: yaml.dump(x, indent=2)]], 24 | [["mp"], ["wb", lambda x: msgpack.packb(x, use_bin_type=True)]], 25 | [["json"], ["w", lambda x: json.dumps(x, indent=4, sort_keys=False)]], 26 | ], 27 | } 28 | 29 | 30 | @c_exc_str 31 | class ExtensionNotSupported(NotImplementedError): 32 | def __init__(self, ext: str) -> None: 33 | self.message = f"Extension `{ext}` is not supported." 34 | super().__init__(self.message) 35 | 36 | 37 | def pcfg(d: str, type: str) -> CustomDict: 38 | """Parse the given string as the given type. 39 | 40 | Args: 41 | - d (`str`): String to parse. 42 | - type (`str`): Type to parse the string as. 43 | 44 | Returns: 45 | `CustomDict`: The parsed string. 46 | """ 47 | 48 | for k, v in TYPES["r"]: 49 | if type in k: 50 | return CustomDict(v[1](d)) 51 | raise ExtensionNotSupported(type) 52 | 53 | 54 | def dcfg(value: dict, ext: str) -> str: 55 | """Dump the given value to a string with the given extension. 56 | 57 | Args: 58 | - value (`dict`): Value to dump to a string. 59 | - ext (`str`): Extension to dump the value to. 60 | 61 | Returns: 62 | `str`: The dumped value. 63 | """ 64 | 65 | for k, v in TYPES["w"]: 66 | if ext in k: 67 | return v[1](value) 68 | raise ExtensionNotSupported(ext) 69 | 70 | 71 | def rcfg(file: str) -> CustomDict: 72 | """Read the contents of a file with the given file name. 73 | 74 | Args: 75 | - file (`str`): File name of the file to read the contents of. 76 | 77 | Returns: 78 | `CustomDict`: The contents of the file. 79 | """ 80 | 81 | ext = file.split(".")[-1] 82 | for k, v in TYPES["r"]: 83 | if ext in k: 84 | with open(file, v[0]) as f: 85 | return CustomDict(v[1](f.read())) 86 | raise ExtensionNotSupported(ext) 87 | 88 | 89 | def wcfg(file: str, value: dict[Any, Any] | list[Any]) -> None: 90 | """Write the given value to a file with the given file name. 91 | 92 | Args: 93 | - file (`str`): File name of the file to write the value to. 94 | - value (`dict[Any, Any] | list[Any])`: Value to write to the file. 95 | """ 96 | ext = file.split(".")[-1] 97 | for k, v in TYPES["w"]: 98 | if ext in k: 99 | with open(file, v[0]) as f: 100 | if value.__class__.__mro__[-2] is dict: 101 | value = dict(value) 102 | f.write(v[1](value)) 103 | 104 | 105 | def de_rcfg(): 106 | return rcfg(CFG_PATH) 107 | 108 | 109 | def de_wcfg(value: dict[Any, Any] | list[Any]): 110 | wcfg(CFG_PATH, value) 111 | -------------------------------------------------------------------------------- /ura/src/cmd.mp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyaku-dl/urasunday/2e47823cedb62a6c2fb2aca356b60c19e320c20b/ura/src/cmd.mp -------------------------------------------------------------------------------- /ura/src/download.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import json 3 | import os 4 | import re 5 | import shutil 6 | import time 7 | from typing import Any, Dict, List 8 | 9 | import aiofiles 10 | from tqdm.asyncio import tqdm_asyncio 11 | 12 | try: 13 | from .base import class_usi, req, soup 14 | from .cfg import de_rcfg 15 | from .utils import sanitize_text 16 | except ImportError: 17 | from base import class_usi, req, soup 18 | from cfg import de_rcfg 19 | from utils import sanitize_text 20 | 21 | # Constants 22 | USI = class_usi( 23 | { 24 | "ch_id": 2, 25 | } 26 | ) 27 | 28 | 29 | def get_stg(path: str, de: Any = None): 30 | return de_rcfg().dir(path, de) 31 | 32 | 33 | def sanitize_filename(filename: str) -> str: 34 | """Sanitize the given filename. 35 | 36 | Args: 37 | - filename (`str`): The filename to be sanitized. 38 | 39 | Returns: 40 | `str`: Sanitized filename. 41 | """ 42 | return re.sub(re.compile(r"[<>:\"/\\|?*]", re.DOTALL), "", str(filename)) 43 | 44 | 45 | def get_extension(filename: str) -> str: 46 | """ 47 | Get the file extension of a file from the given filename. 48 | 49 | Args: 50 | - filename (`str`): The filename to get the file extension from. 51 | 52 | Returns: 53 | `str`: The file extension from the given filename. 54 | """ 55 | return filename.strip("/").split("/")[-1].split("?")[0].split(".")[-1] 56 | 57 | 58 | class Downloader: 59 | def __init__( 60 | self, directory: str = None, overwrite: bool = None, **kwargs: Dict[str, Any] 61 | ): 62 | local = locals() 63 | for k, v in { 64 | "directory": ["ddir", "download_dir"], 65 | "overwrite": ["overwrite", "overwrite"], 66 | }.items(): 67 | gs_var = get_stg(v[1]) 68 | if gs_var is None: 69 | op = local[k] 70 | else: 71 | op = gs_var 72 | setattr(self, v[0], op) 73 | 74 | async def _dlf(self, file: list[str], n: int = 0): 75 | """The core individual image downloader. 76 | 77 | Args: 78 | - file (`str`): List containing the filename and the url of the file. 79 | - n (`int`, optional): Times the download for this certain file is retried. Defaults to 0. 80 | """ 81 | async with aiofiles.open(file[0] + ".tmp", "wb") as f: 82 | r = req.get(file[1]) 83 | if r.status_code == 200: 84 | async for data in r.aiter_bytes(): 85 | await f.write(data) 86 | elif r.status_code == 429: 87 | time.sleep(5) 88 | await self._dlf(file, n) 89 | 90 | async def dlf(self, file: List[str]): 91 | """ 92 | Individual image downloader. 93 | Args: 94 | - file (`str`): List containing the filename and the url of the file. 95 | """ 96 | try: 97 | os.makedirs(os.path.split(file[0])[0]) 98 | except FileExistsError: 99 | pass 100 | if os.path.isfile(f"{file[0]}.tmp"): 101 | os.remove(f"{file[0]}.tmp") 102 | await self._dlf(file) 103 | os.replace(f"{file[0]}.tmp", file[0]) 104 | 105 | async def _dlch(self, manga: str, chapter: str, urls: List[str], n: int = 0): 106 | dl = True 107 | self.jdir = jdir = os.path.join(self.ddir, manga, sanitize_filename(chapter)) 108 | if os.path.isdir(jdir): 109 | if self.overwrite: 110 | shutil.rmtree(jdir) 111 | else: 112 | dl = False 113 | if dl: 114 | dl = True 115 | if dl: 116 | files = [] 117 | for index, page in enumerate(urls): 118 | filename = os.path.join( 119 | self.ddir, 120 | manga, 121 | sanitize_filename(chapter), 122 | f"{index}.{get_extension(str(page))}", 123 | ).replace("\\", "/") 124 | files.append((filename, page)) 125 | fmt = ( 126 | chapter 127 | + " [{remaining_s:05.2f} secs, {rate_fmt:0>12}] " 128 | + "{bar}" 129 | + " [{n:03d}/{total:03d}, {percentage:03.0f}%]" 130 | ) 131 | await tqdm_asyncio.gather( 132 | *[self.dlf(file) for file in files], 133 | total=len(files), 134 | leave=True, 135 | unit=" img", 136 | disable=False, 137 | dynamic_ncols=True, 138 | smoothing=1, 139 | bar_format=fmt, 140 | ) 141 | 142 | def dlch(self, url: str): 143 | RP = r"const pages = \[(\s.+?)+?\s+\];" 144 | 145 | headers = { 146 | "user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1" 147 | } 148 | 149 | resp = req.get(url, headers=headers) 150 | wrong_json = re.search(RP, resp.text).group(0)[14:-1].replace("'", '"') 151 | wrong_json = re.sub(r"(.+?): ", r'"\1": ', wrong_json) 152 | wrong_json = re.sub(r"\",\s+}", r'"}', wrong_json) 153 | pages = re.sub(r"\},\s+]", r"}]", wrong_json) 154 | 155 | ms = soup(url) 156 | title = sanitize_text(ms.select_one("div.info h1").text) 157 | chapter = sanitize_text(ms.select_one("div.title div div").text) 158 | 159 | urls = [i["src"] for i in json.loads(pages)] 160 | asyncio.get_event_loop().run_until_complete( 161 | self._dlch(title, f"{USI.ch_id(url)} - {chapter}", urls) 162 | ) 163 | 164 | return self.jdir 165 | -------------------------------------------------------------------------------- /ura/src/exceptions.py: -------------------------------------------------------------------------------- 1 | def c_exc_str(cls: Exception) -> Exception: 2 | """Decorator to add the __str__ method to an exception. 3 | 4 | Args: 5 | - cls (`BaseException`): The exception to add the __str__ method to. 6 | 7 | Returns: 8 | `BaseException`: The exception to raise. 9 | """ 10 | cls.__str__ = lambda self: self.message 11 | return cls 12 | 13 | 14 | def c_exc(cls: Exception | object) -> Exception: 15 | """Decorator to raise a custom exception. 16 | 17 | This function gives the class an __init__ function that raises the exception. 18 | If the class does not inherit from any Exception, it will be automatically inherit from Exception. 19 | This function also wraps the Exception with `c_exc_str` method, for adding the `__str__` method. 20 | 21 | Args: 22 | - cls (`BaseException | Object`): The exception to modify. 23 | 24 | Returns: 25 | `BaseException`: The exception to raise. 26 | """ 27 | if cls.__mro__[-2] is BaseException: 28 | exc = cls.__mro__[1] 29 | else: 30 | exc = Exception 31 | 32 | def __init__(self, message: str) -> None: 33 | self.message = message 34 | exc.__init__(self.message) 35 | 36 | cls.__init__ = __init__ 37 | return c_exc_str(cls) 38 | -------------------------------------------------------------------------------- /ura/src/globals.py: -------------------------------------------------------------------------------- 1 | import locale 2 | import os 3 | import sys 4 | from os import get_terminal_size, makedirs, path 5 | from os.path import abspath as ap 6 | from os.path import dirname as dn 7 | 8 | import inquirer 9 | import msgpack 10 | import yaml 11 | 12 | try: 13 | TW = get_terminal_size().columns 14 | except OSError as e: 15 | TW = None 16 | 17 | CFLOP = "" 18 | """ 19 | ```mermaid 20 | flowchart LR 21 | A([Config]) --> B[Grab CFLOP] 22 | B --> C{Last item} 23 | C --> |false| D{File exists?} 24 | D --> |true| E([Read config file]) 25 | D --> |false| C 26 | C --> |true| F{OS?} 27 | F --> |Windows| G[Initialize config file
at first lookup path] --> E 28 | F --> |*nix| H{.AppImage?} 29 | H --> |true| I[Initialize config file
at second lookup path] --> E 30 | H --> |false| G 31 | ``` 32 | """ 33 | 34 | 35 | def init(idx: int) -> None: 36 | global CFG_PATH 37 | with open(path.join(dn(ap(__file__)), "cf_tpl.mp"), "rb") as f: 38 | cm = msgpack.unpackb(f.read(), raw=False, use_list=True) 39 | 40 | if sys.platform == "win32": 41 | ddir = os.path.join(os.path.join(os.environ["USERPROFILE"]), "Desktop", "Manga") 42 | else: 43 | ddir = os.path.join(os.path.expanduser("~"), "Manga") 44 | 45 | if TW: 46 | validate = False 47 | while not validate: 48 | if inquirer.list_input( 49 | message="Choose the path to download the chapter to", 50 | choices=[ 51 | [ddir, False], 52 | ["Input it myself", True], 53 | ], 54 | ): 55 | pd = input("Input the path to download the chapter to: ") 56 | if not path.isdir(pd): 57 | if inquirer.confirm( 58 | "The path does not exist. Do you want to make it?", 59 | default=False, 60 | ): 61 | makedirs(pd) 62 | validate = True 63 | ddir = pd 64 | else: 65 | validate = True 66 | 67 | cm["download_dir"] = ddir 68 | CFG_PATH = CFLOP[idx] 69 | with open(CFLOP[idx], "w") as f: 70 | f.write(yaml.dump(cm, indent=2)) 71 | 72 | 73 | if os.name != "posix": 74 | import ctypes 75 | 76 | POSIX = 0 77 | 78 | CFLOP = [ 79 | rf"{os.getcwd()}\ura.yml", 80 | rf"{os.getenv('USERPROFILE')}\AppData\Roaming\ura\config.yml", 81 | ] 82 | LOCALE = locale.windows_locale[ctypes.windll.kernel32.GetUserDefaultUILanguage()][ 83 | :2 84 | ] 85 | else: 86 | POSIX = 1 87 | CFLOP = [f"{os.getcwd()}/ura.yml", "~/.config/ura/config.yml", "~/.ura"] 88 | if xch := os.getenv("XDG_CONFIG_HOME"): 89 | CFLOP.insert(1, f"{xch}/ura/config.yml") 90 | LOCALE = locale.getdefaultlocale()[0][:2] 91 | 92 | 93 | CFG_PATH = None 94 | for i in CFLOP: 95 | if os.path.exists(str(i)): 96 | CFG_PATH = i 97 | break 98 | 99 | if CFG_PATH is None: 100 | if POSIX: 101 | try: 102 | from . import appimage 103 | except ImportError: 104 | from __init__ import appimage 105 | 106 | if appimage: 107 | init(1) 108 | else: 109 | init(0) 110 | else: 111 | init(0) 112 | -------------------------------------------------------------------------------- /ura/src/hc.yml: -------------------------------------------------------------------------------- 1 | random: 2 | - |- 3 | Y'shan't look back. 4 | - |- 5 | Written with <3 by Group: 96 | op = [] 97 | for i in ls: 98 | op.append(Align.center(i)) 99 | return Group(*op) 100 | 101 | def table(cols: list[str], rows: list[list[str]]): 102 | stb = STYLE_ALL["table"] 103 | box = getattr(rich.box, stb.pop("box")) 104 | 105 | new_cols = [] 106 | for title, col in zip(cols, itertools.cycle(stb.pop("columns"))): 107 | attr = {} 108 | for i in ["header_style", "style"]: 109 | attr[i] = getattr(C, col[i]) 110 | new_cols.append(Column(title, **attr, justify="center")) 111 | 112 | t = Table(*new_cols, **stb, **STYLE_ALL["all"], box=box) 113 | for i in rows: 114 | t.add_row(*[str(i) for i in i]) 115 | 116 | pp(t) 117 | -------------------------------------------------------------------------------- /ura/src/utils.py: -------------------------------------------------------------------------------- 1 | import ast 2 | import itertools 3 | import re 4 | import shlex 5 | import sys 6 | import unicodedata 7 | from datetime import datetime, timedelta 8 | from functools import lru_cache 9 | from os import makedirs, path 10 | from os.path import dirname as dn 11 | from os.path import realpath as rp 12 | from subprocess import call 13 | from time import strftime, strptime 14 | from typing import Any 15 | 16 | import arrow 17 | 18 | # Constants 19 | CATEGORIES = {"Cn"} 20 | PR = ["alpha", "beta", "rc"] 21 | 22 | # Derived Constants 23 | ALL_CHARS = (chr(i) for i in range(sys.maxunicode)) 24 | CCHARS = "".join(map(chr, itertools.chain(range(0x00, 0x20), range(0x7F, 0xA0)))) 25 | CCHARS_RE = re.compile("[%s]" % re.escape(CCHARS)) 26 | 27 | # Functions 28 | def inmd(p: str, ls: list[str] = None) -> str: 29 | """ "If Not `path.isdir`, Make Directories" 30 | 31 | Args: 32 | - p (`str`): The path to be created, if it does not exist. 33 | 34 | Returns: 35 | `str`: The path given. 36 | """ 37 | 38 | pd = path.dirname(p) 39 | if (pd) and (not path.isdir(pd)): 40 | makedirs(pd) 41 | if ls: 42 | ls.append(pd) 43 | return p 44 | 45 | 46 | def ivnd(var: Any, de: Any) -> Any: 47 | """If Var is None, return Default else var. 48 | 49 | Args: 50 | - var (`Any`): Variable to check if it is None. 51 | - de (`Any`): Default value to return if var is None. 52 | 53 | Returns: 54 | `Any`: var if var is not None else de. 55 | """ 56 | if var is None: 57 | return de 58 | return var 59 | 60 | 61 | def dnrp(file: str, n: int = 1) -> str: 62 | """ 63 | Get the directory component of a pathname by n times recursively then return it. 64 | 65 | Args: 66 | - file (`str`): File to get the directory of. 67 | - n (`int`, optional): Number of times to get up the directory???? Defaults to 1. 68 | 69 | Returns: 70 | `str`: The directory component got recursively by n times from the given pathname 71 | """ 72 | op = rp(file) 73 | for _ in range(n): 74 | op = dn(op) 75 | return op 76 | 77 | 78 | def dpop( 79 | d: dict[Any, Any], pop: list[int | tuple[str | int | tuple] | str], de: Any = None 80 | ) -> Any: 81 | """Iterate through the preferred order of precedence (`pop`) and see if the value exists in the dictionary. If it does, return it. If not, return `de`. 82 | 83 | Args: 84 | - d (`Dict[Any, Any]`): Dictionary to retrieve the value from. 85 | - pop (`list[int | tuple[str | int | tuple] | str]`): List of keys to iterate through. 86 | - de (`Any`, optional): Default object to be returned. Defaults to None. 87 | 88 | Returns: 89 | `Any`: Retrieved value. 90 | """ 91 | 92 | for i in pop: 93 | if op := d.get(i): 94 | return op 95 | return de 96 | 97 | 98 | @lru_cache 99 | def dt(dt: str, format: str) -> str: 100 | """Remove timezone from datetime and format it to ISO 8601 format. 101 | 102 | Args: 103 | - dt (`str`): Unformatted datetime string to be formatted to ISO 8601 format 104 | - format (`str`): The initial format of the datetime string 105 | 106 | Returns: 107 | `str`: Formatted datetime string 108 | """ 109 | 110 | op = dt 111 | if "ago" in dt and not format: 112 | arw = arrow.utcnow() 113 | op = arw.dehumanize(dt) 114 | tz = re.match(r"(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})([-+])(\d{2}):(\d{2})", op) 115 | if tz: 116 | iso, s, ho, mo = tz.groups() 117 | s = -1 if s == "-" else 1 118 | op = ( 119 | datetime.fromisoformat(iso) 120 | - (s * timedelta(hours=int(ho), minutes=int(mo))) 121 | ).strftime("%Y-%m-%dT%H:%M:%S") 122 | else: 123 | op = strftime("%Y-%m-%dT%H:%M:%S", strptime(dt, format)) 124 | return op 125 | 126 | 127 | @lru_cache 128 | def dt_ts(ts: str) -> str: 129 | """Convert the given unix timestamp to ISO 8601 format. 130 | 131 | Args: 132 | ts (str): unix timestamp to be converted to ISO 8601 format 133 | 134 | Returns: 135 | str: Formatted datetime string 136 | """ 137 | 138 | return (datetime.utcfromtimestamp(int(ts))).strftime("%Y-%m-%dT%H:%M:%S") 139 | 140 | 141 | def le(expr: str) -> Any: 142 | return ast.literal_eval(expr) if expr else expr 143 | 144 | 145 | def repl(s: str, repl_dict: dict[str, list[str]]) -> str: 146 | op = s 147 | for k, v in repl_dict.items(): 148 | for i in v: 149 | op = op.replace(i, k) 150 | return op 151 | 152 | 153 | def run(s: str): 154 | call(shlex.split(s)) 155 | 156 | 157 | # https://stackoverflow.com/a/93029 158 | def sanitize_text(s: str): 159 | return unicodedata.normalize("NFKD", CCHARS_RE.sub("", s)).strip() 160 | -------------------------------------------------------------------------------- /version.yml: -------------------------------------------------------------------------------- 1 | ls: 2 | - 0 3 | - 0 4 | - 0 5 | - 0 6 | - 2 7 | - 0 8 | str: 0.0.0.0-rc.0 9 | sv: 0.0.1-rc.0 10 | --------------------------------------------------------------------------------