├── config ├── resource └── privilege ├── app ├── server │ ├── lib │ │ ├── idna │ │ │ ├── py.typed │ │ │ ├── package_data.py │ │ │ ├── compat.py │ │ │ ├── __init__.py │ │ │ └── intranges.py │ │ ├── blinker │ │ │ ├── py.typed │ │ │ ├── __init__.py │ │ │ └── _utilities.py │ │ ├── certifi │ │ │ ├── py.typed │ │ │ ├── __init__.py │ │ │ └── __main__.py │ │ ├── click │ │ │ ├── py.typed │ │ │ ├── _utils.py │ │ │ ├── _textwrap.py │ │ │ └── globals.py │ │ ├── flask │ │ │ ├── py.typed │ │ │ ├── __main__.py │ │ │ ├── sansio │ │ │ │ └── README.md │ │ │ ├── signals.py │ │ │ ├── globals.py │ │ │ ├── logging.py │ │ │ └── __init__.py │ │ ├── jinja2 │ │ │ ├── py.typed │ │ │ ├── _identifier.py │ │ │ ├── defaults.py │ │ │ ├── constants.py │ │ │ ├── optimizer.py │ │ │ ├── __init__.py │ │ │ └── async_utils.py │ │ ├── mutagen │ │ │ ├── py.typed │ │ │ ├── _tools │ │ │ │ ├── __init__.py │ │ │ │ ├── mutagen_inspect.py │ │ │ │ ├── _util.py │ │ │ │ └── moggsplit.py │ │ │ ├── mp4 │ │ │ │ └── _util.py │ │ │ ├── __init__.py │ │ │ ├── _riff.py │ │ │ ├── m4a.py │ │ │ └── trueaudio.py │ │ ├── watchdog │ │ │ ├── py.typed │ │ │ ├── __init__.py │ │ │ ├── utils │ │ │ │ ├── process_watcher.py │ │ │ │ ├── platform.py │ │ │ │ └── event_debouncer.py │ │ │ └── version.py │ │ ├── werkzeug │ │ │ ├── py.typed │ │ │ ├── sansio │ │ │ │ └── __init__.py │ │ │ ├── middleware │ │ │ │ ├── __init__.py │ │ │ │ └── dispatcher.py │ │ │ ├── debug │ │ │ │ └── shared │ │ │ │ │ ├── less.png │ │ │ │ │ ├── more.png │ │ │ │ │ ├── console.png │ │ │ │ │ └── ICON_LICENSE.md │ │ │ ├── wrappers │ │ │ │ └── __init__.py │ │ │ ├── __init__.py │ │ │ ├── user_agent.py │ │ │ └── datastructures │ │ │ │ └── __init__.py │ │ ├── itsdangerous │ │ │ ├── py.typed │ │ │ ├── _json.py │ │ │ ├── __init__.py │ │ │ ├── encoding.py │ │ │ └── url_safe.py │ │ ├── markupsafe │ │ │ ├── py.typed │ │ │ ├── _speedups.pyi │ │ │ ├── _speedups.cp312-win_amd64.pyd │ │ │ └── _native.py │ │ ├── charset_normalizer │ │ │ ├── py.typed │ │ │ ├── md.cp312-win_amd64.pyd │ │ │ ├── __main__.py │ │ │ ├── md__mypyc.cp312-win_amd64.pyd │ │ │ ├── version.py │ │ │ ├── cli │ │ │ │ └── __init__.py │ │ │ ├── __init__.py │ │ │ └── legacy.py │ │ ├── urllib3 │ │ │ ├── contrib │ │ │ │ ├── __init__.py │ │ │ │ └── emscripten │ │ │ │ │ ├── request.py │ │ │ │ │ └── __init__.py │ │ │ ├── py.typed │ │ │ ├── _version.py │ │ │ ├── util │ │ │ │ ├── __init__.py │ │ │ │ ├── util.py │ │ │ │ └── proxy.py │ │ │ ├── http2 │ │ │ │ ├── __init__.py │ │ │ │ └── probe.py │ │ │ └── filepost.py │ │ ├── flask-3.0.0.dist-info │ │ │ ├── REQUESTED │ │ │ ├── INSTALLER │ │ │ ├── entry_points.txt │ │ │ ├── WHEEL │ │ │ └── LICENSE.rst │ │ ├── idna-3.11.dist-info │ │ │ ├── INSTALLER │ │ │ ├── WHEEL │ │ │ ├── RECORD │ │ │ └── licenses │ │ │ │ └── LICENSE.md │ │ ├── mutagen-1.47.0.dist-info │ │ │ ├── REQUESTED │ │ │ ├── INSTALLER │ │ │ ├── top_level.txt │ │ │ ├── WHEEL │ │ │ ├── entry_points.txt │ │ │ └── METADATA │ │ ├── requests-2.32.5.dist-info │ │ │ ├── REQUESTED │ │ │ ├── INSTALLER │ │ │ ├── top_level.txt │ │ │ ├── WHEEL │ │ │ └── RECORD │ │ ├── watchdog-4.0.0.dist-info │ │ │ ├── REQUESTED │ │ │ ├── INSTALLER │ │ │ ├── top_level.txt │ │ │ ├── entry_points.txt │ │ │ ├── WHEEL │ │ │ ├── COPYING │ │ │ └── AUTHORS │ │ ├── blinker-1.9.0.dist-info │ │ │ ├── INSTALLER │ │ │ ├── WHEEL │ │ │ ├── RECORD │ │ │ ├── LICENSE.txt │ │ │ └── METADATA │ │ ├── click-8.3.1.dist-info │ │ │ ├── INSTALLER │ │ │ ├── WHEEL │ │ │ ├── licenses │ │ │ │ └── LICENSE.txt │ │ │ ├── RECORD │ │ │ └── METADATA │ │ ├── colorama-0.4.6.dist-info │ │ │ ├── INSTALLER │ │ │ ├── WHEEL │ │ │ ├── licenses │ │ │ │ └── LICENSE.txt │ │ │ └── RECORD │ │ ├── jinja2-3.1.6.dist-info │ │ │ ├── INSTALLER │ │ │ ├── entry_points.txt │ │ │ ├── WHEEL │ │ │ ├── licenses │ │ │ │ └── LICENSE.txt │ │ │ └── METADATA │ │ ├── urllib3-2.6.0.dist-info │ │ │ ├── INSTALLER │ │ │ ├── WHEEL │ │ │ └── licenses │ │ │ │ └── LICENSE.txt │ │ ├── werkzeug-3.1.4.dist-info │ │ │ ├── INSTALLER │ │ │ ├── WHEEL │ │ │ └── licenses │ │ │ │ └── LICENSE.txt │ │ ├── certifi-2025.11.12.dist-info │ │ │ ├── INSTALLER │ │ │ ├── top_level.txt │ │ │ ├── WHEEL │ │ │ ├── RECORD │ │ │ ├── licenses │ │ │ │ └── LICENSE │ │ │ └── METADATA │ │ ├── itsdangerous-2.2.0.dist-info │ │ │ ├── INSTALLER │ │ │ ├── WHEEL │ │ │ ├── LICENSE.txt │ │ │ ├── RECORD │ │ │ └── METADATA │ │ ├── markupsafe-3.0.3.dist-info │ │ │ ├── INSTALLER │ │ │ ├── top_level.txt │ │ │ ├── WHEEL │ │ │ ├── RECORD │ │ │ ├── licenses │ │ │ │ └── LICENSE.txt │ │ │ └── METADATA │ │ ├── charset_normalizer-3.4.4.dist-info │ │ │ ├── INSTALLER │ │ │ ├── top_level.txt │ │ │ ├── entry_points.txt │ │ │ ├── WHEEL │ │ │ ├── licenses │ │ │ │ └── LICENSE │ │ │ └── RECORD │ │ ├── bin │ │ │ └── flask.exe │ │ ├── colorama │ │ │ ├── tests │ │ │ │ ├── __init__.py │ │ │ │ ├── utils.py │ │ │ │ ├── isatty_test.py │ │ │ │ └── ansi_test.py │ │ │ ├── __init__.py │ │ │ └── ansi.py │ │ ├── requests │ │ │ ├── __version__.py │ │ │ ├── certs.py │ │ │ ├── hooks.py │ │ │ ├── packages.py │ │ │ ├── _internal_utils.py │ │ │ └── compat.py │ │ └── share │ │ │ └── man │ │ │ └── man1 │ │ │ ├── mutagen-pony.1 │ │ │ ├── mutagen-inspect.1 │ │ │ ├── mid3iconv.1 │ │ │ ├── moggsplit.1 │ │ │ └── mid3cp.1 │ └── requirements.txt ├── www │ ├── .DS_Store │ └── static │ │ ├── images │ │ ├── BG.png │ │ └── ICON_256.PNG │ │ ├── css │ │ └── font-awesome │ │ │ └── webfonts │ │ │ ├── fa-brands-400.ttf │ │ │ ├── fa-regular-400.ttf │ │ │ ├── fa-solid-900.ttf │ │ │ ├── fa-solid-900.woff2 │ │ │ ├── fa-brands-400.woff2 │ │ │ ├── fa-regular-400.woff2 │ │ │ ├── fa-v4compatibility.ttf │ │ │ └── fa-v4compatibility.woff2 │ │ └── manifest.json └── ui │ ├── images │ ├── icon_256.png │ └── icon_64.png │ └── config ├── extensions └── preview-cgi │ ├── config │ ├── resource │ └── privilege │ ├── app │ ├── ui │ │ ├── js │ │ │ ├── config.js │ │ │ └── utils.js │ │ ├── .DS_Store │ │ ├── images │ │ │ ├── .DS_Store │ │ │ ├── icon_256.png │ │ │ └── icon_64.png │ │ ├── css │ │ │ └── font-awesome │ │ │ │ └── webfonts │ │ │ │ ├── fa-brands-400.ttf │ │ │ │ ├── fa-regular-400.ttf │ │ │ │ ├── fa-solid-900.ttf │ │ │ │ ├── fa-solid-900.woff2 │ │ │ │ ├── fa-brands-400.woff2 │ │ │ │ ├── fa-regular-400.woff2 │ │ │ │ ├── fa-v4compatibility.ttf │ │ │ │ └── fa-v4compatibility.woff2 │ │ └── config │ └── .DS_Store │ ├── ICON.PNG │ ├── ICON_256.PNG │ ├── cmd │ ├── install_init │ ├── upgrade_init │ ├── uninstall_init │ ├── upgrade_callback │ ├── uninstall_callback │ ├── config_callback │ ├── config_init │ ├── install_callback │ └── main │ ├── wizard │ └── install │ └── manifest ├── ICON.PNG ├── ICON_256.PNG ├── .gitignore ├── .vscode ├── settings.json └── launch.json ├── cmd ├── install_callback ├── install_init ├── uninstall_init ├── upgrade_callback ├── upgrade_init ├── config_init ├── config_callback └── uninstall_callback ├── wizard ├── install └── uninstall ├── manifest ├── README.md └── .github └── workflows └── extensions-build.yml /config/resource: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /app/server/lib/idna/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/blinker/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/certifi/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/click/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/flask/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/jinja2/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/mutagen/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/watchdog/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/werkzeug/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/itsdangerous/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/markupsafe/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/charset_normalizer/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/urllib3/contrib/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/werkzeug/sansio/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/flask-3.0.0.dist-info/REQUESTED: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/werkzeug/middleware/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extensions/preview-cgi/config/resource: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /app/server/lib/idna-3.11.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /app/server/lib/mutagen-1.47.0.dist-info/REQUESTED: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/requests-2.32.5.dist-info/REQUESTED: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/watchdog-4.0.0.dist-info/REQUESTED: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/server/lib/blinker-1.9.0.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /app/server/lib/click-8.3.1.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /app/server/lib/colorama-0.4.6.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /app/server/lib/flask-3.0.0.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /app/server/lib/jinja2-3.1.6.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /app/server/lib/mutagen-1.47.0.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /app/server/lib/requests-2.32.5.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /app/server/lib/urllib3-2.6.0.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /app/server/lib/watchdog-4.0.0.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /app/server/lib/werkzeug-3.1.4.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /app/server/lib/certifi-2025.11.12.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /app/server/lib/idna/package_data.py: -------------------------------------------------------------------------------- 1 | __version__ = "3.11" 2 | -------------------------------------------------------------------------------- /app/server/lib/itsdangerous-2.2.0.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /app/server/lib/markupsafe-3.0.3.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /ICON.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/ICON.PNG -------------------------------------------------------------------------------- /app/server/lib/charset_normalizer-3.4.4.dist-info/INSTALLER: -------------------------------------------------------------------------------- 1 | pip 2 | -------------------------------------------------------------------------------- /app/server/lib/mutagen-1.47.0.dist-info/top_level.txt: -------------------------------------------------------------------------------- 1 | mutagen 2 | -------------------------------------------------------------------------------- /app/server/lib/requests-2.32.5.dist-info/top_level.txt: -------------------------------------------------------------------------------- 1 | requests 2 | -------------------------------------------------------------------------------- /app/server/lib/watchdog-4.0.0.dist-info/top_level.txt: -------------------------------------------------------------------------------- 1 | watchdog 2 | -------------------------------------------------------------------------------- /app/server/lib/certifi-2025.11.12.dist-info/top_level.txt: -------------------------------------------------------------------------------- 1 | certifi 2 | -------------------------------------------------------------------------------- /app/server/lib/markupsafe-3.0.3.dist-info/top_level.txt: -------------------------------------------------------------------------------- 1 | markupsafe 2 | -------------------------------------------------------------------------------- /ICON_256.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/ICON_256.PNG -------------------------------------------------------------------------------- /app/server/lib/flask/__main__.py: -------------------------------------------------------------------------------- 1 | from .cli import main 2 | 3 | main() 4 | -------------------------------------------------------------------------------- /app/server/lib/charset_normalizer-3.4.4.dist-info/top_level.txt: -------------------------------------------------------------------------------- 1 | charset_normalizer 2 | -------------------------------------------------------------------------------- /app/server/lib/markupsafe/_speedups.pyi: -------------------------------------------------------------------------------- 1 | def _escape_inner(s: str, /) -> str: ... 2 | -------------------------------------------------------------------------------- /app/www/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/www/.DS_Store -------------------------------------------------------------------------------- /config/privilege: -------------------------------------------------------------------------------- 1 | { 2 | "defaults": { 3 | "run-as": "root" 4 | } 5 | } -------------------------------------------------------------------------------- /extensions/preview-cgi/app/ui/js/config.js: -------------------------------------------------------------------------------- 1 | window.PRECONFIGURED_PASSWORD = null; 2 | -------------------------------------------------------------------------------- /app/server/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==3.0.0 2 | mutagen==1.47.0 3 | requests==2.31.0 4 | watchdog==4.0.0 -------------------------------------------------------------------------------- /app/ui/images/icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/ui/images/icon_256.png -------------------------------------------------------------------------------- /app/ui/images/icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/ui/images/icon_64.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | test_tmp 3 | fnpack.exe 4 | 2fmusic.fpk 5 | 2fmusic-preview.fpk 6 | fndepot 7 | -------------------------------------------------------------------------------- /app/server/lib/bin/flask.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/server/lib/bin/flask.exe -------------------------------------------------------------------------------- /app/server/lib/flask-3.0.0.dist-info/entry_points.txt: -------------------------------------------------------------------------------- 1 | [console_scripts] 2 | flask=flask.cli:main 3 | 4 | -------------------------------------------------------------------------------- /app/www/static/images/BG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/www/static/images/BG.png -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.analysis.extraPaths": [ 3 | "./app/server/lib" 4 | ] 5 | } -------------------------------------------------------------------------------- /extensions/preview-cgi/ICON.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/extensions/preview-cgi/ICON.PNG -------------------------------------------------------------------------------- /app/www/static/images/ICON_256.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/www/static/images/ICON_256.PNG -------------------------------------------------------------------------------- /app/server/lib/colorama/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. 2 | -------------------------------------------------------------------------------- /cmd/install_callback: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script is called after the user installs the application. 4 | 5 | exit 0 -------------------------------------------------------------------------------- /cmd/install_init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script is called before the user installs the application. 4 | 5 | exit 0 -------------------------------------------------------------------------------- /cmd/uninstall_init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script is called after the user uninstalls the application. 4 | 5 | exit 0 -------------------------------------------------------------------------------- /cmd/upgrade_callback: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script is called after the user upgrades the application. 4 | 5 | exit 0 -------------------------------------------------------------------------------- /cmd/upgrade_init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script is called before the user upgrades the application. 4 | 5 | exit 0 -------------------------------------------------------------------------------- /extensions/preview-cgi/ICON_256.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/extensions/preview-cgi/ICON_256.PNG -------------------------------------------------------------------------------- /extensions/preview-cgi/app/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/extensions/preview-cgi/app/.DS_Store -------------------------------------------------------------------------------- /extensions/preview-cgi/config/privilege: -------------------------------------------------------------------------------- 1 | { 2 | "defaults": 3 | { 4 | "run-as": "package" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /app/server/lib/jinja2-3.1.6.dist-info/entry_points.txt: -------------------------------------------------------------------------------- 1 | [babel.extractors] 2 | jinja2=jinja2.ext:babel_extract[i18n] 3 | 4 | -------------------------------------------------------------------------------- /extensions/preview-cgi/app/ui/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/extensions/preview-cgi/app/ui/.DS_Store -------------------------------------------------------------------------------- /app/server/lib/urllib3/py.typed: -------------------------------------------------------------------------------- 1 | # Instruct type checkers to look for inline type annotations in this package. 2 | # See PEP 561. 3 | -------------------------------------------------------------------------------- /app/server/lib/watchdog-4.0.0.dist-info/entry_points.txt: -------------------------------------------------------------------------------- 1 | [console_scripts] 2 | watchmedo = watchdog.watchmedo:main [watchmedo] 3 | -------------------------------------------------------------------------------- /app/server/lib/idna-3.11.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: flit 3.12.0 3 | Root-Is-Purelib: true 4 | Tag: py3-none-any 5 | -------------------------------------------------------------------------------- /app/server/lib/blinker-1.9.0.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: flit 3.10.1 3 | Root-Is-Purelib: true 4 | Tag: py3-none-any 5 | -------------------------------------------------------------------------------- /app/server/lib/charset_normalizer-3.4.4.dist-info/entry_points.txt: -------------------------------------------------------------------------------- 1 | [console_scripts] 2 | normalizer = charset_normalizer.cli:cli_detect 3 | -------------------------------------------------------------------------------- /app/server/lib/click-8.3.1.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: flit 3.12.0 3 | Root-Is-Purelib: true 4 | Tag: py3-none-any 5 | -------------------------------------------------------------------------------- /app/server/lib/flask-3.0.0.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: flit 3.9.0 3 | Root-Is-Purelib: true 4 | Tag: py3-none-any 5 | -------------------------------------------------------------------------------- /app/server/lib/jinja2-3.1.6.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: flit 3.11.0 3 | Root-Is-Purelib: true 4 | Tag: py3-none-any 5 | -------------------------------------------------------------------------------- /app/server/lib/werkzeug-3.1.4.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: flit 3.12.0 3 | Root-Is-Purelib: true 4 | Tag: py3-none-any 5 | -------------------------------------------------------------------------------- /app/server/lib/werkzeug/debug/shared/less.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/server/lib/werkzeug/debug/shared/less.png -------------------------------------------------------------------------------- /app/server/lib/werkzeug/debug/shared/more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/server/lib/werkzeug/debug/shared/more.png -------------------------------------------------------------------------------- /extensions/preview-cgi/app/ui/images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/extensions/preview-cgi/app/ui/images/.DS_Store -------------------------------------------------------------------------------- /extensions/preview-cgi/cmd/install_init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script is called before the user installs the application. 4 | 5 | exit 0 -------------------------------------------------------------------------------- /extensions/preview-cgi/cmd/upgrade_init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script is called before the user upgrades the application. 4 | 5 | exit 0 -------------------------------------------------------------------------------- /app/server/lib/certifi/__init__.py: -------------------------------------------------------------------------------- 1 | from .core import contents, where 2 | 3 | __all__ = ["contents", "where"] 4 | __version__ = "2025.11.12" 5 | -------------------------------------------------------------------------------- /app/server/lib/itsdangerous-2.2.0.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: flit 3.9.0 3 | Root-Is-Purelib: true 4 | Tag: py3-none-any 5 | -------------------------------------------------------------------------------- /app/server/lib/urllib3-2.6.0.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: hatchling 1.28.0 3 | Root-Is-Purelib: true 4 | Tag: py3-none-any 5 | -------------------------------------------------------------------------------- /app/server/lib/werkzeug/debug/shared/console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/server/lib/werkzeug/debug/shared/console.png -------------------------------------------------------------------------------- /extensions/preview-cgi/app/ui/images/icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/extensions/preview-cgi/app/ui/images/icon_256.png -------------------------------------------------------------------------------- /extensions/preview-cgi/app/ui/images/icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/extensions/preview-cgi/app/ui/images/icon_64.png -------------------------------------------------------------------------------- /extensions/preview-cgi/cmd/uninstall_init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script is called after the user uninstalls the application. 4 | 5 | exit 0 -------------------------------------------------------------------------------- /extensions/preview-cgi/cmd/upgrade_callback: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script is called after the user upgrades the application. 4 | 5 | exit 0 -------------------------------------------------------------------------------- /cmd/config_init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script is called before the user change environment variables in application setting page. 4 | 5 | exit 0 -------------------------------------------------------------------------------- /extensions/preview-cgi/cmd/uninstall_callback: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script is called after the user uninstalls the application. 4 | 5 | exit 0 -------------------------------------------------------------------------------- /app/server/lib/mutagen-1.47.0.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: bdist_wheel (0.38.4) 3 | Root-Is-Purelib: true 4 | Tag: py3-none-any 5 | 6 | -------------------------------------------------------------------------------- /app/server/lib/requests-2.32.5.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: setuptools (80.9.0) 3 | Root-Is-Purelib: true 4 | Tag: py3-none-any 5 | 6 | -------------------------------------------------------------------------------- /cmd/config_callback: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script is called after the user change environment variables in application setting page. 4 | 5 | exit 0 -------------------------------------------------------------------------------- /app/server/lib/certifi-2025.11.12.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: setuptools (80.9.0) 3 | Root-Is-Purelib: true 4 | Tag: py3-none-any 5 | 6 | -------------------------------------------------------------------------------- /app/server/lib/charset_normalizer/md.cp312-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/server/lib/charset_normalizer/md.cp312-win_amd64.pyd -------------------------------------------------------------------------------- /app/server/lib/markupsafe/_speedups.cp312-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/server/lib/markupsafe/_speedups.cp312-win_amd64.pyd -------------------------------------------------------------------------------- /app/server/lib/watchdog-4.0.0.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: bdist_wheel (0.42.0) 3 | Root-Is-Purelib: true 4 | Tag: py3-none-win_amd64 5 | 6 | -------------------------------------------------------------------------------- /app/server/lib/markupsafe-3.0.3.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: setuptools (80.9.0) 3 | Root-Is-Purelib: false 4 | Tag: cp312-cp312-win_amd64 5 | 6 | -------------------------------------------------------------------------------- /app/www/static/css/font-awesome/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/www/static/css/font-awesome/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /app/www/static/css/font-awesome/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/www/static/css/font-awesome/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /app/www/static/css/font-awesome/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/www/static/css/font-awesome/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /app/www/static/css/font-awesome/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/www/static/css/font-awesome/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /app/server/lib/colorama-0.4.6.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: hatchling 1.11.1 3 | Root-Is-Purelib: true 4 | Tag: py2-none-any 5 | Tag: py3-none-any 6 | -------------------------------------------------------------------------------- /app/www/static/css/font-awesome/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/www/static/css/font-awesome/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /app/www/static/css/font-awesome/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/www/static/css/font-awesome/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /app/server/lib/charset_normalizer-3.4.4.dist-info/WHEEL: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: setuptools (80.9.0) 3 | Root-Is-Purelib: false 4 | Tag: cp312-cp312-win_amd64 5 | 6 | -------------------------------------------------------------------------------- /app/server/lib/charset_normalizer/__main__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from .cli import cli_detect 4 | 5 | if __name__ == "__main__": 6 | cli_detect() 7 | -------------------------------------------------------------------------------- /app/server/lib/charset_normalizer/md__mypyc.cp312-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/server/lib/charset_normalizer/md__mypyc.cp312-win_amd64.pyd -------------------------------------------------------------------------------- /app/www/static/css/font-awesome/webfonts/fa-v4compatibility.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/www/static/css/font-awesome/webfonts/fa-v4compatibility.ttf -------------------------------------------------------------------------------- /extensions/preview-cgi/cmd/config_callback: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script is called after the user change environment variables in application setting page. 4 | 5 | exit 0 -------------------------------------------------------------------------------- /extensions/preview-cgi/cmd/config_init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script is called before the user change environment variables in application setting page. 4 | 5 | exit 0 -------------------------------------------------------------------------------- /app/www/static/css/font-awesome/webfonts/fa-v4compatibility.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/app/www/static/css/font-awesome/webfonts/fa-v4compatibility.woff2 -------------------------------------------------------------------------------- /app/server/lib/charset_normalizer/version.py: -------------------------------------------------------------------------------- 1 | """ 2 | Expose version 3 | """ 4 | 5 | from __future__ import annotations 6 | 7 | __version__ = "3.4.4" 8 | VERSION = __version__.split(".") 9 | -------------------------------------------------------------------------------- /app/server/lib/werkzeug/wrappers/__init__.py: -------------------------------------------------------------------------------- 1 | from .request import Request as Request 2 | from .response import Response as Response 3 | from .response import ResponseStream as ResponseStream 4 | -------------------------------------------------------------------------------- /extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-v4compatibility.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-v4compatibility.ttf -------------------------------------------------------------------------------- /extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-v4compatibility.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuexps/2FMusic/HEAD/extensions/preview-cgi/app/ui/css/font-awesome/webfonts/fa-v4compatibility.woff2 -------------------------------------------------------------------------------- /app/server/lib/charset_normalizer/cli/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from .__main__ import cli_detect, query_yes_no 4 | 5 | __all__ = ( 6 | "cli_detect", 7 | "query_yes_no", 8 | ) 9 | -------------------------------------------------------------------------------- /app/server/lib/werkzeug/__init__.py: -------------------------------------------------------------------------------- 1 | from .serving import run_simple as run_simple 2 | from .test import Client as Client 3 | from .wrappers import Request as Request 4 | from .wrappers import Response as Response 5 | -------------------------------------------------------------------------------- /app/server/lib/markupsafe/_native.py: -------------------------------------------------------------------------------- 1 | def _escape_inner(s: str, /) -> str: 2 | return ( 3 | s.replace("&", "&") 4 | .replace(">", ">") 5 | .replace("<", "<") 6 | .replace("'", "'") 7 | .replace('"', """) 8 | ) 9 | -------------------------------------------------------------------------------- /cmd/uninstall_callback: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### This script is called after the user uninstalls the application. 4 | 5 | wizard_data_action="$wizard_data_action" 6 | 7 | if [ "${wizard_data_action}" = "delete" ]; then 8 | rm -rf "${TRIM_PKGVAR}" 9 | fi 10 | 11 | exit 0 -------------------------------------------------------------------------------- /app/server/lib/flask/sansio/README.md: -------------------------------------------------------------------------------- 1 | # Sansio 2 | 3 | This folder contains code that can be used by alternative Flask 4 | implementations, for example Quart. The code therefore cannot do any 5 | IO, nor be part of a likely IO path. Finally this code cannot use the 6 | Flask globals. 7 | -------------------------------------------------------------------------------- /extensions/preview-cgi/cmd/install_callback: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CONFIG_FILE="${TRIM_APPDEST}/ui/js/config.js" 4 | if [ -n "${wizard_password}" ]; then 5 | echo "window.PRECONFIGURED_PASSWORD = \"${wizard_password}\";" > "${CONFIG_FILE}" 6 | fi 7 | chmod 644 "${CONFIG_FILE}" 8 | exit 0 -------------------------------------------------------------------------------- /app/server/lib/werkzeug/debug/shared/ICON_LICENSE.md: -------------------------------------------------------------------------------- 1 | Silk icon set 1.3 by Mark James 2 | 3 | http://www.famfamfam.com/lab/icons/silk/ 4 | 5 | License: [CC-BY-2.5](https://creativecommons.org/licenses/by/2.5/) 6 | or [CC-BY-3.0](https://creativecommons.org/licenses/by/3.0/) 7 | -------------------------------------------------------------------------------- /app/server/lib/colorama/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. 2 | from .initialise import init, deinit, reinit, colorama_text, just_fix_windows_console 3 | from .ansi import Fore, Back, Style, Cursor 4 | from .ansitowin32 import AnsiToWin32 5 | 6 | __version__ = '0.4.6' 7 | 8 | -------------------------------------------------------------------------------- /app/server/lib/certifi/__main__.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from certifi import contents, where 4 | 5 | parser = argparse.ArgumentParser() 6 | parser.add_argument("-c", "--contents", action="store_true") 7 | args = parser.parse_args() 8 | 9 | if args.contents: 10 | print(contents()) 11 | else: 12 | print(where()) 13 | -------------------------------------------------------------------------------- /app/server/lib/mutagen/_tools/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Christoph Reiter 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | -------------------------------------------------------------------------------- /app/ui/config: -------------------------------------------------------------------------------- 1 | { 2 | ".url": { 3 | "2fmusic.Application": { 4 | "title": "2FMusic", 5 | "icon": "images/icon_{0}.png", 6 | "type": "url", 7 | "protocol": "http", 8 | "port": "23237", 9 | "url": "/", 10 | "allUsers": false, 11 | "noDisplay": false 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /app/server/lib/mutagen-1.47.0.dist-info/entry_points.txt: -------------------------------------------------------------------------------- 1 | [console_scripts] 2 | mid3cp = mutagen._tools.mid3cp:entry_point 3 | mid3iconv = mutagen._tools.mid3iconv:entry_point 4 | mid3v2 = mutagen._tools.mid3v2:entry_point 5 | moggsplit = mutagen._tools.moggsplit:entry_point 6 | mutagen-inspect = mutagen._tools.mutagen_inspect:entry_point 7 | mutagen-pony = mutagen._tools.mutagen_pony:entry_point 8 | -------------------------------------------------------------------------------- /extensions/preview-cgi/wizard/install: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "stepTitle": "主程序认证配置", 4 | "items": [ 5 | { 6 | "type": "password", 7 | "field": "wizard_password", 8 | "label": "请输入 2FMusic 主程序的访问密码", 9 | "rules": [ 10 | { 11 | "required": true, 12 | "message": "请输入密码" 13 | } 14 | ] 15 | } 16 | ] 17 | } 18 | ] -------------------------------------------------------------------------------- /app/server/lib/idna/compat.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Union 2 | 3 | from .core import decode, encode 4 | 5 | 6 | def ToASCII(label: str) -> bytes: 7 | return encode(label) 8 | 9 | 10 | def ToUnicode(label: Union[bytes, bytearray]) -> str: 11 | return decode(label) 12 | 13 | 14 | def nameprep(s: Any) -> None: 15 | raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol") 16 | -------------------------------------------------------------------------------- /app/server/lib/blinker/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from .base import ANY 4 | from .base import default_namespace 5 | from .base import NamedSignal 6 | from .base import Namespace 7 | from .base import Signal 8 | from .base import signal 9 | 10 | __all__ = [ 11 | "ANY", 12 | "default_namespace", 13 | "NamedSignal", 14 | "Namespace", 15 | "Signal", 16 | "signal", 17 | ] 18 | -------------------------------------------------------------------------------- /wizard/install: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "stepTitle": "访问密码设置", 4 | "items": [ 5 | { 6 | "type": "password", 7 | "field": "wizard_password", 8 | "label": "设置密码", 9 | "rules": [ 10 | { 11 | "required": true, 12 | "message": "请输入密码" 13 | }, 14 | { 15 | "min": 6, 16 | "message": "密码长度不能少于6位" 17 | } 18 | ] 19 | } 20 | ] 21 | } 22 | ] -------------------------------------------------------------------------------- /app/www/static/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "2FMusic", 3 | "short_name": "2FMusic", 4 | "description": "2FMusic 本地播放器", 5 | "start_url": "/", 6 | "display": "standalone", 7 | "background_color": "#000000", 8 | "theme_color": "#1db954", 9 | "orientation": "any", 10 | "icons": [ 11 | { 12 | "src": "/static/images/ICON_256.PNG", 13 | "sizes": "256x256", 14 | "type": "image/png" 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /app/server/lib/requests/__version__.py: -------------------------------------------------------------------------------- 1 | # .-. .-. .-. . . .-. .-. .-. .-. 2 | # |( |- |.| | | |- `-. | `-. 3 | # ' ' `-' `-`.`-' `-' `-' ' `-' 4 | 5 | __title__ = "requests" 6 | __description__ = "Python HTTP for Humans." 7 | __url__ = "https://requests.readthedocs.io" 8 | __version__ = "2.32.5" 9 | __build__ = 0x023205 10 | __author__ = "Kenneth Reitz" 11 | __author_email__ = "me@kennethreitz.org" 12 | __license__ = "Apache-2.0" 13 | __copyright__ = "Copyright Kenneth Reitz" 14 | __cake__ = "\u2728 \U0001f370 \u2728" 15 | -------------------------------------------------------------------------------- /app/server/lib/requests/certs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | requests.certs 5 | ~~~~~~~~~~~~~~ 6 | 7 | This module returns the preferred default CA certificate bundle. There is 8 | only one — the one from the certifi package. 9 | 10 | If you are packaging Requests, e.g., for a Linux distribution or a managed 11 | environment, you can change the definition of where() to return a separately 12 | packaged CA bundle. 13 | """ 14 | from certifi import where 15 | 16 | if __name__ == "__main__": 17 | print(where()) 18 | -------------------------------------------------------------------------------- /app/server/lib/itsdangerous/_json.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import json as _json 4 | import typing as t 5 | 6 | 7 | class _CompactJSON: 8 | """Wrapper around json module that strips whitespace.""" 9 | 10 | @staticmethod 11 | def loads(payload: str | bytes) -> t.Any: 12 | return _json.loads(payload) 13 | 14 | @staticmethod 15 | def dumps(obj: t.Any, **kwargs: t.Any) -> str: 16 | kwargs.setdefault("ensure_ascii", False) 17 | kwargs.setdefault("separators", (",", ":")) 18 | return _json.dumps(obj, **kwargs) 19 | -------------------------------------------------------------------------------- /extensions/preview-cgi/manifest: -------------------------------------------------------------------------------- 1 | appname = 2fmusic-preview 2 | version = 0.0.2 3 | display_name = 2FMusic Preview 4 | desc = """ 5 |

2FMusic 预览扩展 (CGI版)

6 |

Web端文件管理器双击预览播放拓展。

7 |

依赖:2FMusic

8 |

注意:此拓展会导致移动端APP音乐播放器失效!

9 | """ 10 | arch = x86_64 11 | maintainer = yuexps 12 | maintainer_url = https://github.com/yuexps/2FMusic 13 | distributor = yuexps 14 | distributor_url = https://www.2fstore.cfd 15 | source = thirdparty 16 | desktop_uidir = ui 17 | install_dep_apps = 2fmusic 18 | -------------------------------------------------------------------------------- /app/server/lib/urllib3/contrib/emscripten/request.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from dataclasses import dataclass, field 4 | 5 | from ..._base_connection import _TYPE_BODY 6 | 7 | 8 | @dataclass 9 | class EmscriptenRequest: 10 | method: str 11 | url: str 12 | params: dict[str, str] | None = None 13 | body: _TYPE_BODY | None = None 14 | headers: dict[str, str] = field(default_factory=dict) 15 | timeout: float = 0 16 | decode_content: bool = True 17 | 18 | def set_header(self, name: str, value: str) -> None: 19 | self.headers[name.capitalize()] = value 20 | 21 | def set_body(self, body: _TYPE_BODY | None) -> None: 22 | self.body = body 23 | -------------------------------------------------------------------------------- /app/server/lib/watchdog-4.0.0.dist-info/COPYING: -------------------------------------------------------------------------------- 1 | Copyright 2011 Yesudeep Mangalapilly 2 | Copyright 2012 Google, Inc & contributors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | -------------------------------------------------------------------------------- /app/server/lib/watchdog/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Yesudeep Mangalapilly 2 | # Copyright 2012 Google, Inc & contributors. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | -------------------------------------------------------------------------------- /extensions/preview-cgi/app/ui/config: -------------------------------------------------------------------------------- 1 | { 2 | ".url": { 3 | "2fmusic-preview.play": { 4 | "title": "播放音乐 (2FMusic CGI)", 5 | "icon": "images/icon_{0}.png", 6 | "type": "iframe", 7 | "url": "/cgi/ThirdParty/2fmusic-preview/index.cgi", 8 | "allUsers": false, 9 | "fileTypes": [ 10 | "mp3", 11 | "flac", 12 | "wav", 13 | "ogg", 14 | "m4a", 15 | "ape" 16 | ], 17 | "control": { 18 | "fullUrlPerm": "readonly", 19 | "pathPerm": "readonly" 20 | }, 21 | "noDisplay": true 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /app/server/lib/mutagen/mp4/_util.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 Christoph Reiter 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | 8 | from mutagen._util import cdata 9 | 10 | 11 | def parse_full_atom(data): 12 | """Some atoms are versioned. Split them up in (version, flags, payload). 13 | Can raise ValueError. 14 | """ 15 | 16 | if len(data) < 4: 17 | raise ValueError("not enough data") 18 | 19 | version = ord(data[0:1]) 20 | flags = cdata.uint_be(b"\x00" + data[1:4]) 21 | return version, flags, data[4:] 22 | -------------------------------------------------------------------------------- /app/server/lib/flask/signals.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from blinker import Namespace 4 | 5 | # This namespace is only for signals provided by Flask itself. 6 | _signals = Namespace() 7 | 8 | template_rendered = _signals.signal("template-rendered") 9 | before_render_template = _signals.signal("before-render-template") 10 | request_started = _signals.signal("request-started") 11 | request_finished = _signals.signal("request-finished") 12 | request_tearing_down = _signals.signal("request-tearing-down") 13 | got_request_exception = _signals.signal("got-request-exception") 14 | appcontext_tearing_down = _signals.signal("appcontext-tearing-down") 15 | appcontext_pushed = _signals.signal("appcontext-pushed") 16 | appcontext_popped = _signals.signal("appcontext-popped") 17 | message_flashed = _signals.signal("message-flashed") 18 | -------------------------------------------------------------------------------- /app/server/lib/urllib3/contrib/emscripten/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import urllib3.connection 4 | 5 | from ...connectionpool import HTTPConnectionPool, HTTPSConnectionPool 6 | from .connection import EmscriptenHTTPConnection, EmscriptenHTTPSConnection 7 | 8 | 9 | def inject_into_urllib3() -> None: 10 | # override connection classes to use emscripten specific classes 11 | # n.b. mypy complains about the overriding of classes below 12 | # if it isn't ignored 13 | HTTPConnectionPool.ConnectionCls = EmscriptenHTTPConnection 14 | HTTPSConnectionPool.ConnectionCls = EmscriptenHTTPSConnection 15 | urllib3.connection.HTTPConnection = EmscriptenHTTPConnection # type: ignore[misc,assignment] 16 | urllib3.connection.HTTPSConnection = EmscriptenHTTPSConnection # type: ignore[misc,assignment] 17 | -------------------------------------------------------------------------------- /app/server/lib/watchdog/utils/process_watcher.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import logging 4 | 5 | from watchdog.utils import BaseThread 6 | 7 | logger = logging.getLogger(__name__) 8 | 9 | 10 | class ProcessWatcher(BaseThread): 11 | def __init__(self, popen_obj, process_termination_callback): 12 | super().__init__() 13 | self.popen_obj = popen_obj 14 | self.process_termination_callback = process_termination_callback 15 | 16 | def run(self): 17 | while True: 18 | if self.popen_obj.poll() is not None: 19 | break 20 | if self.stopped_event.wait(timeout=0.1): 21 | return 22 | 23 | try: 24 | self.process_termination_callback() 25 | except Exception: 26 | logger.exception("Error calling process termination callback") 27 | -------------------------------------------------------------------------------- /app/server/lib/urllib3/_version.py: -------------------------------------------------------------------------------- 1 | # file generated by setuptools-scm 2 | # don't change, don't track in version control 3 | 4 | __all__ = [ 5 | "__version__", 6 | "__version_tuple__", 7 | "version", 8 | "version_tuple", 9 | "__commit_id__", 10 | "commit_id", 11 | ] 12 | 13 | TYPE_CHECKING = False 14 | if TYPE_CHECKING: 15 | from typing import Tuple 16 | from typing import Union 17 | 18 | VERSION_TUPLE = Tuple[Union[int, str], ...] 19 | COMMIT_ID = Union[str, None] 20 | else: 21 | VERSION_TUPLE = object 22 | COMMIT_ID = object 23 | 24 | version: str 25 | __version__: str 26 | __version_tuple__: VERSION_TUPLE 27 | version_tuple: VERSION_TUPLE 28 | commit_id: COMMIT_ID 29 | __commit_id__: COMMIT_ID 30 | 31 | __version__ = version = '2.6.0' 32 | __version_tuple__ = version_tuple = (2, 6, 0) 33 | 34 | __commit_id__ = commit_id = None 35 | -------------------------------------------------------------------------------- /app/server/lib/blinker-1.9.0.dist-info/RECORD: -------------------------------------------------------------------------------- 1 | blinker-1.9.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 2 | blinker-1.9.0.dist-info/LICENSE.txt,sha256=nrc6HzhZekqhcCXSrhvjg5Ykx5XphdTw6Xac4p-spGc,1054 3 | blinker-1.9.0.dist-info/METADATA,sha256=uIRiM8wjjbHkCtbCyTvctU37IAZk0kEe5kxAld1dvzA,1633 4 | blinker-1.9.0.dist-info/RECORD,, 5 | blinker-1.9.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82 6 | blinker/__init__.py,sha256=I2EdZqpy4LyjX17Hn1yzJGWCjeLaVaPzsMgHkLfj_cQ,317 7 | blinker/__pycache__/__init__.cpython-312.pyc,, 8 | blinker/__pycache__/_utilities.cpython-312.pyc,, 9 | blinker/__pycache__/base.cpython-312.pyc,, 10 | blinker/_utilities.py,sha256=0J7eeXXTUx0Ivf8asfpx0ycVkp0Eqfqnj117x2mYX9E,1675 11 | blinker/base.py,sha256=QpDuvXXcwJF49lUBcH5BiST46Rz9wSG7VW_p7N_027M,19132 12 | blinker/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 13 | -------------------------------------------------------------------------------- /app/server/lib/requests/hooks.py: -------------------------------------------------------------------------------- 1 | """ 2 | requests.hooks 3 | ~~~~~~~~~~~~~~ 4 | 5 | This module provides the capabilities for the Requests hooks system. 6 | 7 | Available hooks: 8 | 9 | ``response``: 10 | The response generated from a Request. 11 | """ 12 | HOOKS = ["response"] 13 | 14 | 15 | def default_hooks(): 16 | return {event: [] for event in HOOKS} 17 | 18 | 19 | # TODO: response is the only one 20 | 21 | 22 | def dispatch_hook(key, hooks, hook_data, **kwargs): 23 | """Dispatches a hook dictionary on a given piece of data.""" 24 | hooks = hooks or {} 25 | hooks = hooks.get(key) 26 | if hooks: 27 | if hasattr(hooks, "__call__"): 28 | hooks = [hooks] 29 | for hook in hooks: 30 | _hook_data = hook(hook_data, **kwargs) 31 | if _hook_data is not None: 32 | hook_data = _hook_data 33 | return hook_data 34 | -------------------------------------------------------------------------------- /manifest: -------------------------------------------------------------------------------- 1 | appname = 2fmusic 2 | version = 0.0.7 3 | display_name = 2FMusic 4 | desc = """ 5 |

2FMusic 简洁高效的本地音乐播放器,专为 FNOS 而设计。

6 |
  • 🧪 测试版 - 功能暂不稳定,仅供测试!
  • 7 |
      8 |
    • 🎵 本地音乐库:自动扫描,支持识别 ID3 内嵌元数据。
    • 9 |
    • 🖥️ Web 播放器:移动端适配,支持网络自动获取歌词、封面。
    • 10 |
    • 🗂️ 目录管理:支持将服务器任意文件夹添加到音乐库。
    • 11 |
    • ☁️ 网易云集成:支持搜索、下载、链接解析及扫码登录。
    • 12 |
    • 🎧 音频预览:支持文件管理器双击预览播放(需安装2FMusic Preview)。
    • 13 |
    14 | """ 15 | arch = x86_64 16 | source = thirdparty 17 | maintainer = yuexps,UCKET 18 | maintainer_url = https://github.com/yuexps/2FMusic 19 | distributor = yuexps 20 | distributor_url = https://www.2fstore.cfd 21 | desktop_uidir = ui 22 | desktop_applaunchname = 2fmusic.Application 23 | service_port = 23237 24 | install_dep_apps = python312 25 | -------------------------------------------------------------------------------- /app/server/lib/jinja2/_identifier.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | # generated by scripts/generate_identifier_pattern.py 4 | pattern = re.compile( 5 | r"[\w·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߽߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛࣓-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣ৾ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣૺ-૿ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఄా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഀ-ഃ഻഼ാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳷-᳹᷀-᷹᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꣿꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𐴤-𐽆𐴧-𐽐𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑄴𑅅𑅆𑅳𑆀-𑆂𑆳-𑇀𑇉-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌻𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑑞𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑠬-𑠺𑨁-𑨊𑨳-𑨹𑨻-𑨾𑩇𑩑-𑩛𑪊-𑪙𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𑴱-𑴶𑴺𑴼𑴽𑴿-𑵅𑵇𑶊-𑶎𑶐𑶑𑶓-𑶗𑻳-𑻶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯]+" # noqa: B950 6 | ) 7 | -------------------------------------------------------------------------------- /app/server/lib/requests/packages.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from .compat import chardet 4 | 5 | # This code exists for backwards compatibility reasons. 6 | # I don't like it either. Just look the other way. :) 7 | 8 | for package in ("urllib3", "idna"): 9 | locals()[package] = __import__(package) 10 | # This traversal is apparently necessary such that the identities are 11 | # preserved (requests.packages.urllib3.* is urllib3.*) 12 | for mod in list(sys.modules): 13 | if mod == package or mod.startswith(f"{package}."): 14 | sys.modules[f"requests.packages.{mod}"] = sys.modules[mod] 15 | 16 | if chardet is not None: 17 | target = chardet.__name__ 18 | for mod in list(sys.modules): 19 | if mod == target or mod.startswith(f"{target}."): 20 | imported_mod = sys.modules[mod] 21 | sys.modules[f"requests.packages.{mod}"] = imported_mod 22 | mod = mod.replace(target, "chardet") 23 | sys.modules[f"requests.packages.{mod}"] = imported_mod 24 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Python: Debug 2FMusic Server", 6 | "type": "debugpy", 7 | "request": "launch", 8 | "program": "${workspaceFolder}/app/server/app.py", 9 | "console": "integratedTerminal", 10 | "args": [ 11 | "--music-library-path", 12 | "${workspaceFolder}/test_tmp/Music", 13 | "--log-path", 14 | "${workspaceFolder}/test_tmp/app.log", 15 | "--port", 16 | "23237", 17 | "--password", 18 | "123456" 19 | ], 20 | "justMyCode": true, 21 | "rules": [ 22 | { 23 | "path": "${workspaceFolder}/app/server/lib", 24 | "include": false 25 | } 26 | ], 27 | "env": { 28 | "FLASK_DEBUG": "1" 29 | } 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /app/server/lib/idna/__init__.py: -------------------------------------------------------------------------------- 1 | from .core import ( 2 | IDNABidiError, 3 | IDNAError, 4 | InvalidCodepoint, 5 | InvalidCodepointContext, 6 | alabel, 7 | check_bidi, 8 | check_hyphen_ok, 9 | check_initial_combiner, 10 | check_label, 11 | check_nfc, 12 | decode, 13 | encode, 14 | ulabel, 15 | uts46_remap, 16 | valid_contextj, 17 | valid_contexto, 18 | valid_label_length, 19 | valid_string_length, 20 | ) 21 | from .intranges import intranges_contain 22 | from .package_data import __version__ 23 | 24 | __all__ = [ 25 | "__version__", 26 | "IDNABidiError", 27 | "IDNAError", 28 | "InvalidCodepoint", 29 | "InvalidCodepointContext", 30 | "alabel", 31 | "check_bidi", 32 | "check_hyphen_ok", 33 | "check_initial_combiner", 34 | "check_label", 35 | "check_nfc", 36 | "decode", 37 | "encode", 38 | "intranges_contain", 39 | "ulabel", 40 | "uts46_remap", 41 | "valid_contextj", 42 | "valid_contexto", 43 | "valid_label_length", 44 | "valid_string_length", 45 | ] 46 | -------------------------------------------------------------------------------- /app/server/lib/certifi-2025.11.12.dist-info/RECORD: -------------------------------------------------------------------------------- 1 | certifi-2025.11.12.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 2 | certifi-2025.11.12.dist-info/METADATA,sha256=_JprGu_1lWSdHlruRBKcorXnrfvBDhvX_6KRr8HQbLc,2475 3 | certifi-2025.11.12.dist-info/RECORD,, 4 | certifi-2025.11.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 5 | certifi-2025.11.12.dist-info/licenses/LICENSE,sha256=6TcW2mucDVpKHfYP5pWzcPBpVgPSH2-D8FPkLPwQyvc,989 6 | certifi-2025.11.12.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 7 | certifi/__init__.py,sha256=1BRSxNMnZW7CZ2oJtYWLoJgfHfcB9i273exwiPwfjJM,94 8 | certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243 9 | certifi/__pycache__/__init__.cpython-312.pyc,, 10 | certifi/__pycache__/__main__.cpython-312.pyc,, 11 | certifi/__pycache__/core.cpython-312.pyc,, 12 | certifi/cacert.pem,sha256=oa1dZD4hxDtb7XTH4IkdzbWPavUcis4eTwINZUqlKhY,283932 13 | certifi/core.py,sha256=XFXycndG5pf37ayeF8N32HUuDafsyhkVMbO4BAPWHa0,3394 14 | certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 15 | -------------------------------------------------------------------------------- /app/server/lib/certifi-2025.11.12.dist-info/licenses/LICENSE: -------------------------------------------------------------------------------- 1 | This package contains a modified version of ca-bundle.crt: 2 | 3 | ca-bundle.crt -- Bundle of CA Root Certificates 4 | 5 | This is a bundle of X.509 certificates of public Certificate Authorities 6 | (CA). These were automatically extracted from Mozilla's root certificates 7 | file (certdata.txt). This file can be found in the mozilla source tree: 8 | https://hg.mozilla.org/mozilla-central/file/tip/security/nss/lib/ckfw/builtins/certdata.txt 9 | It contains the certificates in PEM format and therefore 10 | can be directly used with curl / libcurl / php_curl, or with 11 | an Apache+mod_ssl webserver for SSL client authentication. 12 | Just configure this file as the SSLCACertificateFile.# 13 | 14 | ***** BEGIN LICENSE BLOCK ***** 15 | This Source Code Form is subject to the terms of the Mozilla Public License, 16 | v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain 17 | one at http://mozilla.org/MPL/2.0/. 18 | 19 | ***** END LICENSE BLOCK ***** 20 | @(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $ 21 | -------------------------------------------------------------------------------- /app/server/lib/click/_utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import enum 4 | import typing as t 5 | 6 | 7 | class Sentinel(enum.Enum): 8 | """Enum used to define sentinel values. 9 | 10 | .. seealso:: 11 | 12 | `PEP 661 - Sentinel Values `_. 13 | """ 14 | 15 | UNSET = object() 16 | FLAG_NEEDS_VALUE = object() 17 | 18 | def __repr__(self) -> str: 19 | return f"{self.__class__.__name__}.{self.name}" 20 | 21 | 22 | UNSET = Sentinel.UNSET 23 | """Sentinel used to indicate that a value is not set.""" 24 | 25 | FLAG_NEEDS_VALUE = Sentinel.FLAG_NEEDS_VALUE 26 | """Sentinel used to indicate an option was passed as a flag without a 27 | value but is not a flag option. 28 | 29 | ``Option.consume_value`` uses this to prompt or use the ``flag_value``. 30 | """ 31 | 32 | T_UNSET = t.Literal[UNSET] # type: ignore[valid-type] 33 | """Type hint for the :data:`UNSET` sentinel value.""" 34 | 35 | T_FLAG_NEEDS_VALUE = t.Literal[FLAG_NEEDS_VALUE] # type: ignore[valid-type] 36 | """Type hint for the :data:`FLAG_NEEDS_VALUE` sentinel value.""" 37 | -------------------------------------------------------------------------------- /app/server/lib/watchdog/version.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Yesudeep Mangalapilly 2 | # Copyright 2012 Google, Inc & contributors. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | from __future__ import annotations 18 | 19 | # When updating this version number, please update the 20 | # ``docs/source/global.rst.inc`` file as well. 21 | VERSION_MAJOR = 4 22 | VERSION_MINOR = 0 23 | VERSION_BUILD = 0 24 | VERSION_INFO = (VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD) 25 | VERSION_STRING = f"{VERSION_MAJOR}.{VERSION_MINOR}.{VERSION_BUILD}" 26 | 27 | __version__ = VERSION_INFO 28 | -------------------------------------------------------------------------------- /app/server/lib/blinker-1.9.0.dist-info/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2010 Jason Kirtland 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /app/server/lib/markupsafe-3.0.3.dist-info/RECORD: -------------------------------------------------------------------------------- 1 | markupsafe-3.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 2 | markupsafe-3.0.3.dist-info/METADATA,sha256=8K5duwnVD7X3Yyw9U_AiCZXvdgGeWJLgpUV0ATak48s,2764 3 | markupsafe-3.0.3.dist-info/RECORD,, 4 | markupsafe-3.0.3.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101 5 | markupsafe-3.0.3.dist-info/licenses/LICENSE.txt,sha256=RjHsDbX9kKVH4zaBcmTGeYIUM4FG-KyUtKV_lu6MnsQ,1503 6 | markupsafe-3.0.3.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 7 | markupsafe/__init__.py,sha256=ut2LXj-6sqkIVUdSAx-dboB5crAaRG5y7EO447hmaro,13644 8 | markupsafe/__pycache__/__init__.cpython-312.pyc,, 9 | markupsafe/__pycache__/_native.cpython-312.pyc,, 10 | markupsafe/_native.py,sha256=2ptkJ40yCcp9kq3L1NqpgjfpZB-obniYKFFKUOkHh4Q,218 11 | markupsafe/_speedups.c,sha256=efc6azc50WbKxSNinxV4rktIX2xzWfKsLvncC8Z3I_w,4527 12 | markupsafe/_speedups.cp312-win_amd64.pyd,sha256=YQfNEuAnNXGUlHqeSIGuz0aHkNLLbvTdbsd_VzYjIJg,13312 13 | markupsafe/_speedups.pyi,sha256=LSDmXYOefH4HVpAXuL8sl7AttLw0oXh1njVoVZp2wqQ,42 14 | markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 15 | -------------------------------------------------------------------------------- /wizard/uninstall: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "stepTitle": "确认卸载", 4 | "items": [ 5 | { 6 | "type": "tips", 7 | "helpText": "您即将卸载 2FMusic 应用。请选择如何处理应用数据:" 8 | }, 9 | { 10 | "type": "radio", 11 | "field": "wizard_data_action", 12 | "label": "数据保留选项", 13 | "initValue": "keep", 14 | "options": [ 15 | { 16 | "label": "保留数据(推荐)- 将来重新安装时可恢复", 17 | "value": "keep" 18 | }, 19 | { 20 | "label": "删除所有数据 - 此操作不可恢复!", 21 | "value": "delete" 22 | } 23 | ], 24 | "rules": [ 25 | { 26 | "required": true, 27 | "message": "请选择数据保留选项" 28 | } 29 | ] 30 | }, 31 | { 32 | "type": "tips", 33 | "helpText": "警告: 选择删除数据后,所有 2FMusic 配置和数据将永久丢失,无法恢复。" 34 | } 35 | ] 36 | } 37 | ] 38 | -------------------------------------------------------------------------------- /app/server/lib/charset_normalizer-3.4.4.dist-info/licenses/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 TAHRI Ahmed R. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/server/lib/urllib3/util/__init__.py: -------------------------------------------------------------------------------- 1 | # For backwards compatibility, provide imports that used to be here. 2 | from __future__ import annotations 3 | 4 | from .connection import is_connection_dropped 5 | from .request import SKIP_HEADER, SKIPPABLE_HEADERS, make_headers 6 | from .response import is_fp_closed 7 | from .retry import Retry 8 | from .ssl_ import ( 9 | ALPN_PROTOCOLS, 10 | IS_PYOPENSSL, 11 | SSLContext, 12 | assert_fingerprint, 13 | create_urllib3_context, 14 | resolve_cert_reqs, 15 | resolve_ssl_version, 16 | ssl_wrap_socket, 17 | ) 18 | from .timeout import Timeout 19 | from .url import Url, parse_url 20 | from .wait import wait_for_read, wait_for_write 21 | 22 | __all__ = ( 23 | "IS_PYOPENSSL", 24 | "SSLContext", 25 | "ALPN_PROTOCOLS", 26 | "Retry", 27 | "Timeout", 28 | "Url", 29 | "assert_fingerprint", 30 | "create_urllib3_context", 31 | "is_connection_dropped", 32 | "is_fp_closed", 33 | "parse_url", 34 | "make_headers", 35 | "resolve_cert_reqs", 36 | "resolve_ssl_version", 37 | "ssl_wrap_socket", 38 | "wait_for_read", 39 | "wait_for_write", 40 | "SKIP_HEADER", 41 | "SKIPPABLE_HEADERS", 42 | ) 43 | -------------------------------------------------------------------------------- /app/server/lib/urllib3-2.6.0.dist-info/licenses/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2008-2020 Andrey Petrov and contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/server/lib/mutagen/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2005 Michael Urman 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | 8 | """Mutagen aims to be an all purpose multimedia tagging library. 9 | 10 | :: 11 | 12 | import mutagen.[format] 13 | metadata = mutagen.[format].Open(filename) 14 | 15 | ``metadata`` acts like a dictionary of tags in the file. Tags are generally a 16 | list of string-like values, but may have additional methods available 17 | depending on tag or format. They may also be entirely different objects 18 | for certain keys, again depending on format. 19 | """ 20 | 21 | from mutagen._util import MutagenError 22 | from mutagen._file import FileType, StreamInfo, File 23 | from mutagen._tags import Tags, Metadata, PaddingInfo 24 | 25 | version = (1, 47, 0) 26 | """Version tuple.""" 27 | 28 | version_string = ".".join(map(str, version)) 29 | """Version string.""" 30 | 31 | MutagenError 32 | 33 | FileType 34 | 35 | StreamInfo 36 | 37 | File 38 | 39 | Tags 40 | 41 | Metadata 42 | 43 | PaddingInfo 44 | -------------------------------------------------------------------------------- /app/server/lib/colorama/tests/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. 2 | from contextlib import contextmanager 3 | from io import StringIO 4 | import sys 5 | import os 6 | 7 | 8 | class StreamTTY(StringIO): 9 | def isatty(self): 10 | return True 11 | 12 | class StreamNonTTY(StringIO): 13 | def isatty(self): 14 | return False 15 | 16 | @contextmanager 17 | def osname(name): 18 | orig = os.name 19 | os.name = name 20 | yield 21 | os.name = orig 22 | 23 | @contextmanager 24 | def replace_by(stream): 25 | orig_stdout = sys.stdout 26 | orig_stderr = sys.stderr 27 | sys.stdout = stream 28 | sys.stderr = stream 29 | yield 30 | sys.stdout = orig_stdout 31 | sys.stderr = orig_stderr 32 | 33 | @contextmanager 34 | def replace_original_by(stream): 35 | orig_stdout = sys.__stdout__ 36 | orig_stderr = sys.__stderr__ 37 | sys.__stdout__ = stream 38 | sys.__stderr__ = stream 39 | yield 40 | sys.__stdout__ = orig_stdout 41 | sys.__stderr__ = orig_stderr 42 | 43 | @contextmanager 44 | def pycharm(): 45 | os.environ["PYCHARM_HOSTED"] = "1" 46 | non_tty = StreamNonTTY() 47 | with replace_by(non_tty), replace_original_by(non_tty): 48 | yield 49 | del os.environ["PYCHARM_HOSTED"] 50 | -------------------------------------------------------------------------------- /app/server/lib/urllib3/util/util.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import typing 4 | from types import TracebackType 5 | 6 | 7 | def to_bytes( 8 | x: str | bytes, encoding: str | None = None, errors: str | None = None 9 | ) -> bytes: 10 | if isinstance(x, bytes): 11 | return x 12 | elif not isinstance(x, str): 13 | raise TypeError(f"not expecting type {type(x).__name__}") 14 | if encoding or errors: 15 | return x.encode(encoding or "utf-8", errors=errors or "strict") 16 | return x.encode() 17 | 18 | 19 | def to_str( 20 | x: str | bytes, encoding: str | None = None, errors: str | None = None 21 | ) -> str: 22 | if isinstance(x, str): 23 | return x 24 | elif not isinstance(x, bytes): 25 | raise TypeError(f"not expecting type {type(x).__name__}") 26 | if encoding or errors: 27 | return x.decode(encoding or "utf-8", errors=errors or "strict") 28 | return x.decode() 29 | 30 | 31 | def reraise( 32 | tp: type[BaseException] | None, 33 | value: BaseException, 34 | tb: TracebackType | None = None, 35 | ) -> typing.NoReturn: 36 | try: 37 | if value.__traceback__ is not tb: 38 | raise value.with_traceback(tb) 39 | raise value 40 | finally: 41 | value = None # type: ignore[assignment] 42 | tb = None 43 | -------------------------------------------------------------------------------- /app/server/lib/share/man/man1/mutagen-pony.1: -------------------------------------------------------------------------------- 1 | .\" Man page generated from reStructuredText. 2 | . 3 | .TH MUTAGEN-PONY 1 "" "" "" 4 | .SH NAME 5 | mutagen-pony \- scan a collection of MP3 files 6 | . 7 | .nr rst2man-indent-level 0 8 | . 9 | .de1 rstReportMargin 10 | \\$1 \\n[an-margin] 11 | level \\n[rst2man-indent-level] 12 | level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] 13 | - 14 | \\n[rst2man-indent0] 15 | \\n[rst2man-indent1] 16 | \\n[rst2man-indent2] 17 | .. 18 | .de1 INDENT 19 | .\" .rstReportMargin pre: 20 | . RS \\$1 21 | . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] 22 | . nr rst2man-indent-level +1 23 | .\" .rstReportMargin post: 24 | .. 25 | .de UNINDENT 26 | . RE 27 | .\" indent \\n[an-margin] 28 | .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] 29 | .nr rst2man-indent-level -1 30 | .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] 31 | .in \\n[rst2man-indent\\n[rst2man-indent-level]]u 32 | .. 33 | .SH SYNOPSIS 34 | .sp 35 | \fBmutagen\-pony\fP \fIdirectory\fP ... 36 | .SH DESCRIPTION 37 | .sp 38 | \fBmutagen\-pony\fP scans any directories given and reports on the kinds of 39 | tags in the MP3s it finds in them. Ride the pony. 40 | .sp 41 | It is primarily intended as a debugging tool for Mutagen. 42 | .SH AUTHORS 43 | .sp 44 | Michael Urman and Joe Wreschnig 45 | .\" Generated by docutils manpage writer. 46 | . 47 | -------------------------------------------------------------------------------- /app/server/lib/urllib3/util/proxy.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import typing 4 | 5 | from .url import Url 6 | 7 | if typing.TYPE_CHECKING: 8 | from ..connection import ProxyConfig 9 | 10 | 11 | def connection_requires_http_tunnel( 12 | proxy_url: Url | None = None, 13 | proxy_config: ProxyConfig | None = None, 14 | destination_scheme: str | None = None, 15 | ) -> bool: 16 | """ 17 | Returns True if the connection requires an HTTP CONNECT through the proxy. 18 | 19 | :param URL proxy_url: 20 | URL of the proxy. 21 | :param ProxyConfig proxy_config: 22 | Proxy configuration from poolmanager.py 23 | :param str destination_scheme: 24 | The scheme of the destination. (i.e https, http, etc) 25 | """ 26 | # If we're not using a proxy, no way to use a tunnel. 27 | if proxy_url is None: 28 | return False 29 | 30 | # HTTP destinations never require tunneling, we always forward. 31 | if destination_scheme == "http": 32 | return False 33 | 34 | # Support for forwarding with HTTPS proxies and HTTPS destinations. 35 | if ( 36 | proxy_url.scheme == "https" 37 | and proxy_config 38 | and proxy_config.use_forwarding_for_https 39 | ): 40 | return False 41 | 42 | # Otherwise always use a tunnel. 43 | return True 44 | -------------------------------------------------------------------------------- /app/server/lib/share/man/man1/mutagen-inspect.1: -------------------------------------------------------------------------------- 1 | .\" Man page generated from reStructuredText. 2 | . 3 | .TH MUTAGEN-INSPECT 1 "" "" "" 4 | .SH NAME 5 | mutagen-inspect \- view Mutagen-supported audio tags 6 | . 7 | .nr rst2man-indent-level 0 8 | . 9 | .de1 rstReportMargin 10 | \\$1 \\n[an-margin] 11 | level \\n[rst2man-indent-level] 12 | level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] 13 | - 14 | \\n[rst2man-indent0] 15 | \\n[rst2man-indent1] 16 | \\n[rst2man-indent2] 17 | .. 18 | .de1 INDENT 19 | .\" .rstReportMargin pre: 20 | . RS \\$1 21 | . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] 22 | . nr rst2man-indent-level +1 23 | .\" .rstReportMargin post: 24 | .. 25 | .de UNINDENT 26 | . RE 27 | .\" indent \\n[an-margin] 28 | .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] 29 | .nr rst2man-indent-level -1 30 | .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] 31 | .in \\n[rst2man-indent\\n[rst2man-indent-level]]u 32 | .. 33 | .SH SYNOPSIS 34 | .sp 35 | \fBmutagen\-inspect\fP \fIfilename\fP ... 36 | .SH DESCRIPTION 37 | .sp 38 | \fBmutagen\-inspect\fP loads and prints information about an audio file and 39 | its tags. 40 | .sp 41 | It is primarily intended as a debugging tool for Mutagen, but can be useful 42 | for extracting tags from the command line. 43 | .SH AUTHOR 44 | .sp 45 | Joe Wreschnig 46 | .\" Generated by docutils manpage writer. 47 | . 48 | -------------------------------------------------------------------------------- /app/server/lib/mutagen/_tools/mutagen_inspect.py: -------------------------------------------------------------------------------- 1 | # Copyright 2005 Joe Wreschnig 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | 8 | """Full tag list for any given file.""" 9 | 10 | import sys 11 | 12 | from ._util import SignalHandler, OptionParser 13 | 14 | 15 | _sig = SignalHandler() 16 | 17 | 18 | def main(argv): 19 | from mutagen import File 20 | 21 | parser = OptionParser(usage="usage: %prog [options] FILE [FILE...]") 22 | parser.add_option("--no-flac", help="Compatibility; does nothing.") 23 | parser.add_option("--no-mp3", help="Compatibility; does nothing.") 24 | parser.add_option("--no-apev2", help="Compatibility; does nothing.") 25 | 26 | (options, args) = parser.parse_args(argv[1:]) 27 | if not args: 28 | raise SystemExit(parser.print_help() or 1) 29 | 30 | for filename in args: 31 | print(u"--", filename) 32 | try: 33 | print(u"-", File(filename).pprint()) 34 | except AttributeError: 35 | print(u"- Unknown file type") 36 | except Exception as err: 37 | print(str(err)) 38 | print(u"") 39 | 40 | 41 | def entry_point(): 42 | _sig.init() 43 | return main(sys.argv) 44 | -------------------------------------------------------------------------------- /app/server/lib/idna-3.11.dist-info/RECORD: -------------------------------------------------------------------------------- 1 | idna-3.11.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 2 | idna-3.11.dist-info/METADATA,sha256=fCwSww9SuiN8TIHllFSASUQCW55hAs8dzKnr9RaEEbA,8378 3 | idna-3.11.dist-info/RECORD,, 4 | idna-3.11.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 5 | idna-3.11.dist-info/licenses/LICENSE.md,sha256=t6M2q_OwThgOwGXN0W5wXQeeHMehT5EKpukYfza5zYc,1541 6 | idna/__init__.py,sha256=MPqNDLZbXqGaNdXxAFhiqFPKEQXju2jNQhCey6-5eJM,868 7 | idna/__pycache__/__init__.cpython-312.pyc,, 8 | idna/__pycache__/codec.cpython-312.pyc,, 9 | idna/__pycache__/compat.cpython-312.pyc,, 10 | idna/__pycache__/core.cpython-312.pyc,, 11 | idna/__pycache__/idnadata.cpython-312.pyc,, 12 | idna/__pycache__/intranges.cpython-312.pyc,, 13 | idna/__pycache__/package_data.cpython-312.pyc,, 14 | idna/__pycache__/uts46data.cpython-312.pyc,, 15 | idna/codec.py,sha256=M2SGWN7cs_6B32QmKTyTN6xQGZeYQgQ2wiX3_DR6loE,3438 16 | idna/compat.py,sha256=RzLy6QQCdl9784aFhb2EX9EKGCJjg0P3PilGdeXXcx8,316 17 | idna/core.py,sha256=P26_XVycuMTZ1R2mNK1ZREVzM5mvTzdabBXfyZVU1Lc,13246 18 | idna/idnadata.py,sha256=SG8jhaGE53iiD6B49pt2pwTv_UvClciWE-N54oR2p4U,79623 19 | idna/intranges.py,sha256=amUtkdhYcQG8Zr-CoMM_kVRacxkivC1WgxN1b63KKdU,1898 20 | idna/package_data.py,sha256=_CUavOxobnbyNG2FLyHoN8QHP3QM9W1tKuw7eq9QwBk,21 21 | idna/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 22 | idna/uts46data.py,sha256=H9J35VkD0F9L9mKOqjeNGd2A-Va6FlPoz6Jz4K7h-ps,243725 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🎵 2FMusic 2 | 3 | > **本项目是基于 Gemini 3 Pro 协助开发的实验性产物。** 4 | > 5 | > 这是一个轻量级、高颜值的 FNOS 本地音乐播放器,基于 Flask + 原生 Web 技术构建。 6 | 7 | 🚧 **目前项目处于早期开发阶段,功能暂不稳定,欢迎提交 PR 完善项目 或 Issue 反馈 Bug!** 8 | 9 | --- 10 | 11 | ## ✨ 核心功能 12 | 13 | * **🎧 本地音乐库** 14 | * 自动扫描并管理上传的音乐文件。 15 | * 支持识别 ID3 内嵌元数据(支持封面、歌词)。 16 | * 播放时支持通过 LrcApi 获取封面、歌词。 17 | * **📱 沉浸式播放器** 18 | * **响应式 UI**:完美适配 PC Web端,提供原生 App 般的流畅体验。 19 | * **动态视觉**:支持歌词滚动显示、根据封面自动提取主题色。 20 | * **📂 灵活目录管理** 21 | * 支持添加服务器上的任意文件夹到音乐库,无需重复移动文件。 22 | * **☁️ 网易云音乐集成** 23 | * 集成搜索、高品质下载功能。 24 | * 支持链接解析及扫码登录,轻松同步歌单。 25 | * **🔊 音频预览** 26 | * 支持右键快速预览播放音频文件(需安装 2FMusic Preview 扩展)。 27 | 28 | ## 🚀 快速开始 29 | 30 | ### 1. 启动服务 31 | 32 | ```bash 33 | python app/server/app.py --music-library-path ./Music --log-path ./app.log --port 23237 34 | ``` 35 | 36 | 参数: 37 | - `--music-library-path`: 音乐文件存储目录 38 | - `--log-path`: 日志文件路径 39 | - `--port`: 服务端口 (默认 23237) 40 | - `--password`: 设置访问密码 41 | 42 | ### 2. 访问应用 43 | 44 | 请在浏览器中访问: 45 | 👉 `http://localhost:23237` 46 | 47 | ## 🛠️ 开源致谢 48 | 49 | 本项目使用了以下优秀的开源项目: 50 | 51 | * **UI 图标**: [Font Awesome](https://fontawesome.com/) (CC BY 4.0 / OFL) 52 | * **色彩算法**: [ColorThief](https://lokeshdhakar.com/projects/color-thief/) (MIT) 53 | * **歌词/封面 API**: [LrcApi](https://github.com/HisAtri/LrcApi) (GPL-3.0) 54 | * **网易云 API**: [NeteaseCloudMusicApiEnhanced](https://github.com/NeteaseCloudMusicApiEnhanced/api-enhanced) (MIT) 55 | -------------------------------------------------------------------------------- /app/server/lib/jinja2/defaults.py: -------------------------------------------------------------------------------- 1 | import typing as t 2 | 3 | from .filters import FILTERS as DEFAULT_FILTERS # noqa: F401 4 | from .tests import TESTS as DEFAULT_TESTS # noqa: F401 5 | from .utils import Cycler 6 | from .utils import generate_lorem_ipsum 7 | from .utils import Joiner 8 | from .utils import Namespace 9 | 10 | if t.TYPE_CHECKING: 11 | import typing_extensions as te 12 | 13 | # defaults for the parser / lexer 14 | BLOCK_START_STRING = "{%" 15 | BLOCK_END_STRING = "%}" 16 | VARIABLE_START_STRING = "{{" 17 | VARIABLE_END_STRING = "}}" 18 | COMMENT_START_STRING = "{#" 19 | COMMENT_END_STRING = "#}" 20 | LINE_STATEMENT_PREFIX: t.Optional[str] = None 21 | LINE_COMMENT_PREFIX: t.Optional[str] = None 22 | TRIM_BLOCKS = False 23 | LSTRIP_BLOCKS = False 24 | NEWLINE_SEQUENCE: "te.Literal['\\n', '\\r\\n', '\\r']" = "\n" 25 | KEEP_TRAILING_NEWLINE = False 26 | 27 | # default filters, tests and namespace 28 | 29 | DEFAULT_NAMESPACE = { 30 | "range": range, 31 | "dict": dict, 32 | "lipsum": generate_lorem_ipsum, 33 | "cycler": Cycler, 34 | "joiner": Joiner, 35 | "namespace": Namespace, 36 | } 37 | 38 | # default policies 39 | DEFAULT_POLICIES: t.Dict[str, t.Any] = { 40 | "compiler.ascii_str": True, 41 | "urlize.rel": "noopener", 42 | "urlize.target": None, 43 | "urlize.extra_schemes": None, 44 | "truncate.leeway": 5, 45 | "json.dumps_function": None, 46 | "json.dumps_kwargs": {"sort_keys": True}, 47 | "ext.i18n.trimmed": False, 48 | } 49 | -------------------------------------------------------------------------------- /app/server/lib/jinja2/constants.py: -------------------------------------------------------------------------------- 1 | #: list of lorem ipsum words used by the lipsum() helper function 2 | LOREM_IPSUM_WORDS = """\ 3 | a ac accumsan ad adipiscing aenean aliquam aliquet amet ante aptent arcu at 4 | auctor augue bibendum blandit class commodo condimentum congue consectetuer 5 | consequat conubia convallis cras cubilia cum curabitur curae cursus dapibus 6 | diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend 7 | elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames 8 | faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac 9 | hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum 10 | justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem 11 | luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie 12 | mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non 13 | nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque 14 | penatibus per pharetra phasellus placerat platea porta porttitor posuere 15 | potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus 16 | ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit 17 | sociis sociosqu sodales sollicitudin suscipit suspendisse taciti tellus tempor 18 | tempus tincidunt torquent tortor tristique turpis ullamcorper ultrices 19 | ultricies urna ut varius vehicula vel velit venenatis vestibulum vitae vivamus 20 | viverra volutpat vulputate""" 21 | -------------------------------------------------------------------------------- /extensions/preview-cgi/cmd/main: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | APP_NAME="2FMusic Preview" 4 | LOG_FILE="${TRIM_PKGVAR}/info.log" 5 | 6 | # 启动应用(纯 CGI 模式) 7 | start_process() { 8 | log_msg "正在启动 ${APP_NAME}(纯 CGI 模式)..." 9 | 10 | # 纯 CGI 应用不需要启动进程 11 | # 只需要重载 HTTP CGI 服务,让 Web 服务器识别 CGI 脚本 12 | log_msg "重载 HTTP CGI 服务..." 13 | systemctl restart trim_http_cgi.service >> ${LOG_FILE} 2>&1 14 | 15 | if [ $? -eq 0 ]; then 16 | log_msg "HTTP CGI 服务重载成功" 17 | log_msg "${APP_NAME} 已启动(CGI 模式)" 18 | return 0 19 | else 20 | log_msg "ERROR: HTTP CGI 服务重载失败" 21 | return 1 22 | fi 23 | } 24 | 25 | # 停止应用(纯 CGI 模式) 26 | stop_process() { 27 | log_msg "正在停止 ${APP_NAME}(纯 CGI 模式)..." 28 | 29 | # 纯 CGI 应用不需要停止进程 30 | # CGI 脚本由 Web 服务器按需调用,无需手动停止 31 | log_msg "${APP_NAME} 已停止(CGI 模式)" 32 | 33 | return 0 34 | } 35 | 36 | # 检查应用状态 37 | status() { 38 | # 纯 CGI 应用没有持续运行的进程 39 | # 只要应用已安装,就认为是"运行"状态 40 | # CGI 脚本由 Web 服务器按需调用 41 | return 0 42 | } 43 | 44 | case $1 in 45 | start) 46 | # run start command. exit 0 if success, exit 1 if failed 47 | start_process 48 | ;; 49 | stop) 50 | # run stop command. exit 0 if success, exit 1 if failed 51 | stop_process 52 | ;; 53 | status) 54 | # check application status command. exit 0 if running, exit 3 if not running 55 | if status; then 56 | exit 0 57 | else 58 | exit 3 59 | fi 60 | ;; 61 | *) 62 | exit 1 63 | ;; 64 | esac 65 | -------------------------------------------------------------------------------- /app/server/lib/itsdangerous/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import typing as t 4 | 5 | from .encoding import base64_decode as base64_decode 6 | from .encoding import base64_encode as base64_encode 7 | from .encoding import want_bytes as want_bytes 8 | from .exc import BadData as BadData 9 | from .exc import BadHeader as BadHeader 10 | from .exc import BadPayload as BadPayload 11 | from .exc import BadSignature as BadSignature 12 | from .exc import BadTimeSignature as BadTimeSignature 13 | from .exc import SignatureExpired as SignatureExpired 14 | from .serializer import Serializer as Serializer 15 | from .signer import HMACAlgorithm as HMACAlgorithm 16 | from .signer import NoneAlgorithm as NoneAlgorithm 17 | from .signer import Signer as Signer 18 | from .timed import TimedSerializer as TimedSerializer 19 | from .timed import TimestampSigner as TimestampSigner 20 | from .url_safe import URLSafeSerializer as URLSafeSerializer 21 | from .url_safe import URLSafeTimedSerializer as URLSafeTimedSerializer 22 | 23 | 24 | def __getattr__(name: str) -> t.Any: 25 | if name == "__version__": 26 | import importlib.metadata 27 | import warnings 28 | 29 | warnings.warn( 30 | "The '__version__' attribute is deprecated and will be removed in" 31 | " ItsDangerous 2.3. Use feature detection or" 32 | " 'importlib.metadata.version(\"itsdangerous\")' instead.", 33 | DeprecationWarning, 34 | stacklevel=2, 35 | ) 36 | return importlib.metadata.version("itsdangerous") 37 | 38 | raise AttributeError(name) 39 | -------------------------------------------------------------------------------- /app/server/lib/flask-3.0.0.dist-info/LICENSE.rst: -------------------------------------------------------------------------------- 1 | Copyright 2010 Pallets 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of the copyright holder nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /app/server/lib/click-8.3.1.dist-info/licenses/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2014 Pallets 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of the copyright holder nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /app/server/lib/itsdangerous-2.2.0.dist-info/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2011 Pallets 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of the copyright holder nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /app/server/lib/jinja2-3.1.6.dist-info/licenses/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2007 Pallets 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of the copyright holder nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /app/server/lib/markupsafe-3.0.3.dist-info/licenses/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2010 Pallets 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of the copyright holder nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /app/server/lib/werkzeug-3.1.4.dist-info/licenses/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2007 Pallets 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of the copyright holder nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /app/server/lib/colorama-0.4.6.dist-info/licenses/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Jonathan Hartley 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the copyright holders, nor those of its contributors 15 | may be used to endorse or promote products derived from this software without 16 | specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /app/server/lib/itsdangerous-2.2.0.dist-info/RECORD: -------------------------------------------------------------------------------- 1 | itsdangerous-2.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 2 | itsdangerous-2.2.0.dist-info/LICENSE.txt,sha256=Y68JiRtr6K0aQlLtQ68PTvun_JSOIoNnvtfzxa4LCdc,1475 3 | itsdangerous-2.2.0.dist-info/METADATA,sha256=0rk0-1ZwihuU5DnwJVwPWoEI4yWOyCexih3JyZHblhE,1924 4 | itsdangerous-2.2.0.dist-info/RECORD,, 5 | itsdangerous-2.2.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 6 | itsdangerous/__init__.py,sha256=4SK75sCe29xbRgQE1ZQtMHnKUuZYAf3bSpZOrff1IAY,1427 7 | itsdangerous/__pycache__/__init__.cpython-312.pyc,, 8 | itsdangerous/__pycache__/_json.cpython-312.pyc,, 9 | itsdangerous/__pycache__/encoding.cpython-312.pyc,, 10 | itsdangerous/__pycache__/exc.cpython-312.pyc,, 11 | itsdangerous/__pycache__/serializer.cpython-312.pyc,, 12 | itsdangerous/__pycache__/signer.cpython-312.pyc,, 13 | itsdangerous/__pycache__/timed.cpython-312.pyc,, 14 | itsdangerous/__pycache__/url_safe.cpython-312.pyc,, 15 | itsdangerous/_json.py,sha256=wPQGmge2yZ9328EHKF6gadGeyGYCJQKxtU-iLKE6UnA,473 16 | itsdangerous/encoding.py,sha256=wwTz5q_3zLcaAdunk6_vSoStwGqYWe307Zl_U87aRFM,1409 17 | itsdangerous/exc.py,sha256=Rr3exo0MRFEcPZltwecyK16VV1bE2K9_F1-d-ljcUn4,3201 18 | itsdangerous/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 19 | itsdangerous/serializer.py,sha256=PmdwADLqkSyQLZ0jOKAgDsAW4k_H0TlA71Ei3z0C5aI,15601 20 | itsdangerous/signer.py,sha256=YO0CV7NBvHA6j549REHJFUjUojw2pHqwcUpQnU7yNYQ,9647 21 | itsdangerous/timed.py,sha256=6RvDMqNumGMxf0-HlpaZdN9PUQQmRvrQGplKhxuivUs,8083 22 | itsdangerous/url_safe.py,sha256=az4e5fXi_vs-YbWj8YZwn4wiVKfeD--GEKRT5Ueu4P4,2505 23 | -------------------------------------------------------------------------------- /app/server/lib/click/_textwrap.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import collections.abc as cabc 4 | import textwrap 5 | from contextlib import contextmanager 6 | 7 | 8 | class TextWrapper(textwrap.TextWrapper): 9 | def _handle_long_word( 10 | self, 11 | reversed_chunks: list[str], 12 | cur_line: list[str], 13 | cur_len: int, 14 | width: int, 15 | ) -> None: 16 | space_left = max(width - cur_len, 1) 17 | 18 | if self.break_long_words: 19 | last = reversed_chunks[-1] 20 | cut = last[:space_left] 21 | res = last[space_left:] 22 | cur_line.append(cut) 23 | reversed_chunks[-1] = res 24 | elif not cur_line: 25 | cur_line.append(reversed_chunks.pop()) 26 | 27 | @contextmanager 28 | def extra_indent(self, indent: str) -> cabc.Iterator[None]: 29 | old_initial_indent = self.initial_indent 30 | old_subsequent_indent = self.subsequent_indent 31 | self.initial_indent += indent 32 | self.subsequent_indent += indent 33 | 34 | try: 35 | yield 36 | finally: 37 | self.initial_indent = old_initial_indent 38 | self.subsequent_indent = old_subsequent_indent 39 | 40 | def indent_only(self, text: str) -> str: 41 | rv = [] 42 | 43 | for idx, line in enumerate(text.splitlines()): 44 | indent = self.initial_indent 45 | 46 | if idx > 0: 47 | indent = self.subsequent_indent 48 | 49 | rv.append(f"{indent}{line}") 50 | 51 | return "\n".join(rv) 52 | -------------------------------------------------------------------------------- /app/server/lib/werkzeug/user_agent.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | 4 | class UserAgent: 5 | """Represents a parsed user agent header value. 6 | 7 | The default implementation does no parsing, only the :attr:`string` 8 | attribute is set. A subclass may parse the string to set the 9 | common attributes or expose other information. Set 10 | :attr:`werkzeug.wrappers.Request.user_agent_class` to use a 11 | subclass. 12 | 13 | :param string: The header value to parse. 14 | 15 | .. versionadded:: 2.0 16 | This replaces the previous ``useragents`` module, but does not 17 | provide a built-in parser. 18 | """ 19 | 20 | platform: str | None = None 21 | """The OS name, if it could be parsed from the string.""" 22 | 23 | browser: str | None = None 24 | """The browser name, if it could be parsed from the string.""" 25 | 26 | version: str | None = None 27 | """The browser version, if it could be parsed from the string.""" 28 | 29 | language: str | None = None 30 | """The browser language, if it could be parsed from the string.""" 31 | 32 | def __init__(self, string: str) -> None: 33 | self.string: str = string 34 | """The original header value.""" 35 | 36 | def __repr__(self) -> str: 37 | return f"<{type(self).__name__} {self.browser}/{self.version}>" 38 | 39 | def __str__(self) -> str: 40 | return self.string 41 | 42 | def __bool__(self) -> bool: 43 | return bool(self.browser) 44 | 45 | def to_header(self) -> str: 46 | """Convert to a header value.""" 47 | return self.string 48 | -------------------------------------------------------------------------------- /app/server/lib/itsdangerous/encoding.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import base64 4 | import string 5 | import struct 6 | import typing as t 7 | 8 | from .exc import BadData 9 | 10 | 11 | def want_bytes( 12 | s: str | bytes, encoding: str = "utf-8", errors: str = "strict" 13 | ) -> bytes: 14 | if isinstance(s, str): 15 | s = s.encode(encoding, errors) 16 | 17 | return s 18 | 19 | 20 | def base64_encode(string: str | bytes) -> bytes: 21 | """Base64 encode a string of bytes or text. The resulting bytes are 22 | safe to use in URLs. 23 | """ 24 | string = want_bytes(string) 25 | return base64.urlsafe_b64encode(string).rstrip(b"=") 26 | 27 | 28 | def base64_decode(string: str | bytes) -> bytes: 29 | """Base64 decode a URL-safe string of bytes or text. The result is 30 | bytes. 31 | """ 32 | string = want_bytes(string, encoding="ascii", errors="ignore") 33 | string += b"=" * (-len(string) % 4) 34 | 35 | try: 36 | return base64.urlsafe_b64decode(string) 37 | except (TypeError, ValueError) as e: 38 | raise BadData("Invalid base64-encoded data") from e 39 | 40 | 41 | # The alphabet used by base64.urlsafe_* 42 | _base64_alphabet = f"{string.ascii_letters}{string.digits}-_=".encode("ascii") 43 | 44 | _int64_struct = struct.Struct(">Q") 45 | _int_to_bytes = _int64_struct.pack 46 | _bytes_to_int = t.cast("t.Callable[[bytes], tuple[int]]", _int64_struct.unpack) 47 | 48 | 49 | def int_to_bytes(num: int) -> bytes: 50 | return _int_to_bytes(num).lstrip(b"\x00") 51 | 52 | 53 | def bytes_to_int(bytestr: bytes) -> int: 54 | return _bytes_to_int(bytestr.rjust(8, b"\x00"))[0] 55 | -------------------------------------------------------------------------------- /app/server/lib/idna-3.11.dist-info/licenses/LICENSE.md: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2013-2025, Kim Davies and contributors. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are 8 | met: 9 | 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 27 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | -------------------------------------------------------------------------------- /app/server/lib/requests/_internal_utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | requests._internal_utils 3 | ~~~~~~~~~~~~~~ 4 | 5 | Provides utility functions that are consumed internally by Requests 6 | which depend on extremely few external helpers (such as compat) 7 | """ 8 | import re 9 | 10 | from .compat import builtin_str 11 | 12 | _VALID_HEADER_NAME_RE_BYTE = re.compile(rb"^[^:\s][^:\r\n]*$") 13 | _VALID_HEADER_NAME_RE_STR = re.compile(r"^[^:\s][^:\r\n]*$") 14 | _VALID_HEADER_VALUE_RE_BYTE = re.compile(rb"^\S[^\r\n]*$|^$") 15 | _VALID_HEADER_VALUE_RE_STR = re.compile(r"^\S[^\r\n]*$|^$") 16 | 17 | _HEADER_VALIDATORS_STR = (_VALID_HEADER_NAME_RE_STR, _VALID_HEADER_VALUE_RE_STR) 18 | _HEADER_VALIDATORS_BYTE = (_VALID_HEADER_NAME_RE_BYTE, _VALID_HEADER_VALUE_RE_BYTE) 19 | HEADER_VALIDATORS = { 20 | bytes: _HEADER_VALIDATORS_BYTE, 21 | str: _HEADER_VALIDATORS_STR, 22 | } 23 | 24 | 25 | def to_native_string(string, encoding="ascii"): 26 | """Given a string object, regardless of type, returns a representation of 27 | that string in the native string type, encoding and decoding where 28 | necessary. This assumes ASCII unless told otherwise. 29 | """ 30 | if isinstance(string, builtin_str): 31 | out = string 32 | else: 33 | out = string.decode(encoding) 34 | 35 | return out 36 | 37 | 38 | def unicode_is_ascii(u_string): 39 | """Determine if unicode string only contains ASCII characters. 40 | 41 | :param str u_string: unicode string to check. Must be unicode 42 | and not Python 2 `str`. 43 | :rtype: bool 44 | """ 45 | assert isinstance(u_string, str) 46 | try: 47 | u_string.encode("ascii") 48 | return True 49 | except UnicodeEncodeError: 50 | return False 51 | -------------------------------------------------------------------------------- /app/server/lib/charset_normalizer/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Charset-Normalizer 3 | ~~~~~~~~~~~~~~ 4 | The Real First Universal Charset Detector. 5 | A library that helps you read text from an unknown charset encoding. 6 | Motivated by chardet, This package is trying to resolve the issue by taking a new approach. 7 | All IANA character set names for which the Python core library provides codecs are supported. 8 | 9 | Basic usage: 10 | >>> from charset_normalizer import from_bytes 11 | >>> results = from_bytes('Bсеки човек има право на образование. Oбразованието!'.encode('utf_8')) 12 | >>> best_guess = results.best() 13 | >>> str(best_guess) 14 | 'Bсеки човек има право на образование. Oбразованието!' 15 | 16 | Others methods and usages are available - see the full documentation 17 | at . 18 | :copyright: (c) 2021 by Ahmed TAHRI 19 | :license: MIT, see LICENSE for more details. 20 | """ 21 | 22 | from __future__ import annotations 23 | 24 | import logging 25 | 26 | from .api import from_bytes, from_fp, from_path, is_binary 27 | from .legacy import detect 28 | from .models import CharsetMatch, CharsetMatches 29 | from .utils import set_logging_handler 30 | from .version import VERSION, __version__ 31 | 32 | __all__ = ( 33 | "from_fp", 34 | "from_path", 35 | "from_bytes", 36 | "is_binary", 37 | "detect", 38 | "CharsetMatch", 39 | "CharsetMatches", 40 | "__version__", 41 | "VERSION", 42 | "set_logging_handler", 43 | ) 44 | 45 | # Attach a NullHandler to the top level logger by default 46 | # https://docs.python.org/3.3/howto/logging.html#configuring-logging-for-a-library 47 | 48 | logging.getLogger("charset_normalizer").addHandler(logging.NullHandler()) 49 | -------------------------------------------------------------------------------- /app/server/lib/watchdog/utils/platform.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Yesudeep Mangalapilly 2 | # Copyright 2012 Google, Inc & contributors. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | from __future__ import annotations 18 | 19 | import sys 20 | 21 | PLATFORM_WINDOWS = "windows" 22 | PLATFORM_LINUX = "linux" 23 | PLATFORM_BSD = "bsd" 24 | PLATFORM_DARWIN = "darwin" 25 | PLATFORM_UNKNOWN = "unknown" 26 | 27 | 28 | def get_platform_name(): 29 | if sys.platform.startswith("win"): 30 | return PLATFORM_WINDOWS 31 | elif sys.platform.startswith("darwin"): 32 | return PLATFORM_DARWIN 33 | elif sys.platform.startswith("linux"): 34 | return PLATFORM_LINUX 35 | elif sys.platform.startswith(("dragonfly", "freebsd", "netbsd", "openbsd", "bsd")): 36 | return PLATFORM_BSD 37 | else: 38 | return PLATFORM_UNKNOWN 39 | 40 | 41 | __platform__ = get_platform_name() 42 | 43 | 44 | def is_linux(): 45 | return __platform__ == PLATFORM_LINUX 46 | 47 | 48 | def is_bsd(): 49 | return __platform__ == PLATFORM_BSD 50 | 51 | 52 | def is_darwin(): 53 | return __platform__ == PLATFORM_DARWIN 54 | 55 | 56 | def is_windows(): 57 | return __platform__ == PLATFORM_WINDOWS 58 | -------------------------------------------------------------------------------- /extensions/preview-cgi/app/ui/js/utils.js: -------------------------------------------------------------------------------- 1 | export function autoResizeUI() { 2 | if (window.innerWidth > 768) { 3 | let scale = Math.min(Math.max(window.innerWidth / 1440, 0.8), 1.2); 4 | document.documentElement.style.setProperty('--ui-scale', scale.toFixed(3)); 5 | } else { 6 | document.documentElement.style.setProperty('--ui-scale', '1.0'); 7 | } 8 | } 9 | 10 | export function showToast(message, type = 'info') { 11 | const container = document.getElementById('toast-container'); 12 | if (!container) return; 13 | 14 | const iconMap = { 15 | 'info': '', 16 | 'success': '', 17 | 'error': '', 18 | 'warning': '', 19 | 'loading': '' 20 | }; 21 | 22 | const toast = document.createElement('div'); 23 | toast.className = `toast toast-${type}`; 24 | toast.innerHTML = ` 25 |
    ${iconMap[type] || iconMap['info']}
    26 |
    ${message}
    27 | `; 28 | 29 | container.appendChild(toast); 30 | // Limit max toasts 31 | if (container.childElementCount > 5) { 32 | container.firstChild.remove(); 33 | } 34 | 35 | // Animation frame for smooth entry 36 | requestAnimationFrame(() => toast.classList.add('show')); 37 | 38 | // Auto remove 39 | if (type !== 'loading') { 40 | setTimeout(() => { 41 | toast.classList.remove('show'); 42 | setTimeout(() => toast.remove(), 300); 43 | }, 3000); 44 | } 45 | } 46 | 47 | export function formatTime(seconds) { 48 | if (isNaN(seconds)) return "0:00"; 49 | const m = Math.floor(seconds / 60); 50 | const s = Math.floor(seconds % 60); 51 | return `${m}:${s < 10 ? '0' : ''}${s}`; 52 | } 53 | -------------------------------------------------------------------------------- /app/server/lib/jinja2/optimizer.py: -------------------------------------------------------------------------------- 1 | """The optimizer tries to constant fold expressions and modify the AST 2 | in place so that it should be faster to evaluate. 3 | 4 | Because the AST does not contain all the scoping information and the 5 | compiler has to find that out, we cannot do all the optimizations we 6 | want. For example, loop unrolling doesn't work because unrolled loops 7 | would have a different scope. The solution would be a second syntax tree 8 | that stored the scoping rules. 9 | """ 10 | 11 | import typing as t 12 | 13 | from . import nodes 14 | from .visitor import NodeTransformer 15 | 16 | if t.TYPE_CHECKING: 17 | from .environment import Environment 18 | 19 | 20 | def optimize(node: nodes.Node, environment: "Environment") -> nodes.Node: 21 | """The context hint can be used to perform an static optimization 22 | based on the context given.""" 23 | optimizer = Optimizer(environment) 24 | return t.cast(nodes.Node, optimizer.visit(node)) 25 | 26 | 27 | class Optimizer(NodeTransformer): 28 | def __init__(self, environment: "t.Optional[Environment]") -> None: 29 | self.environment = environment 30 | 31 | def generic_visit( 32 | self, node: nodes.Node, *args: t.Any, **kwargs: t.Any 33 | ) -> nodes.Node: 34 | node = super().generic_visit(node, *args, **kwargs) 35 | 36 | # Do constant folding. Some other nodes besides Expr have 37 | # as_const, but folding them causes errors later on. 38 | if isinstance(node, nodes.Expr): 39 | try: 40 | return nodes.Const.from_untrusted( 41 | node.as_const(args[0] if args else None), 42 | lineno=node.lineno, 43 | environment=self.environment, 44 | ) 45 | except nodes.Impossible: 46 | pass 47 | 48 | return node 49 | -------------------------------------------------------------------------------- /app/server/lib/share/man/man1/mid3iconv.1: -------------------------------------------------------------------------------- 1 | .\" Man page generated from reStructuredText. 2 | . 3 | .TH MID3ICONV 1 "" "" "" 4 | .SH NAME 5 | mid3iconv \- convert ID3 tag encodings 6 | . 7 | .nr rst2man-indent-level 0 8 | . 9 | .de1 rstReportMargin 10 | \\$1 \\n[an-margin] 11 | level \\n[rst2man-indent-level] 12 | level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] 13 | - 14 | \\n[rst2man-indent0] 15 | \\n[rst2man-indent1] 16 | \\n[rst2man-indent2] 17 | .. 18 | .de1 INDENT 19 | .\" .rstReportMargin pre: 20 | . RS \\$1 21 | . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] 22 | . nr rst2man-indent-level +1 23 | .\" .rstReportMargin post: 24 | .. 25 | .de UNINDENT 26 | . RE 27 | .\" indent \\n[an-margin] 28 | .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] 29 | .nr rst2man-indent-level -1 30 | .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] 31 | .in \\n[rst2man-indent\\n[rst2man-indent-level]]u 32 | .. 33 | .SH SYNOPSIS 34 | .sp 35 | \fBmid3iconv\fP [\fIoptions\fP] \fIfilename\fP ... 36 | .SH DESCRIPTION 37 | .sp 38 | \fBmid3iconv\fP converts ID3 tags from legacy encodings to Unicode and stores 39 | them using the ID3v2 format. 40 | .SH OPTIONS 41 | .INDENT 0.0 42 | .TP 43 | .B \-\-debug\fP,\fB \-d 44 | Print updated tags 45 | .TP 46 | .B \-\-dry\-run\fP,\fB \-p 47 | Do not actually modify files 48 | .TP 49 | .B \-\-encoding\fP,\fB \-e 50 | Convert from this encoding. By default, your locale\(aqs default encoding is 51 | used. 52 | .TP 53 | .B \-\-force\-v1 54 | Use an ID3v1 tag even if an ID3v2 tag is present 55 | .TP 56 | .B \-\-quiet\fP,\fB \-q 57 | Only output errors 58 | .TP 59 | .B \-\-remove\-v1 60 | Remove any ID3v1 tag after processing the files 61 | .UNINDENT 62 | .SH AUTHOR 63 | .sp 64 | Emfox Zhou. 65 | .sp 66 | Based on id3iconv (\fI\%http://www.cs.berkeley.edu/~zf/id3iconv/\fP) by Feng Zhou. 67 | .\" Generated by docutils manpage writer. 68 | . 69 | -------------------------------------------------------------------------------- /app/server/lib/blinker-1.9.0.dist-info/METADATA: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.3 2 | Name: blinker 3 | Version: 1.9.0 4 | Summary: Fast, simple object-to-object and broadcast signaling 5 | Author: Jason Kirtland 6 | Maintainer-email: Pallets Ecosystem 7 | Requires-Python: >=3.9 8 | Description-Content-Type: text/markdown 9 | Classifier: Development Status :: 5 - Production/Stable 10 | Classifier: License :: OSI Approved :: MIT License 11 | Classifier: Programming Language :: Python 12 | Classifier: Typing :: Typed 13 | Project-URL: Chat, https://discord.gg/pallets 14 | Project-URL: Documentation, https://blinker.readthedocs.io 15 | Project-URL: Source, https://github.com/pallets-eco/blinker/ 16 | 17 | # Blinker 18 | 19 | Blinker provides a fast dispatching system that allows any number of 20 | interested parties to subscribe to events, or "signals". 21 | 22 | 23 | ## Pallets Community Ecosystem 24 | 25 | > [!IMPORTANT]\ 26 | > This project is part of the Pallets Community Ecosystem. Pallets is the open 27 | > source organization that maintains Flask; Pallets-Eco enables community 28 | > maintenance of related projects. If you are interested in helping maintain 29 | > this project, please reach out on [the Pallets Discord server][discord]. 30 | > 31 | > [discord]: https://discord.gg/pallets 32 | 33 | 34 | ## Example 35 | 36 | Signal receivers can subscribe to specific senders or receive signals 37 | sent by any sender. 38 | 39 | ```pycon 40 | >>> from blinker import signal 41 | >>> started = signal('round-started') 42 | >>> def each(round): 43 | ... print(f"Round {round}") 44 | ... 45 | >>> started.connect(each) 46 | 47 | >>> def round_two(round): 48 | ... print("This is round two.") 49 | ... 50 | >>> started.connect(round_two, sender=2) 51 | 52 | >>> for round in range(1, 4): 53 | ... started.send(round) 54 | ... 55 | Round 1! 56 | Round 2! 57 | This is round two. 58 | Round 3! 59 | ``` 60 | 61 | -------------------------------------------------------------------------------- /app/server/lib/mutagen-1.47.0.dist-info/METADATA: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.1 2 | Name: mutagen 3 | Version: 1.47.0 4 | Summary: read and write audio tags for many formats 5 | Home-page: https://github.com/quodlibet/mutagen 6 | Author: Christoph Reiter 7 | Author-email: reiter.christoph@gmail.com 8 | License: GPL-2.0-or-later 9 | Classifier: Operating System :: OS Independent 10 | Classifier: Programming Language :: Python :: 3 11 | Classifier: Programming Language :: Python :: Implementation :: CPython 12 | Classifier: Programming Language :: Python :: Implementation :: PyPy 13 | Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+) 14 | Classifier: Topic :: Multimedia :: Sound/Audio 15 | Requires-Python: >=3.7 16 | License-File: COPYING 17 | 18 | .. image:: https://raw.githubusercontent.com/quodlibet/mutagen/master/docs/images/logo.svg 19 | :align: center 20 | :width: 400px 21 | 22 | | 23 | 24 | Mutagen is a Python module to handle audio metadata. It supports ASF, FLAC, 25 | MP4, Monkey's Audio, MP3, Musepack, Ogg Opus, Ogg FLAC, Ogg Speex, Ogg Theora, 26 | Ogg Vorbis, True Audio, WavPack, OptimFROG, and AIFF audio files. All 27 | versions of ID3v2 are supported, and all standard ID3v2.4 frames are parsed. 28 | It can read Xing headers to accurately calculate the bitrate and length of 29 | MP3s. ID3 and APEv2 tags can be edited regardless of audio format. It can also 30 | manipulate Ogg streams on an individual packet/page level. 31 | 32 | Mutagen works with Python 3.7+ (CPython and PyPy) on Linux, Windows and macOS, 33 | and has no dependencies outside the Python standard library. Mutagen is licensed 34 | under `the GPL version 2 or 35 | later `__. 36 | 37 | For more information visit https://mutagen.readthedocs.org 38 | 39 | .. image:: https://codecov.io/gh/quodlibet/mutagen/branch/master/graph/badge.svg 40 | :target: https://codecov.io/gh/quodlibet/mutagen 41 | -------------------------------------------------------------------------------- /app/server/lib/flask/globals.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import typing as t 4 | from contextvars import ContextVar 5 | 6 | from werkzeug.local import LocalProxy 7 | 8 | if t.TYPE_CHECKING: # pragma: no cover 9 | from .app import Flask 10 | from .ctx import _AppCtxGlobals 11 | from .ctx import AppContext 12 | from .ctx import RequestContext 13 | from .sessions import SessionMixin 14 | from .wrappers import Request 15 | 16 | 17 | _no_app_msg = """\ 18 | Working outside of application context. 19 | 20 | This typically means that you attempted to use functionality that needed 21 | the current application. To solve this, set up an application context 22 | with app.app_context(). See the documentation for more information.\ 23 | """ 24 | _cv_app: ContextVar[AppContext] = ContextVar("flask.app_ctx") 25 | app_ctx: AppContext = LocalProxy( # type: ignore[assignment] 26 | _cv_app, unbound_message=_no_app_msg 27 | ) 28 | current_app: Flask = LocalProxy( # type: ignore[assignment] 29 | _cv_app, "app", unbound_message=_no_app_msg 30 | ) 31 | g: _AppCtxGlobals = LocalProxy( # type: ignore[assignment] 32 | _cv_app, "g", unbound_message=_no_app_msg 33 | ) 34 | 35 | _no_req_msg = """\ 36 | Working outside of request context. 37 | 38 | This typically means that you attempted to use functionality that needed 39 | an active HTTP request. Consult the documentation on testing for 40 | information about how to avoid this problem.\ 41 | """ 42 | _cv_request: ContextVar[RequestContext] = ContextVar("flask.request_ctx") 43 | request_ctx: RequestContext = LocalProxy( # type: ignore[assignment] 44 | _cv_request, unbound_message=_no_req_msg 45 | ) 46 | request: Request = LocalProxy( # type: ignore[assignment] 47 | _cv_request, "request", unbound_message=_no_req_msg 48 | ) 49 | session: SessionMixin = LocalProxy( # type: ignore[assignment] 50 | _cv_request, "session", unbound_message=_no_req_msg 51 | ) 52 | -------------------------------------------------------------------------------- /.github/workflows/extensions-build.yml: -------------------------------------------------------------------------------- 1 | name: Build Extensions 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | paths: 7 | - 'extensions/**' 8 | 9 | jobs: 10 | build-extensions: 11 | runs-on: ubuntu-22.04 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v4 15 | 16 | - name: Install fnpack 17 | run: | 18 | wget https://static2.fnnas.com/fnpack/fnpack-1.0.4-linux-amd64 -O fnpack 19 | chmod +x fnpack 20 | sudo mv fnpack /usr/local/bin/ 21 | 22 | # =============================== 23 | # Build 2FMusic Preview (CGI) 24 | # =============================== 25 | - name: Build Preview (CGI) 26 | id: build_preview_cgi 27 | run: | 28 | echo "📦 Building Preview Extension (CGI)..." 29 | cd extensions/preview-cgi 30 | 31 | # Compile C Code 32 | echo "🔨 Compiling index.c..." 33 | gcc -static -O2 -o app/ui/index.cgi app/ui/index.c 34 | chmod +x app/ui/index.cgi 35 | rm app/ui/index.c 36 | 37 | # Package 38 | fnpack build 39 | 40 | # Get Version from Manifest 41 | VERSION=$(grep "^version" manifest | awk -F'=' '{print $2}' | tr -d '[:space:]') 42 | SHORT_SHA=$(git rev-parse --short HEAD) 43 | PKG_NAME="2fmusic-preview-cgi-${VERSION}-${SHORT_SHA}.fpk" 44 | 45 | # Find and Move 46 | if [ -f "2fmusic-preview.fpk" ]; then 47 | mv 2fmusic-preview.fpk "../../$PKG_NAME" 48 | else 49 | mv *.fpk "../../$PKG_NAME" || echo "Warning: No fpk found!" 50 | fi 51 | 52 | cd ../.. 53 | echo "pkg_name=${PKG_NAME}" >> $GITHUB_OUTPUT 54 | echo "✅ Built: $PKG_NAME" 55 | 56 | - name: Upload CGI Extension 57 | uses: actions/upload-artifact@v4 58 | with: 59 | name: 2fmusic-preview-cgi 60 | path: ${{ steps.build_preview_cgi.outputs.pkg_name }} -------------------------------------------------------------------------------- /app/server/lib/blinker/_utilities.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import collections.abc as c 4 | import inspect 5 | import typing as t 6 | from weakref import ref 7 | from weakref import WeakMethod 8 | 9 | T = t.TypeVar("T") 10 | 11 | 12 | class Symbol: 13 | """A constant symbol, nicer than ``object()``. Repeated calls return the 14 | same instance. 15 | 16 | >>> Symbol('foo') is Symbol('foo') 17 | True 18 | >>> Symbol('foo') 19 | foo 20 | """ 21 | 22 | symbols: t.ClassVar[dict[str, Symbol]] = {} 23 | 24 | def __new__(cls, name: str) -> Symbol: 25 | if name in cls.symbols: 26 | return cls.symbols[name] 27 | 28 | obj = super().__new__(cls) 29 | cls.symbols[name] = obj 30 | return obj 31 | 32 | def __init__(self, name: str) -> None: 33 | self.name = name 34 | 35 | def __repr__(self) -> str: 36 | return self.name 37 | 38 | def __getnewargs__(self) -> tuple[t.Any, ...]: 39 | return (self.name,) 40 | 41 | 42 | def make_id(obj: object) -> c.Hashable: 43 | """Get a stable identifier for a receiver or sender, to be used as a dict 44 | key or in a set. 45 | """ 46 | if inspect.ismethod(obj): 47 | # The id of a bound method is not stable, but the id of the unbound 48 | # function and instance are. 49 | return id(obj.__func__), id(obj.__self__) 50 | 51 | if isinstance(obj, (str, int)): 52 | # Instances with the same value always compare equal and have the same 53 | # hash, even if the id may change. 54 | return obj 55 | 56 | # Assume other types are not hashable but will always be the same instance. 57 | return id(obj) 58 | 59 | 60 | def make_ref(obj: T, callback: c.Callable[[ref[T]], None] | None = None) -> ref[T]: 61 | if inspect.ismethod(obj): 62 | return WeakMethod(obj, callback) # type: ignore[arg-type, return-value] 63 | 64 | return ref(obj, callback) 65 | -------------------------------------------------------------------------------- /app/server/lib/urllib3/http2/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from importlib.metadata import version 4 | 5 | __all__ = [ 6 | "inject_into_urllib3", 7 | "extract_from_urllib3", 8 | ] 9 | 10 | import typing 11 | 12 | orig_HTTPSConnection: typing.Any = None 13 | 14 | 15 | def inject_into_urllib3() -> None: 16 | # First check if h2 version is valid 17 | h2_version = version("h2") 18 | if not h2_version.startswith("4."): 19 | raise ImportError( 20 | "urllib3 v2 supports h2 version 4.x.x, currently " 21 | f"the 'h2' module is compiled with {h2_version!r}. " 22 | "See: https://github.com/urllib3/urllib3/issues/3290" 23 | ) 24 | 25 | # Import here to avoid circular dependencies. 26 | from .. import connection as urllib3_connection 27 | from .. import util as urllib3_util 28 | from ..connectionpool import HTTPSConnectionPool 29 | from ..util import ssl_ as urllib3_util_ssl 30 | from .connection import HTTP2Connection 31 | 32 | global orig_HTTPSConnection 33 | orig_HTTPSConnection = urllib3_connection.HTTPSConnection 34 | 35 | HTTPSConnectionPool.ConnectionCls = HTTP2Connection 36 | urllib3_connection.HTTPSConnection = HTTP2Connection # type: ignore[misc] 37 | 38 | # TODO: Offer 'http/1.1' as well, but for testing purposes this is handy. 39 | urllib3_util.ALPN_PROTOCOLS = ["h2"] 40 | urllib3_util_ssl.ALPN_PROTOCOLS = ["h2"] 41 | 42 | 43 | def extract_from_urllib3() -> None: 44 | from .. import connection as urllib3_connection 45 | from .. import util as urllib3_util 46 | from ..connectionpool import HTTPSConnectionPool 47 | from ..util import ssl_ as urllib3_util_ssl 48 | 49 | HTTPSConnectionPool.ConnectionCls = orig_HTTPSConnection 50 | urllib3_connection.HTTPSConnection = orig_HTTPSConnection # type: ignore[misc] 51 | 52 | urllib3_util.ALPN_PROTOCOLS = ["http/1.1"] 53 | urllib3_util_ssl.ALPN_PROTOCOLS = ["http/1.1"] 54 | -------------------------------------------------------------------------------- /app/server/lib/share/man/man1/moggsplit.1: -------------------------------------------------------------------------------- 1 | .\" Man page generated from reStructuredText. 2 | . 3 | .TH MOGGSPLIT 1 "" "" "" 4 | .SH NAME 5 | moggsplit \- split Ogg logical streams 6 | . 7 | .nr rst2man-indent-level 0 8 | . 9 | .de1 rstReportMargin 10 | \\$1 \\n[an-margin] 11 | level \\n[rst2man-indent-level] 12 | level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] 13 | - 14 | \\n[rst2man-indent0] 15 | \\n[rst2man-indent1] 16 | \\n[rst2man-indent2] 17 | .. 18 | .de1 INDENT 19 | .\" .rstReportMargin pre: 20 | . RS \\$1 21 | . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] 22 | . nr rst2man-indent-level +1 23 | .\" .rstReportMargin post: 24 | .. 25 | .de UNINDENT 26 | . RE 27 | .\" indent \\n[an-margin] 28 | .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] 29 | .nr rst2man-indent-level -1 30 | .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] 31 | .in \\n[rst2man-indent\\n[rst2man-indent-level]]u 32 | .. 33 | .SH SYNOPSIS 34 | .sp 35 | \fBmoggsplit\fP \fIfilename\fP ... 36 | .SH DESCRIPTION 37 | .sp 38 | \fBmoggsplit\fP splits a multiplexed Ogg stream into separate files. For 39 | example, it can separate an OGM into separate Ogg DivX and Ogg Vorbis 40 | streams, or a chained Ogg Vorbis file into two separate files. 41 | .SH OPTIONS 42 | .INDENT 0.0 43 | .TP 44 | .B \-\-extension 45 | Use the supplied extension when generating new files; the default is 46 | \fBogg\fP\&. 47 | .TP 48 | .B \-\-pattern 49 | Use the supplied pattern when generating new files. This is a Python 50 | keyword format string with three variables, \fIbase\fP for the original 51 | file\(aqs base name, \fIstream\fP for the stream\(aqs serial number, and ext for 52 | the extension give by \fB\-\-extension\fP\&. 53 | .sp 54 | The default is \fB%(base)s\-%(stream)d.%(ext)s\fP\&. 55 | .TP 56 | .B \-\-m3u 57 | Generate an m3u playlist along with the newly generated files. Useful 58 | for large chained Oggs. 59 | .UNINDENT 60 | .SH AUTHOR 61 | .sp 62 | Joe Wreschnig 63 | .\" Generated by docutils manpage writer. 64 | . 65 | -------------------------------------------------------------------------------- /app/server/lib/share/man/man1/mid3cp.1: -------------------------------------------------------------------------------- 1 | .\" Man page generated from reStructuredText. 2 | . 3 | .TH MID3CP 1 "" "" "" 4 | .SH NAME 5 | mid3cp \- copy ID3 tags 6 | . 7 | .nr rst2man-indent-level 0 8 | . 9 | .de1 rstReportMargin 10 | \\$1 \\n[an-margin] 11 | level \\n[rst2man-indent-level] 12 | level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] 13 | - 14 | \\n[rst2man-indent0] 15 | \\n[rst2man-indent1] 16 | \\n[rst2man-indent2] 17 | .. 18 | .de1 INDENT 19 | .\" .rstReportMargin pre: 20 | . RS \\$1 21 | . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] 22 | . nr rst2man-indent-level +1 23 | .\" .rstReportMargin post: 24 | .. 25 | .de UNINDENT 26 | . RE 27 | .\" indent \\n[an-margin] 28 | .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] 29 | .nr rst2man-indent-level -1 30 | .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] 31 | .in \\n[rst2man-indent\\n[rst2man-indent-level]]u 32 | .. 33 | .SH SYNOPSIS 34 | .sp 35 | \fBmid3cp\fP [\fIoptions\fP] \fIsource\fP \fIdest\fP 36 | .SH DESCRIPTION 37 | .sp 38 | \fBmid3cp\fP copies the ID3 tags from a source file to a destination file. 39 | .sp 40 | It is designed to provide similar functionality to id3lib\(aqs id3cp tool, and can 41 | optionally write ID3v1 tags. It can also exclude specific tags from being 42 | copied. 43 | .SH OPTIONS 44 | .INDENT 0.0 45 | .TP 46 | .B \-\-verbose\fP,\fB \-v 47 | Be verbose: state all operations performed, and list tags in source file. 48 | .TP 49 | .B \-\-write\-v1 50 | Write ID3v1 tags to the destination file, derived from the ID3v2 tags. 51 | .TP 52 | .B \-\-exclude\-tag\fP,\fB \-x 53 | Exclude a specific tag from being copied. Can be specified multiple times. 54 | .TP 55 | .B \-\-merge 56 | Copy over frames instead of replacing the whole ID3 tag. The tag version 57 | of \fIdest\fP will be used. In case \fIdest\fP has no ID3 tag this option has no 58 | effect. 59 | .UNINDENT 60 | .SH AUTHOR 61 | .sp 62 | Marcus Sundman. 63 | .sp 64 | Based on id3cp (part of id3lib) by Dirk Mahoney and Scott Thomas Haug. 65 | .\" Generated by docutils manpage writer. 66 | . 67 | -------------------------------------------------------------------------------- /app/server/lib/watchdog/utils/event_debouncer.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import logging 4 | import threading 5 | 6 | from watchdog.utils import BaseThread 7 | 8 | logger = logging.getLogger(__name__) 9 | 10 | 11 | class EventDebouncer(BaseThread): 12 | """Background thread for debouncing event handling. 13 | 14 | When an event is received, wait until the configured debounce interval 15 | passes before calling the callback. If additional events are received 16 | before the interval passes, reset the timer and keep waiting. When the 17 | debouncing interval passes, the callback will be called with a list of 18 | events in the order in which they were received. 19 | """ 20 | 21 | def __init__(self, debounce_interval_seconds, events_callback): 22 | super().__init__() 23 | self.debounce_interval_seconds = debounce_interval_seconds 24 | self.events_callback = events_callback 25 | 26 | self._events = [] 27 | self._cond = threading.Condition() 28 | 29 | def handle_event(self, event): 30 | with self._cond: 31 | self._events.append(event) 32 | self._cond.notify() 33 | 34 | def stop(self): 35 | with self._cond: 36 | super().stop() 37 | self._cond.notify() 38 | 39 | def run(self): 40 | with self._cond: 41 | while True: 42 | # Wait for first event (or shutdown). 43 | self._cond.wait() 44 | 45 | if self.debounce_interval_seconds: 46 | # Wait for additional events (or shutdown) until the debounce interval passes. 47 | while self.should_keep_running(): 48 | if not self._cond.wait(timeout=self.debounce_interval_seconds): 49 | break 50 | 51 | if not self.should_keep_running(): 52 | break 53 | 54 | events = self._events 55 | self._events = [] 56 | self.events_callback(events) 57 | -------------------------------------------------------------------------------- /app/server/lib/jinja2/__init__.py: -------------------------------------------------------------------------------- 1 | """Jinja is a template engine written in pure Python. It provides a 2 | non-XML syntax that supports inline expressions and an optional 3 | sandboxed environment. 4 | """ 5 | 6 | from .bccache import BytecodeCache as BytecodeCache 7 | from .bccache import FileSystemBytecodeCache as FileSystemBytecodeCache 8 | from .bccache import MemcachedBytecodeCache as MemcachedBytecodeCache 9 | from .environment import Environment as Environment 10 | from .environment import Template as Template 11 | from .exceptions import TemplateAssertionError as TemplateAssertionError 12 | from .exceptions import TemplateError as TemplateError 13 | from .exceptions import TemplateNotFound as TemplateNotFound 14 | from .exceptions import TemplateRuntimeError as TemplateRuntimeError 15 | from .exceptions import TemplatesNotFound as TemplatesNotFound 16 | from .exceptions import TemplateSyntaxError as TemplateSyntaxError 17 | from .exceptions import UndefinedError as UndefinedError 18 | from .loaders import BaseLoader as BaseLoader 19 | from .loaders import ChoiceLoader as ChoiceLoader 20 | from .loaders import DictLoader as DictLoader 21 | from .loaders import FileSystemLoader as FileSystemLoader 22 | from .loaders import FunctionLoader as FunctionLoader 23 | from .loaders import ModuleLoader as ModuleLoader 24 | from .loaders import PackageLoader as PackageLoader 25 | from .loaders import PrefixLoader as PrefixLoader 26 | from .runtime import ChainableUndefined as ChainableUndefined 27 | from .runtime import DebugUndefined as DebugUndefined 28 | from .runtime import make_logging_undefined as make_logging_undefined 29 | from .runtime import StrictUndefined as StrictUndefined 30 | from .runtime import Undefined as Undefined 31 | from .utils import clear_caches as clear_caches 32 | from .utils import is_undefined as is_undefined 33 | from .utils import pass_context as pass_context 34 | from .utils import pass_environment as pass_environment 35 | from .utils import pass_eval_context as pass_eval_context 36 | from .utils import select_autoescape as select_autoescape 37 | 38 | __version__ = "3.1.6" 39 | -------------------------------------------------------------------------------- /app/server/lib/colorama/tests/isatty_test.py: -------------------------------------------------------------------------------- 1 | # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. 2 | import sys 3 | from unittest import TestCase, main 4 | 5 | from ..ansitowin32 import StreamWrapper, AnsiToWin32 6 | from .utils import pycharm, replace_by, replace_original_by, StreamTTY, StreamNonTTY 7 | 8 | 9 | def is_a_tty(stream): 10 | return StreamWrapper(stream, None).isatty() 11 | 12 | class IsattyTest(TestCase): 13 | 14 | def test_TTY(self): 15 | tty = StreamTTY() 16 | self.assertTrue(is_a_tty(tty)) 17 | with pycharm(): 18 | self.assertTrue(is_a_tty(tty)) 19 | 20 | def test_nonTTY(self): 21 | non_tty = StreamNonTTY() 22 | self.assertFalse(is_a_tty(non_tty)) 23 | with pycharm(): 24 | self.assertFalse(is_a_tty(non_tty)) 25 | 26 | def test_withPycharm(self): 27 | with pycharm(): 28 | self.assertTrue(is_a_tty(sys.stderr)) 29 | self.assertTrue(is_a_tty(sys.stdout)) 30 | 31 | def test_withPycharmTTYOverride(self): 32 | tty = StreamTTY() 33 | with pycharm(), replace_by(tty): 34 | self.assertTrue(is_a_tty(tty)) 35 | 36 | def test_withPycharmNonTTYOverride(self): 37 | non_tty = StreamNonTTY() 38 | with pycharm(), replace_by(non_tty): 39 | self.assertFalse(is_a_tty(non_tty)) 40 | 41 | def test_withPycharmNoneOverride(self): 42 | with pycharm(): 43 | with replace_by(None), replace_original_by(None): 44 | self.assertFalse(is_a_tty(None)) 45 | self.assertFalse(is_a_tty(StreamNonTTY())) 46 | self.assertTrue(is_a_tty(StreamTTY())) 47 | 48 | def test_withPycharmStreamWrapped(self): 49 | with pycharm(): 50 | self.assertTrue(AnsiToWin32(StreamTTY()).stream.isatty()) 51 | self.assertFalse(AnsiToWin32(StreamNonTTY()).stream.isatty()) 52 | self.assertTrue(AnsiToWin32(sys.stdout).stream.isatty()) 53 | self.assertTrue(AnsiToWin32(sys.stderr).stream.isatty()) 54 | 55 | 56 | if __name__ == '__main__': 57 | main() 58 | -------------------------------------------------------------------------------- /app/server/lib/idna/intranges.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a list of integers, made up of (hopefully) a small number of long runs 3 | of consecutive integers, compute a representation of the form 4 | ((start1, end1), (start2, end2) ...). Then answer the question "was x present 5 | in the original list?" in time O(log(# runs)). 6 | """ 7 | 8 | import bisect 9 | from typing import List, Tuple 10 | 11 | 12 | def intranges_from_list(list_: List[int]) -> Tuple[int, ...]: 13 | """Represent a list of integers as a sequence of ranges: 14 | ((start_0, end_0), (start_1, end_1), ...), such that the original 15 | integers are exactly those x such that start_i <= x < end_i for some i. 16 | 17 | Ranges are encoded as single integers (start << 32 | end), not as tuples. 18 | """ 19 | 20 | sorted_list = sorted(list_) 21 | ranges = [] 22 | last_write = -1 23 | for i in range(len(sorted_list)): 24 | if i + 1 < len(sorted_list): 25 | if sorted_list[i] == sorted_list[i + 1] - 1: 26 | continue 27 | current_range = sorted_list[last_write + 1 : i + 1] 28 | ranges.append(_encode_range(current_range[0], current_range[-1] + 1)) 29 | last_write = i 30 | 31 | return tuple(ranges) 32 | 33 | 34 | def _encode_range(start: int, end: int) -> int: 35 | return (start << 32) | end 36 | 37 | 38 | def _decode_range(r: int) -> Tuple[int, int]: 39 | return (r >> 32), (r & ((1 << 32) - 1)) 40 | 41 | 42 | def intranges_contain(int_: int, ranges: Tuple[int, ...]) -> bool: 43 | """Determine if `int_` falls into one of the ranges in `ranges`.""" 44 | tuple_ = _encode_range(int_, 0) 45 | pos = bisect.bisect_left(ranges, tuple_) 46 | # we could be immediately ahead of a tuple (start, end) 47 | # with start < int_ <= end 48 | if pos > 0: 49 | left, right = _decode_range(ranges[pos - 1]) 50 | if left <= int_ < right: 51 | return True 52 | # or we could be immediately behind a tuple (int_, end) 53 | if pos < len(ranges): 54 | left, _ = _decode_range(ranges[pos]) 55 | if left == int_: 56 | return True 57 | return False 58 | -------------------------------------------------------------------------------- /app/server/lib/mutagen/_riff.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017 Borewit 2 | # Copyright (C) 2019-2020 Philipp Wolfer 3 | # 4 | # This program is free software; you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation; either version 2 of the License, or 7 | # (at your option) any later version. 8 | 9 | """Resource Interchange File Format (RIFF).""" 10 | 11 | import struct 12 | from struct import pack 13 | 14 | from mutagen._iff import ( 15 | IffChunk, 16 | IffContainerChunkMixin, 17 | IffFile, 18 | InvalidChunk, 19 | ) 20 | 21 | 22 | class RiffChunk(IffChunk): 23 | """Generic RIFF chunk""" 24 | 25 | @classmethod 26 | def parse_header(cls, header): 27 | return struct.unpack('<4sI', header) 28 | 29 | @classmethod 30 | def get_class(cls, id): 31 | if id in (u'LIST', u'RIFF'): 32 | return RiffListChunk 33 | else: 34 | return cls 35 | 36 | def write_new_header(self, id_, size): 37 | self._fileobj.write(pack('<4sI', id_, size)) 38 | 39 | def write_size(self): 40 | self._fileobj.write(pack(' 6 | Requires-Python: >=3.8 7 | Description-Content-Type: text/markdown 8 | Classifier: Development Status :: 5 - Production/Stable 9 | Classifier: Intended Audience :: Developers 10 | Classifier: License :: OSI Approved :: BSD License 11 | Classifier: Operating System :: OS Independent 12 | Classifier: Programming Language :: Python 13 | Classifier: Typing :: Typed 14 | Project-URL: Changes, https://itsdangerous.palletsprojects.com/changes/ 15 | Project-URL: Chat, https://discord.gg/pallets 16 | Project-URL: Documentation, https://itsdangerous.palletsprojects.com/ 17 | Project-URL: Donate, https://palletsprojects.com/donate 18 | Project-URL: Source, https://github.com/pallets/itsdangerous/ 19 | 20 | # ItsDangerous 21 | 22 | ... so better sign this 23 | 24 | Various helpers to pass data to untrusted environments and to get it 25 | back safe and sound. Data is cryptographically signed to ensure that a 26 | token has not been tampered with. 27 | 28 | It's possible to customize how data is serialized. Data is compressed as 29 | needed. A timestamp can be added and verified automatically while 30 | loading a token. 31 | 32 | 33 | ## A Simple Example 34 | 35 | Here's how you could generate a token for transmitting a user's id and 36 | name between web requests. 37 | 38 | ```python 39 | from itsdangerous import URLSafeSerializer 40 | auth_s = URLSafeSerializer("secret key", "auth") 41 | token = auth_s.dumps({"id": 5, "name": "itsdangerous"}) 42 | 43 | print(token) 44 | # eyJpZCI6NSwibmFtZSI6Iml0c2Rhbmdlcm91cyJ9.6YP6T0BaO67XP--9UzTrmurXSmg 45 | 46 | data = auth_s.loads(token) 47 | print(data["name"]) 48 | # itsdangerous 49 | ``` 50 | 51 | 52 | ## Donate 53 | 54 | The Pallets organization develops and supports ItsDangerous and other 55 | popular packages. In order to grow the community of contributors and 56 | users, and allow the maintainers to devote more time to the projects, 57 | [please donate today][]. 58 | 59 | [please donate today]: https://palletsprojects.com/donate 60 | 61 | -------------------------------------------------------------------------------- /app/server/lib/click/globals.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import typing as t 4 | from threading import local 5 | 6 | if t.TYPE_CHECKING: 7 | from .core import Context 8 | 9 | _local = local() 10 | 11 | 12 | @t.overload 13 | def get_current_context(silent: t.Literal[False] = False) -> Context: ... 14 | 15 | 16 | @t.overload 17 | def get_current_context(silent: bool = ...) -> Context | None: ... 18 | 19 | 20 | def get_current_context(silent: bool = False) -> Context | None: 21 | """Returns the current click context. This can be used as a way to 22 | access the current context object from anywhere. This is a more implicit 23 | alternative to the :func:`pass_context` decorator. This function is 24 | primarily useful for helpers such as :func:`echo` which might be 25 | interested in changing its behavior based on the current context. 26 | 27 | To push the current context, :meth:`Context.scope` can be used. 28 | 29 | .. versionadded:: 5.0 30 | 31 | :param silent: if set to `True` the return value is `None` if no context 32 | is available. The default behavior is to raise a 33 | :exc:`RuntimeError`. 34 | """ 35 | try: 36 | return t.cast("Context", _local.stack[-1]) 37 | except (AttributeError, IndexError) as e: 38 | if not silent: 39 | raise RuntimeError("There is no active click context.") from e 40 | 41 | return None 42 | 43 | 44 | def push_context(ctx: Context) -> None: 45 | """Pushes a new context to the current stack.""" 46 | _local.__dict__.setdefault("stack", []).append(ctx) 47 | 48 | 49 | def pop_context() -> None: 50 | """Removes the top level from the stack.""" 51 | _local.stack.pop() 52 | 53 | 54 | def resolve_color_default(color: bool | None = None) -> bool | None: 55 | """Internal helper to get the default value of the color flag. If a 56 | value is passed it's returned unchanged, otherwise it's looked up from 57 | the current context. 58 | """ 59 | if color is not None: 60 | return color 61 | 62 | ctx = get_current_context(silent=True) 63 | 64 | if ctx is not None: 65 | return ctx.color 66 | 67 | return None 68 | -------------------------------------------------------------------------------- /app/server/lib/colorama-0.4.6.dist-info/RECORD: -------------------------------------------------------------------------------- 1 | colorama-0.4.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 2 | colorama-0.4.6.dist-info/METADATA,sha256=e67SnrUMOym9sz_4TjF3vxvAV4T3aF7NyqRHHH3YEMw,17158 3 | colorama-0.4.6.dist-info/RECORD,, 4 | colorama-0.4.6.dist-info/WHEEL,sha256=cdcF4Fbd0FPtw2EMIOwH-3rSOTUdTCeOSXRMD1iLUb8,105 5 | colorama-0.4.6.dist-info/licenses/LICENSE.txt,sha256=ysNcAmhuXQSlpxQL-zs25zrtSWZW6JEQLkKIhteTAxg,1491 6 | colorama/__init__.py,sha256=wePQA4U20tKgYARySLEC047ucNX-g8pRLpYBuiHlLb8,266 7 | colorama/__pycache__/__init__.cpython-312.pyc,, 8 | colorama/__pycache__/ansi.cpython-312.pyc,, 9 | colorama/__pycache__/ansitowin32.cpython-312.pyc,, 10 | colorama/__pycache__/initialise.cpython-312.pyc,, 11 | colorama/__pycache__/win32.cpython-312.pyc,, 12 | colorama/__pycache__/winterm.cpython-312.pyc,, 13 | colorama/ansi.py,sha256=Top4EeEuaQdBWdteKMEcGOTeKeF19Q-Wo_6_Cj5kOzQ,2522 14 | colorama/ansitowin32.py,sha256=vPNYa3OZbxjbuFyaVo0Tmhmy1FZ1lKMWCnT7odXpItk,11128 15 | colorama/initialise.py,sha256=-hIny86ClXo39ixh5iSCfUIa2f_h_bgKRDW7gqs-KLU,3325 16 | colorama/tests/__init__.py,sha256=MkgPAEzGQd-Rq0w0PZXSX2LadRWhUECcisJY8lSrm4Q,75 17 | colorama/tests/__pycache__/__init__.cpython-312.pyc,, 18 | colorama/tests/__pycache__/ansi_test.cpython-312.pyc,, 19 | colorama/tests/__pycache__/ansitowin32_test.cpython-312.pyc,, 20 | colorama/tests/__pycache__/initialise_test.cpython-312.pyc,, 21 | colorama/tests/__pycache__/isatty_test.cpython-312.pyc,, 22 | colorama/tests/__pycache__/utils.cpython-312.pyc,, 23 | colorama/tests/__pycache__/winterm_test.cpython-312.pyc,, 24 | colorama/tests/ansi_test.py,sha256=FeViDrUINIZcr505PAxvU4AjXz1asEiALs9GXMhwRaE,2839 25 | colorama/tests/ansitowin32_test.py,sha256=RN7AIhMJ5EqDsYaCjVo-o4u8JzDD4ukJbmevWKS70rY,10678 26 | colorama/tests/initialise_test.py,sha256=BbPy-XfyHwJ6zKozuQOvNvQZzsx9vdb_0bYXn7hsBTc,6741 27 | colorama/tests/isatty_test.py,sha256=Pg26LRpv0yQDB5Ac-sxgVXG7hsA1NYvapFgApZfYzZg,1866 28 | colorama/tests/utils.py,sha256=1IIRylG39z5-dzq09R_ngufxyPZxgldNbrxKxUGwGKE,1079 29 | colorama/tests/winterm_test.py,sha256=qoWFPEjym5gm2RuMwpf3pOis3a5r_PJZFCzK254JL8A,3709 30 | colorama/win32.py,sha256=YQOKwMTwtGBbsY4dL5HYTvwTeP9wIQra5MvPNddpxZs,6181 31 | colorama/winterm.py,sha256=XCQFDHjPi6AHYNdZwy0tA02H-Jh48Jp-HvCjeLeLp3U,7134 32 | -------------------------------------------------------------------------------- /app/server/lib/mutagen/m4a.py: -------------------------------------------------------------------------------- 1 | # Copyright 2006 Joe Wreschnig 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | 8 | """ 9 | since 1.9: mutagen.m4a is deprecated; use mutagen.mp4 instead. 10 | since 1.31: mutagen.m4a will no longer work; any operation that could fail 11 | will fail now. 12 | """ 13 | 14 | import warnings 15 | 16 | from mutagen import FileType, Tags, StreamInfo 17 | from ._util import DictProxy, MutagenError, loadfile 18 | 19 | warnings.warn( 20 | "mutagen.m4a is deprecated; use mutagen.mp4 instead.", 21 | DeprecationWarning) 22 | 23 | 24 | class error(MutagenError): 25 | pass 26 | 27 | 28 | class M4AMetadataError(error): 29 | pass 30 | 31 | 32 | class M4AStreamInfoError(error): 33 | pass 34 | 35 | 36 | class M4AMetadataValueError(error): 37 | pass 38 | 39 | 40 | __all__ = ['M4A', 'Open', 'delete', 'M4ACover'] 41 | 42 | 43 | class M4ACover(bytes): 44 | 45 | FORMAT_JPEG = 0x0D 46 | FORMAT_PNG = 0x0E 47 | 48 | def __new__(cls, data, imageformat=None): 49 | self = bytes.__new__(cls, data) 50 | if imageformat is None: 51 | imageformat = M4ACover.FORMAT_JPEG 52 | self.imageformat = imageformat 53 | return self 54 | 55 | 56 | class M4ATags(DictProxy, Tags): 57 | 58 | def load(self, atoms, fileobj): 59 | raise error("deprecated") 60 | 61 | def save(self, filename): 62 | raise error("deprecated") 63 | 64 | def delete(self, filename): 65 | raise error("deprecated") 66 | 67 | def pprint(self): 68 | return u"" 69 | 70 | 71 | class M4AInfo(StreamInfo): 72 | 73 | bitrate = 0 74 | 75 | def __init__(self, atoms, fileobj): 76 | raise error("deprecated") 77 | 78 | def pprint(self): 79 | return u"" 80 | 81 | 82 | class M4A(FileType): 83 | 84 | _mimes = ["audio/mp4", "audio/x-m4a", "audio/mpeg4", "audio/aac"] 85 | 86 | @loadfile() 87 | def load(self, filething): 88 | raise error("deprecated") 89 | 90 | def add_tags(self): 91 | self.tags = M4ATags() 92 | 93 | @staticmethod 94 | def score(filename, fileobj, header): 95 | return 0 96 | 97 | 98 | Open = M4A 99 | 100 | 101 | def delete(filename): 102 | raise error("deprecated") 103 | -------------------------------------------------------------------------------- /app/server/lib/click-8.3.1.dist-info/RECORD: -------------------------------------------------------------------------------- 1 | click-8.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 2 | click-8.3.1.dist-info/METADATA,sha256=XZeBrMAE0ghTE88SjfrSDuSyNCpBPplxJR1tbwD9oZg,2621 3 | click-8.3.1.dist-info/RECORD,, 4 | click-8.3.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 5 | click-8.3.1.dist-info/licenses/LICENSE.txt,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 6 | click/__init__.py,sha256=6YyS1aeyknZ0LYweWozNZy0A9nZ_11wmYIhv3cbQrYo,4473 7 | click/__pycache__/__init__.cpython-312.pyc,, 8 | click/__pycache__/_compat.cpython-312.pyc,, 9 | click/__pycache__/_termui_impl.cpython-312.pyc,, 10 | click/__pycache__/_textwrap.cpython-312.pyc,, 11 | click/__pycache__/_utils.cpython-312.pyc,, 12 | click/__pycache__/_winconsole.cpython-312.pyc,, 13 | click/__pycache__/core.cpython-312.pyc,, 14 | click/__pycache__/decorators.cpython-312.pyc,, 15 | click/__pycache__/exceptions.cpython-312.pyc,, 16 | click/__pycache__/formatting.cpython-312.pyc,, 17 | click/__pycache__/globals.cpython-312.pyc,, 18 | click/__pycache__/parser.cpython-312.pyc,, 19 | click/__pycache__/shell_completion.cpython-312.pyc,, 20 | click/__pycache__/termui.cpython-312.pyc,, 21 | click/__pycache__/testing.cpython-312.pyc,, 22 | click/__pycache__/types.cpython-312.pyc,, 23 | click/__pycache__/utils.cpython-312.pyc,, 24 | click/_compat.py,sha256=v3xBZkFbvA1BXPRkFfBJc6-pIwPI7345m-kQEnpVAs4,18693 25 | click/_termui_impl.py,sha256=rgCb3On8X5A4200rA5L6i13u5iapmFer7sru57Jy6zA,27093 26 | click/_textwrap.py,sha256=BOae0RQ6vg3FkNgSJyOoGzG1meGMxJ_ukWVZKx_v-0o,1400 27 | click/_utils.py,sha256=kZwtTf5gMuCilJJceS2iTCvRvCY-0aN5rJq8gKw7p8g,943 28 | click/_winconsole.py,sha256=_vxUuUaxwBhoR0vUWCNuHY8VUefiMdCIyU2SXPqoF-A,8465 29 | click/core.py,sha256=U6Bfxt8GkjNDqyJ0HqXvluJHtyZ4sY5USAvM1Cdq7mQ,132105 30 | click/decorators.py,sha256=5P7abhJtAQYp_KHgjUvhMv464ERwOzrv2enNknlwHyQ,18461 31 | click/exceptions.py,sha256=8utf8w6V5hJXMnO_ic1FNrtbwuEn1NUu1aDwV8UqnG4,9954 32 | click/formatting.py,sha256=RVfwwr0rwWNpgGr8NaHodPzkIr7_tUyVh_nDdanLMNc,9730 33 | click/globals.py,sha256=gM-Nh6A4M0HB_SgkaF5M4ncGGMDHc_flHXu9_oh4GEU,1923 34 | click/parser.py,sha256=Q31pH0FlQZEq-UXE_ABRzlygEfvxPTuZbWNh4xfXmzw,19010 35 | click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 36 | click/shell_completion.py,sha256=Cc4GQUFuWpfQBa9sF5qXeeYI7n3tI_1k6ZdSn4BZbT0,20994 37 | click/termui.py,sha256=hqCEjNndU-nzW08nRAkBaVgfZp_FdCA9KxfIWlKYaMc,31037 38 | click/testing.py,sha256=EERbzcl1br0mW0qBS9EqkknfNfXB9WQEW0ELIpkvuSs,19102 39 | click/types.py,sha256=ek54BNSFwPKsqtfT7jsqcc4WHui8AIFVMKM4oVZIXhc,39927 40 | click/utils.py,sha256=gCUoewdAhA-QLBUUHxrLh4uj6m7T1WjZZMNPvR0I7YA,20257 41 | -------------------------------------------------------------------------------- /app/server/lib/flask/logging.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import logging 4 | import sys 5 | import typing as t 6 | 7 | from werkzeug.local import LocalProxy 8 | 9 | from .globals import request 10 | 11 | if t.TYPE_CHECKING: # pragma: no cover 12 | from .sansio.app import App 13 | 14 | 15 | @LocalProxy 16 | def wsgi_errors_stream() -> t.TextIO: 17 | """Find the most appropriate error stream for the application. If a request 18 | is active, log to ``wsgi.errors``, otherwise use ``sys.stderr``. 19 | 20 | If you configure your own :class:`logging.StreamHandler`, you may want to 21 | use this for the stream. If you are using file or dict configuration and 22 | can't import this directly, you can refer to it as 23 | ``ext://flask.logging.wsgi_errors_stream``. 24 | """ 25 | return request.environ["wsgi.errors"] if request else sys.stderr 26 | 27 | 28 | def has_level_handler(logger: logging.Logger) -> bool: 29 | """Check if there is a handler in the logging chain that will handle the 30 | given logger's :meth:`effective level <~logging.Logger.getEffectiveLevel>`. 31 | """ 32 | level = logger.getEffectiveLevel() 33 | current = logger 34 | 35 | while current: 36 | if any(handler.level <= level for handler in current.handlers): 37 | return True 38 | 39 | if not current.propagate: 40 | break 41 | 42 | current = current.parent # type: ignore 43 | 44 | return False 45 | 46 | 47 | #: Log messages to :func:`~flask.logging.wsgi_errors_stream` with the format 48 | #: ``[%(asctime)s] %(levelname)s in %(module)s: %(message)s``. 49 | default_handler = logging.StreamHandler(wsgi_errors_stream) # type: ignore 50 | default_handler.setFormatter( 51 | logging.Formatter("[%(asctime)s] %(levelname)s in %(module)s: %(message)s") 52 | ) 53 | 54 | 55 | def create_logger(app: App) -> logging.Logger: 56 | """Get the Flask app's logger and configure it if needed. 57 | 58 | The logger name will be the same as 59 | :attr:`app.import_name `. 60 | 61 | When :attr:`~flask.Flask.debug` is enabled, set the logger level to 62 | :data:`logging.DEBUG` if it is not set. 63 | 64 | If there is no handler for the logger's effective level, add a 65 | :class:`~logging.StreamHandler` for 66 | :func:`~flask.logging.wsgi_errors_stream` with a basic format. 67 | """ 68 | logger = logging.getLogger(app.name) 69 | 70 | if app.debug and not logger.level: 71 | logger.setLevel(logging.DEBUG) 72 | 73 | if not has_level_handler(logger): 74 | logger.addHandler(default_handler) 75 | 76 | return logger 77 | -------------------------------------------------------------------------------- /app/server/lib/requests/compat.py: -------------------------------------------------------------------------------- 1 | """ 2 | requests.compat 3 | ~~~~~~~~~~~~~~~ 4 | 5 | This module previously handled import compatibility issues 6 | between Python 2 and Python 3. It remains for backwards 7 | compatibility until the next major version. 8 | """ 9 | 10 | import importlib 11 | import sys 12 | 13 | # ------- 14 | # urllib3 15 | # ------- 16 | from urllib3 import __version__ as urllib3_version 17 | 18 | # Detect which major version of urllib3 is being used. 19 | try: 20 | is_urllib3_1 = int(urllib3_version.split(".")[0]) == 1 21 | except (TypeError, AttributeError): 22 | # If we can't discern a version, prefer old functionality. 23 | is_urllib3_1 = True 24 | 25 | # ------------------- 26 | # Character Detection 27 | # ------------------- 28 | 29 | 30 | def _resolve_char_detection(): 31 | """Find supported character detection libraries.""" 32 | chardet = None 33 | for lib in ("chardet", "charset_normalizer"): 34 | if chardet is None: 35 | try: 36 | chardet = importlib.import_module(lib) 37 | except ImportError: 38 | pass 39 | return chardet 40 | 41 | 42 | chardet = _resolve_char_detection() 43 | 44 | # ------- 45 | # Pythons 46 | # ------- 47 | 48 | # Syntax sugar. 49 | _ver = sys.version_info 50 | 51 | #: Python 2.x? 52 | is_py2 = _ver[0] == 2 53 | 54 | #: Python 3.x? 55 | is_py3 = _ver[0] == 3 56 | 57 | # json/simplejson module import resolution 58 | has_simplejson = False 59 | try: 60 | import simplejson as json 61 | 62 | has_simplejson = True 63 | except ImportError: 64 | import json 65 | 66 | if has_simplejson: 67 | from simplejson import JSONDecodeError 68 | else: 69 | from json import JSONDecodeError 70 | 71 | # Keep OrderedDict for backwards compatibility. 72 | from collections import OrderedDict 73 | from collections.abc import Callable, Mapping, MutableMapping 74 | from http import cookiejar as cookielib 75 | from http.cookies import Morsel 76 | from io import StringIO 77 | 78 | # -------------- 79 | # Legacy Imports 80 | # -------------- 81 | from urllib.parse import ( 82 | quote, 83 | quote_plus, 84 | unquote, 85 | unquote_plus, 86 | urldefrag, 87 | urlencode, 88 | urljoin, 89 | urlparse, 90 | urlsplit, 91 | urlunparse, 92 | ) 93 | from urllib.request import ( 94 | getproxies, 95 | getproxies_environment, 96 | parse_http_list, 97 | proxy_bypass, 98 | proxy_bypass_environment, 99 | ) 100 | 101 | builtin_str = str 102 | str = str 103 | bytes = bytes 104 | basestring = (str, bytes) 105 | numeric_types = (int, float) 106 | integer_types = (int,) 107 | -------------------------------------------------------------------------------- /app/server/lib/urllib3/filepost.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import binascii 4 | import codecs 5 | import os 6 | import typing 7 | from io import BytesIO 8 | 9 | from .fields import _TYPE_FIELD_VALUE_TUPLE, RequestField 10 | 11 | writer = codecs.lookup("utf-8")[3] 12 | 13 | _TYPE_FIELDS_SEQUENCE = typing.Sequence[ 14 | typing.Union[tuple[str, _TYPE_FIELD_VALUE_TUPLE], RequestField] 15 | ] 16 | _TYPE_FIELDS = typing.Union[ 17 | _TYPE_FIELDS_SEQUENCE, 18 | typing.Mapping[str, _TYPE_FIELD_VALUE_TUPLE], 19 | ] 20 | 21 | 22 | def choose_boundary() -> str: 23 | """ 24 | Our embarrassingly-simple replacement for mimetools.choose_boundary. 25 | """ 26 | return binascii.hexlify(os.urandom(16)).decode() 27 | 28 | 29 | def iter_field_objects(fields: _TYPE_FIELDS) -> typing.Iterable[RequestField]: 30 | """ 31 | Iterate over fields. 32 | 33 | Supports list of (k, v) tuples and dicts, and lists of 34 | :class:`~urllib3.fields.RequestField`. 35 | 36 | """ 37 | iterable: typing.Iterable[RequestField | tuple[str, _TYPE_FIELD_VALUE_TUPLE]] 38 | 39 | if isinstance(fields, typing.Mapping): 40 | iterable = fields.items() 41 | else: 42 | iterable = fields 43 | 44 | for field in iterable: 45 | if isinstance(field, RequestField): 46 | yield field 47 | else: 48 | yield RequestField.from_tuples(*field) 49 | 50 | 51 | def encode_multipart_formdata( 52 | fields: _TYPE_FIELDS, boundary: str | None = None 53 | ) -> tuple[bytes, str]: 54 | """ 55 | Encode a dictionary of ``fields`` using the multipart/form-data MIME format. 56 | 57 | :param fields: 58 | Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestField`). 59 | Values are processed by :func:`urllib3.fields.RequestField.from_tuples`. 60 | 61 | :param boundary: 62 | If not specified, then a random boundary will be generated using 63 | :func:`urllib3.filepost.choose_boundary`. 64 | """ 65 | body = BytesIO() 66 | if boundary is None: 67 | boundary = choose_boundary() 68 | 69 | for field in iter_field_objects(fields): 70 | body.write(f"--{boundary}\r\n".encode("latin-1")) 71 | 72 | writer(body).write(field.render_headers()) 73 | data = field.data 74 | 75 | if isinstance(data, int): 76 | data = str(data) # Backwards compatibility 77 | 78 | if isinstance(data, str): 79 | writer(body).write(data) 80 | else: 81 | body.write(data) 82 | 83 | body.write(b"\r\n") 84 | 85 | body.write(f"--{boundary}--\r\n".encode("latin-1")) 86 | 87 | content_type = f"multipart/form-data; boundary={boundary}" 88 | 89 | return body.getvalue(), content_type 90 | -------------------------------------------------------------------------------- /app/server/lib/mutagen/_tools/_util.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Christoph Reiter 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | 8 | import os 9 | import signal 10 | import contextlib 11 | import optparse 12 | 13 | from mutagen._util import iterbytes 14 | 15 | 16 | def split_escape(string, sep, maxsplit=None, escape_char="\\"): 17 | """Like unicode/str/bytes.split but allows for the separator to be escaped 18 | 19 | If passed unicode/str/bytes will only return list of unicode/str/bytes. 20 | """ 21 | 22 | assert len(sep) == 1 23 | assert len(escape_char) == 1 24 | 25 | if isinstance(string, bytes): 26 | if isinstance(escape_char, str): 27 | escape_char = escape_char.encode("ascii") 28 | iter_ = iterbytes 29 | else: 30 | iter_ = iter 31 | 32 | if maxsplit is None: 33 | maxsplit = len(string) 34 | 35 | empty = string[:0] 36 | result = [] 37 | current = empty 38 | escaped = False 39 | for char in iter_(string): 40 | if escaped: 41 | if char != escape_char and char != sep: 42 | current += escape_char 43 | current += char 44 | escaped = False 45 | else: 46 | if char == escape_char: 47 | escaped = True 48 | elif char == sep and len(result) < maxsplit: 49 | result.append(current) 50 | current = empty 51 | else: 52 | current += char 53 | result.append(current) 54 | return result 55 | 56 | 57 | class SignalHandler(object): 58 | 59 | def __init__(self): 60 | self._interrupted = False 61 | self._nosig = False 62 | self._init = False 63 | 64 | def init(self): 65 | signal.signal(signal.SIGINT, self._handler) 66 | signal.signal(signal.SIGTERM, self._handler) 67 | if os.name != "nt": 68 | signal.signal(signal.SIGHUP, self._handler) 69 | 70 | def _handler(self, signum, frame): 71 | self._interrupted = True 72 | if not self._nosig: 73 | raise SystemExit("Aborted...") 74 | 75 | @contextlib.contextmanager 76 | def block(self): 77 | """While this context manager is active any signals for aborting 78 | the process will be queued and exit the program once the context 79 | is left. 80 | """ 81 | 82 | self._nosig = True 83 | yield 84 | self._nosig = False 85 | if self._interrupted: 86 | raise SystemExit("Aborted...") 87 | 88 | 89 | OptionParser = optparse.OptionParser 90 | -------------------------------------------------------------------------------- /app/server/lib/certifi-2025.11.12.dist-info/METADATA: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.4 2 | Name: certifi 3 | Version: 2025.11.12 4 | Summary: Python package for providing Mozilla's CA Bundle. 5 | Home-page: https://github.com/certifi/python-certifi 6 | Author: Kenneth Reitz 7 | Author-email: me@kennethreitz.com 8 | License: MPL-2.0 9 | Project-URL: Source, https://github.com/certifi/python-certifi 10 | Classifier: Development Status :: 5 - Production/Stable 11 | Classifier: Intended Audience :: Developers 12 | Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) 13 | Classifier: Natural Language :: English 14 | Classifier: Programming Language :: Python 15 | Classifier: Programming Language :: Python :: 3 16 | Classifier: Programming Language :: Python :: 3 :: Only 17 | Classifier: Programming Language :: Python :: 3.7 18 | Classifier: Programming Language :: Python :: 3.8 19 | Classifier: Programming Language :: Python :: 3.9 20 | Classifier: Programming Language :: Python :: 3.10 21 | Classifier: Programming Language :: Python :: 3.11 22 | Classifier: Programming Language :: Python :: 3.12 23 | Classifier: Programming Language :: Python :: 3.13 24 | Classifier: Programming Language :: Python :: 3.14 25 | Requires-Python: >=3.7 26 | License-File: LICENSE 27 | Dynamic: author 28 | Dynamic: author-email 29 | Dynamic: classifier 30 | Dynamic: description 31 | Dynamic: home-page 32 | Dynamic: license 33 | Dynamic: license-file 34 | Dynamic: project-url 35 | Dynamic: requires-python 36 | Dynamic: summary 37 | 38 | Certifi: Python SSL Certificates 39 | ================================ 40 | 41 | Certifi provides Mozilla's carefully curated collection of Root Certificates for 42 | validating the trustworthiness of SSL certificates while verifying the identity 43 | of TLS hosts. It has been extracted from the `Requests`_ project. 44 | 45 | Installation 46 | ------------ 47 | 48 | ``certifi`` is available on PyPI. Simply install it with ``pip``:: 49 | 50 | $ pip install certifi 51 | 52 | Usage 53 | ----- 54 | 55 | To reference the installed certificate authority (CA) bundle, you can use the 56 | built-in function:: 57 | 58 | >>> import certifi 59 | 60 | >>> certifi.where() 61 | '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem' 62 | 63 | Or from the command line:: 64 | 65 | $ python -m certifi 66 | /usr/local/lib/python3.7/site-packages/certifi/cacert.pem 67 | 68 | Enjoy! 69 | 70 | .. _`Requests`: https://requests.readthedocs.io/en/master/ 71 | 72 | Addition/Removal of Certificates 73 | -------------------------------- 74 | 75 | Certifi does not support any addition/removal or other modification of the 76 | CA trust store content. This project is intended to provide a reliable and 77 | highly portable root of trust to python deployments. Look to upstream projects 78 | for methods to use alternate trust. 79 | -------------------------------------------------------------------------------- /app/server/lib/mutagen/_tools/moggsplit.py: -------------------------------------------------------------------------------- 1 | # Copyright 2006 Joe Wreschnig 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | 8 | """Split a multiplex/chained Ogg file into its component parts.""" 9 | 10 | import os 11 | import sys 12 | 13 | import mutagen.ogg 14 | 15 | from ._util import SignalHandler, OptionParser 16 | 17 | 18 | _sig = SignalHandler() 19 | 20 | 21 | def main(argv): 22 | from mutagen.ogg import OggPage 23 | parser = OptionParser( 24 | usage="%prog [options] filename.ogg ...", 25 | description="Split Ogg logical streams using Mutagen.", 26 | version="Mutagen %s" % ".".join(map(str, mutagen.version)) 27 | ) 28 | 29 | parser.add_option( 30 | "--extension", dest="extension", default="ogg", metavar='ext', 31 | help="use this extension (default 'ogg')") 32 | parser.add_option( 33 | "--pattern", dest="pattern", default="%(base)s-%(stream)d.%(ext)s", 34 | metavar='pattern', help="name files using this pattern") 35 | parser.add_option( 36 | "--m3u", dest="m3u", action="store_true", default=False, 37 | help="generate an m3u (playlist) file") 38 | 39 | (options, args) = parser.parse_args(argv[1:]) 40 | if not args: 41 | raise SystemExit(parser.print_help() or 1) 42 | 43 | format = {'ext': options.extension} 44 | for filename in args: 45 | with _sig.block(): 46 | fileobjs = {} 47 | format["base"] = os.path.splitext(os.path.basename(filename))[0] 48 | with open(filename, "rb") as fileobj: 49 | if options.m3u: 50 | m3u = open(format["base"] + ".m3u", "w") 51 | fileobjs["m3u"] = m3u 52 | else: 53 | m3u = None 54 | while True: 55 | try: 56 | page = OggPage(fileobj) 57 | except EOFError: 58 | break 59 | else: 60 | format["stream"] = page.serial 61 | if page.serial not in fileobjs: 62 | new_filename = options.pattern % format 63 | new_fileobj = open(new_filename, "wb") 64 | fileobjs[page.serial] = new_fileobj 65 | if m3u: 66 | m3u.write(new_filename + "\r\n") 67 | fileobjs[page.serial].write(page.write()) 68 | for f in fileobjs.values(): 69 | f.close() 70 | 71 | 72 | def entry_point(): 73 | _sig.init() 74 | return main(sys.argv) 75 | -------------------------------------------------------------------------------- /app/server/lib/flask/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import typing as t 4 | 5 | from . import json as json 6 | from .app import Flask as Flask 7 | from .blueprints import Blueprint as Blueprint 8 | from .config import Config as Config 9 | from .ctx import after_this_request as after_this_request 10 | from .ctx import copy_current_request_context as copy_current_request_context 11 | from .ctx import has_app_context as has_app_context 12 | from .ctx import has_request_context as has_request_context 13 | from .globals import current_app as current_app 14 | from .globals import g as g 15 | from .globals import request as request 16 | from .globals import session as session 17 | from .helpers import abort as abort 18 | from .helpers import flash as flash 19 | from .helpers import get_flashed_messages as get_flashed_messages 20 | from .helpers import get_template_attribute as get_template_attribute 21 | from .helpers import make_response as make_response 22 | from .helpers import redirect as redirect 23 | from .helpers import send_file as send_file 24 | from .helpers import send_from_directory as send_from_directory 25 | from .helpers import stream_with_context as stream_with_context 26 | from .helpers import url_for as url_for 27 | from .json import jsonify as jsonify 28 | from .signals import appcontext_popped as appcontext_popped 29 | from .signals import appcontext_pushed as appcontext_pushed 30 | from .signals import appcontext_tearing_down as appcontext_tearing_down 31 | from .signals import before_render_template as before_render_template 32 | from .signals import got_request_exception as got_request_exception 33 | from .signals import message_flashed as message_flashed 34 | from .signals import request_finished as request_finished 35 | from .signals import request_started as request_started 36 | from .signals import request_tearing_down as request_tearing_down 37 | from .signals import template_rendered as template_rendered 38 | from .templating import render_template as render_template 39 | from .templating import render_template_string as render_template_string 40 | from .templating import stream_template as stream_template 41 | from .templating import stream_template_string as stream_template_string 42 | from .wrappers import Request as Request 43 | from .wrappers import Response as Response 44 | 45 | 46 | def __getattr__(name: str) -> t.Any: 47 | if name == "__version__": 48 | import importlib.metadata 49 | import warnings 50 | 51 | warnings.warn( 52 | "The '__version__' attribute is deprecated and will be removed in" 53 | " Flask 3.1. Use feature detection or" 54 | " 'importlib.metadata.version(\"flask\")' instead.", 55 | DeprecationWarning, 56 | stacklevel=2, 57 | ) 58 | return importlib.metadata.version("flask") 59 | 60 | raise AttributeError(name) 61 | -------------------------------------------------------------------------------- /app/server/lib/itsdangerous/url_safe.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import typing as t 4 | import zlib 5 | 6 | from ._json import _CompactJSON 7 | from .encoding import base64_decode 8 | from .encoding import base64_encode 9 | from .exc import BadPayload 10 | from .serializer import _PDataSerializer 11 | from .serializer import Serializer 12 | from .timed import TimedSerializer 13 | 14 | 15 | class URLSafeSerializerMixin(Serializer[str]): 16 | """Mixed in with a regular serializer it will attempt to zlib 17 | compress the string to make it shorter if necessary. It will also 18 | base64 encode the string so that it can safely be placed in a URL. 19 | """ 20 | 21 | default_serializer: _PDataSerializer[str] = _CompactJSON 22 | 23 | def load_payload( 24 | self, 25 | payload: bytes, 26 | *args: t.Any, 27 | serializer: t.Any | None = None, 28 | **kwargs: t.Any, 29 | ) -> t.Any: 30 | decompress = False 31 | 32 | if payload.startswith(b"."): 33 | payload = payload[1:] 34 | decompress = True 35 | 36 | try: 37 | json = base64_decode(payload) 38 | except Exception as e: 39 | raise BadPayload( 40 | "Could not base64 decode the payload because of an exception", 41 | original_error=e, 42 | ) from e 43 | 44 | if decompress: 45 | try: 46 | json = zlib.decompress(json) 47 | except Exception as e: 48 | raise BadPayload( 49 | "Could not zlib decompress the payload before decoding the payload", 50 | original_error=e, 51 | ) from e 52 | 53 | return super().load_payload(json, *args, **kwargs) 54 | 55 | def dump_payload(self, obj: t.Any) -> bytes: 56 | json = super().dump_payload(obj) 57 | is_compressed = False 58 | compressed = zlib.compress(json) 59 | 60 | if len(compressed) < (len(json) - 1): 61 | json = compressed 62 | is_compressed = True 63 | 64 | base64d = base64_encode(json) 65 | 66 | if is_compressed: 67 | base64d = b"." + base64d 68 | 69 | return base64d 70 | 71 | 72 | class URLSafeSerializer(URLSafeSerializerMixin, Serializer[str]): 73 | """Works like :class:`.Serializer` but dumps and loads into a URL 74 | safe string consisting of the upper and lowercase character of the 75 | alphabet as well as ``'_'``, ``'-'`` and ``'.'``. 76 | """ 77 | 78 | 79 | class URLSafeTimedSerializer(URLSafeSerializerMixin, TimedSerializer[str]): 80 | """Works like :class:`.TimedSerializer` but dumps and loads into a 81 | URL safe string consisting of the upper and lowercase character of 82 | the alphabet as well as ``'_'``, ``'-'`` and ``'.'``. 83 | """ 84 | -------------------------------------------------------------------------------- /app/server/lib/charset_normalizer-3.4.4.dist-info/RECORD: -------------------------------------------------------------------------------- 1 | ../../bin/normalizer.exe,sha256=ls7LMvqydDzGExsykryyKRqliUy8Jt6kL54L8nKtPEg,108407 2 | charset_normalizer-3.4.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 3 | charset_normalizer-3.4.4.dist-info/METADATA,sha256=Mg5oc0yfpVMtDcprHt_pPbbV0qUSHEeaEz4NG53pmyY,38067 4 | charset_normalizer-3.4.4.dist-info/RECORD,, 5 | charset_normalizer-3.4.4.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101 6 | charset_normalizer-3.4.4.dist-info/entry_points.txt,sha256=ADSTKrkXZ3hhdOVFi6DcUEHQRS0xfxDIE_pEz4wLIXA,65 7 | charset_normalizer-3.4.4.dist-info/licenses/LICENSE,sha256=GFd0hdNwTxpHne2OVzwJds_tMV_S_ReYP6mI2kwvcNE,1092 8 | charset_normalizer-3.4.4.dist-info/top_level.txt,sha256=7ASyzePr8_xuZWJsnqJjIBtyV8vhEo0wBCv1MPRRi3Q,19 9 | charset_normalizer/__init__.py,sha256=0NT8MHi7SKq3juMqYfOdrkzjisK0L73lneNHH4qaUAs,1638 10 | charset_normalizer/__main__.py,sha256=2sj_BS6H0sU25C1bMqz9DVwa6kOK9lchSEbSU-_iu7M,115 11 | charset_normalizer/__pycache__/__init__.cpython-312.pyc,, 12 | charset_normalizer/__pycache__/__main__.cpython-312.pyc,, 13 | charset_normalizer/__pycache__/api.cpython-312.pyc,, 14 | charset_normalizer/__pycache__/cd.cpython-312.pyc,, 15 | charset_normalizer/__pycache__/constant.cpython-312.pyc,, 16 | charset_normalizer/__pycache__/legacy.cpython-312.pyc,, 17 | charset_normalizer/__pycache__/md.cpython-312.pyc,, 18 | charset_normalizer/__pycache__/models.cpython-312.pyc,, 19 | charset_normalizer/__pycache__/utils.cpython-312.pyc,, 20 | charset_normalizer/__pycache__/version.cpython-312.pyc,, 21 | charset_normalizer/api.py,sha256=ODy4hX78b3ldTl5sViYPU1yzQ5qkclfgSIFE8BtNrTI,23337 22 | charset_normalizer/cd.py,sha256=uq8nVxRpR6Guc16ACvOWtL8KO3w7vYaCh8hHisuOyTg,12917 23 | charset_normalizer/cli/__init__.py,sha256=d9MUx-1V_qD3x9igIy4JT4oC5CU0yjulk7QyZWeRFhg,144 24 | charset_normalizer/cli/__main__.py,sha256=-pdJCyPywouPyFsC8_eTSgTmvh1YEvgjsvy1WZ0XjaA,13027 25 | charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc,, 26 | charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc,, 27 | charset_normalizer/constant.py,sha256=mCJmYzpBU27Ut9kiNWWoBbhhxQ-aRVw3K7LSwoFwBGI,44728 28 | charset_normalizer/legacy.py,sha256=ui08NlKqAXU3Y7smK-NFJjEgRRQz9ruM7aNCbT0OOrE,2811 29 | charset_normalizer/md.cp312-win_amd64.pyd,sha256=dqU14JU7SKI0i4dyNqV5nPHQHLIUIsfxeULzU2fLXI8,10752 30 | charset_normalizer/md.py,sha256=LSuW2hNgXSgF7JGdRapLAHLuj6pABHiP85LTNAYmu7c,20780 31 | charset_normalizer/md__mypyc.cp312-win_amd64.pyd,sha256=CDDD_25vg5Sn3xcPlfwQ3mWrnyKzD50jg_DMKZuN8QE,126976 32 | charset_normalizer/models.py,sha256=ZR2PE-fqf6dASZfqdE5Uhkmr0o1MciSdXOjuNqwkmvg,12754 33 | charset_normalizer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 34 | charset_normalizer/utils.py,sha256=XtWIQeOuz7cnGebMzyi4Vvi1JtA84QBSIeR9PDzF7pw,12584 35 | charset_normalizer/version.py,sha256=MhW8dOLls4GbbxBUqeS1huc7Rth1ArKi4nS90qTFwz8,123 36 | -------------------------------------------------------------------------------- /app/server/lib/werkzeug/datastructures/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import typing as t 4 | 5 | from .accept import Accept as Accept 6 | from .accept import CharsetAccept as CharsetAccept 7 | from .accept import LanguageAccept as LanguageAccept 8 | from .accept import MIMEAccept as MIMEAccept 9 | from .auth import Authorization as Authorization 10 | from .auth import WWWAuthenticate as WWWAuthenticate 11 | from .cache_control import RequestCacheControl as RequestCacheControl 12 | from .cache_control import ResponseCacheControl as ResponseCacheControl 13 | from .csp import ContentSecurityPolicy as ContentSecurityPolicy 14 | from .etag import ETags as ETags 15 | from .file_storage import FileMultiDict as FileMultiDict 16 | from .file_storage import FileStorage as FileStorage 17 | from .headers import EnvironHeaders as EnvironHeaders 18 | from .headers import Headers as Headers 19 | from .mixins import ImmutableDictMixin as ImmutableDictMixin 20 | from .mixins import ImmutableHeadersMixin as ImmutableHeadersMixin 21 | from .mixins import ImmutableListMixin as ImmutableListMixin 22 | from .mixins import ImmutableMultiDictMixin as ImmutableMultiDictMixin 23 | from .mixins import UpdateDictMixin as UpdateDictMixin 24 | from .range import ContentRange as ContentRange 25 | from .range import IfRange as IfRange 26 | from .range import Range as Range 27 | from .structures import CallbackDict as CallbackDict 28 | from .structures import CombinedMultiDict as CombinedMultiDict 29 | from .structures import HeaderSet as HeaderSet 30 | from .structures import ImmutableDict as ImmutableDict 31 | from .structures import ImmutableList as ImmutableList 32 | from .structures import ImmutableMultiDict as ImmutableMultiDict 33 | from .structures import ImmutableTypeConversionDict as ImmutableTypeConversionDict 34 | from .structures import iter_multi_items as iter_multi_items 35 | from .structures import MultiDict as MultiDict 36 | from .structures import TypeConversionDict as TypeConversionDict 37 | 38 | 39 | def __getattr__(name: str) -> t.Any: 40 | import warnings 41 | 42 | if name == "OrderedMultiDict": 43 | from .structures import _OrderedMultiDict 44 | 45 | warnings.warn( 46 | "'OrderedMultiDict' is deprecated and will be removed in Werkzeug" 47 | " 3.2. Use 'MultiDict' instead.", 48 | DeprecationWarning, 49 | stacklevel=2, 50 | ) 51 | return _OrderedMultiDict 52 | 53 | if name == "ImmutableOrderedMultiDict": 54 | from .structures import _ImmutableOrderedMultiDict 55 | 56 | warnings.warn( 57 | "'OrderedMultiDict' is deprecated and will be removed in Werkzeug" 58 | " 3.2. Use 'ImmutableMultiDict' instead.", 59 | DeprecationWarning, 60 | stacklevel=2, 61 | ) 62 | return _ImmutableOrderedMultiDict 63 | 64 | raise AttributeError(name) 65 | -------------------------------------------------------------------------------- /app/server/lib/werkzeug/middleware/dispatcher.py: -------------------------------------------------------------------------------- 1 | """ 2 | Application Dispatcher 3 | ====================== 4 | 5 | This middleware creates a single WSGI application that dispatches to 6 | multiple other WSGI applications mounted at different URL paths. 7 | 8 | A common example is writing a Single Page Application, where you have a 9 | backend API and a frontend written in JavaScript that does the routing 10 | in the browser rather than requesting different pages from the server. 11 | The frontend is a single HTML and JS file that should be served for any 12 | path besides "/api". 13 | 14 | This example dispatches to an API app under "/api", an admin app 15 | under "/admin", and an app that serves frontend files for all other 16 | requests:: 17 | 18 | app = DispatcherMiddleware(serve_frontend, { 19 | '/api': api_app, 20 | '/admin': admin_app, 21 | }) 22 | 23 | In production, you might instead handle this at the HTTP server level, 24 | serving files or proxying to application servers based on location. The 25 | API and admin apps would each be deployed with a separate WSGI server, 26 | and the static files would be served directly by the HTTP server. 27 | 28 | .. autoclass:: DispatcherMiddleware 29 | 30 | :copyright: 2007 Pallets 31 | :license: BSD-3-Clause 32 | """ 33 | 34 | from __future__ import annotations 35 | 36 | import typing as t 37 | 38 | if t.TYPE_CHECKING: 39 | from _typeshed.wsgi import StartResponse 40 | from _typeshed.wsgi import WSGIApplication 41 | from _typeshed.wsgi import WSGIEnvironment 42 | 43 | 44 | class DispatcherMiddleware: 45 | """Combine multiple applications as a single WSGI application. 46 | Requests are dispatched to an application based on the path it is 47 | mounted under. 48 | 49 | :param app: The WSGI application to dispatch to if the request 50 | doesn't match a mounted path. 51 | :param mounts: Maps path prefixes to applications for dispatching. 52 | """ 53 | 54 | def __init__( 55 | self, 56 | app: WSGIApplication, 57 | mounts: dict[str, WSGIApplication] | None = None, 58 | ) -> None: 59 | self.app = app 60 | self.mounts = mounts or {} 61 | 62 | def __call__( 63 | self, environ: WSGIEnvironment, start_response: StartResponse 64 | ) -> t.Iterable[bytes]: 65 | script = environ.get("PATH_INFO", "") 66 | path_info = "" 67 | 68 | while "/" in script: 69 | if script in self.mounts: 70 | app = self.mounts[script] 71 | break 72 | 73 | script, last_item = script.rsplit("/", 1) 74 | path_info = f"/{last_item}{path_info}" 75 | else: 76 | app = self.mounts.get(script, self.app) 77 | 78 | original_script_name = environ.get("SCRIPT_NAME", "") 79 | environ["SCRIPT_NAME"] = original_script_name + script 80 | environ["PATH_INFO"] = path_info 81 | return app(environ, start_response) 82 | -------------------------------------------------------------------------------- /app/server/lib/requests-2.32.5.dist-info/RECORD: -------------------------------------------------------------------------------- 1 | requests-2.32.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 2 | requests-2.32.5.dist-info/METADATA,sha256=ZbWgjagfSRVRPnYJZf8Ut1GPZbe7Pv4NqzZLvMTUDLA,4945 3 | requests-2.32.5.dist-info/RECORD,, 4 | requests-2.32.5.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 5 | requests-2.32.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 6 | requests-2.32.5.dist-info/licenses/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142 7 | requests-2.32.5.dist-info/top_level.txt,sha256=fMSVmHfb5rbGOo6xv-O_tUX6j-WyixssE-SnwcDRxNQ,9 8 | requests/__init__.py,sha256=4xaAERmPDIBPsa2PsjpU9r06yooK-2mZKHTZAhWRWts,5072 9 | requests/__pycache__/__init__.cpython-312.pyc,, 10 | requests/__pycache__/__version__.cpython-312.pyc,, 11 | requests/__pycache__/_internal_utils.cpython-312.pyc,, 12 | requests/__pycache__/adapters.cpython-312.pyc,, 13 | requests/__pycache__/api.cpython-312.pyc,, 14 | requests/__pycache__/auth.cpython-312.pyc,, 15 | requests/__pycache__/certs.cpython-312.pyc,, 16 | requests/__pycache__/compat.cpython-312.pyc,, 17 | requests/__pycache__/cookies.cpython-312.pyc,, 18 | requests/__pycache__/exceptions.cpython-312.pyc,, 19 | requests/__pycache__/help.cpython-312.pyc,, 20 | requests/__pycache__/hooks.cpython-312.pyc,, 21 | requests/__pycache__/models.cpython-312.pyc,, 22 | requests/__pycache__/packages.cpython-312.pyc,, 23 | requests/__pycache__/sessions.cpython-312.pyc,, 24 | requests/__pycache__/status_codes.cpython-312.pyc,, 25 | requests/__pycache__/structures.cpython-312.pyc,, 26 | requests/__pycache__/utils.cpython-312.pyc,, 27 | requests/__version__.py,sha256=QKDceK8K_ujqwDDc3oYrR0odOBYgKVOQQ5vFap_G_cg,435 28 | requests/_internal_utils.py,sha256=nMQymr4hs32TqVo5AbCrmcJEhvPUh7xXlluyqwslLiQ,1495 29 | requests/adapters.py,sha256=8nX113gbb123aUtx2ETkAN_6IsYX-M2fRoLGluTEcRk,26285 30 | requests/api.py,sha256=_Zb9Oa7tzVIizTKwFrPjDEY9ejtm_OnSRERnADxGsQs,6449 31 | requests/auth.py,sha256=kF75tqnLctZ9Mf_hm9TZIj4cQWnN5uxRz8oWsx5wmR0,10186 32 | requests/certs.py,sha256=Z9Sb410Anv6jUFTyss0jFFhU6xst8ctELqfy8Ev23gw,429 33 | requests/compat.py,sha256=J7sIjR6XoDGp5JTVzOxkK5fSoUVUa_Pjc7iRZhAWGmI,2142 34 | requests/cookies.py,sha256=bNi-iqEj4NPZ00-ob-rHvzkvObzN3lEpgw3g6paS3Xw,18590 35 | requests/exceptions.py,sha256=jJPS1UWATs86ShVUaLorTiJb1SaGuoNEWgICJep-VkY,4260 36 | requests/help.py,sha256=gPX5d_H7Xd88aDABejhqGgl9B1VFRTt5BmiYvL3PzIQ,3875 37 | requests/hooks.py,sha256=CiuysiHA39V5UfcCBXFIx83IrDpuwfN9RcTUgv28ftQ,733 38 | requests/models.py,sha256=MjZdZ4k7tnw-1nz5PKShjmPmqyk0L6DciwnFngb_Vk4,35510 39 | requests/packages.py,sha256=_g0gZ681UyAlKHRjH6kanbaoxx2eAb6qzcXiODyTIoc,904 40 | requests/sessions.py,sha256=Cl1dpEnOfwrzzPbku-emepNeN4Rt_0_58Iy2x-JGTm8,30503 41 | requests/status_codes.py,sha256=iJUAeA25baTdw-6PfD0eF4qhpINDJRJI-yaMqxs4LEI,4322 42 | requests/structures.py,sha256=-IbmhVz06S-5aPSZuUthZ6-6D9XOjRuTXHOabY041XM,2912 43 | requests/utils.py,sha256=WqU86rZ3wvhC-tQjWcjtH_HEKZwWB3iWCZV6SW5DEdQ,33213 44 | -------------------------------------------------------------------------------- /app/server/lib/click-8.3.1.dist-info/METADATA: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.4 2 | Name: click 3 | Version: 8.3.1 4 | Summary: Composable command line interface toolkit 5 | Maintainer-email: Pallets 6 | Requires-Python: >=3.10 7 | Description-Content-Type: text/markdown 8 | License-Expression: BSD-3-Clause 9 | Classifier: Development Status :: 5 - Production/Stable 10 | Classifier: Intended Audience :: Developers 11 | Classifier: Operating System :: OS Independent 12 | Classifier: Programming Language :: Python 13 | Classifier: Typing :: Typed 14 | License-File: LICENSE.txt 15 | Requires-Dist: colorama; platform_system == 'Windows' 16 | Project-URL: Changes, https://click.palletsprojects.com/page/changes/ 17 | Project-URL: Chat, https://discord.gg/pallets 18 | Project-URL: Documentation, https://click.palletsprojects.com/ 19 | Project-URL: Donate, https://palletsprojects.com/donate 20 | Project-URL: Source, https://github.com/pallets/click/ 21 | 22 |
    23 | 24 | # Click 25 | 26 | Click is a Python package for creating beautiful command line interfaces 27 | in a composable way with as little code as necessary. It's the "Command 28 | Line Interface Creation Kit". It's highly configurable but comes with 29 | sensible defaults out of the box. 30 | 31 | It aims to make the process of writing command line tools quick and fun 32 | while also preventing any frustration caused by the inability to 33 | implement an intended CLI API. 34 | 35 | Click in three points: 36 | 37 | - Arbitrary nesting of commands 38 | - Automatic help page generation 39 | - Supports lazy loading of subcommands at runtime 40 | 41 | 42 | ## A Simple Example 43 | 44 | ```python 45 | import click 46 | 47 | @click.command() 48 | @click.option("--count", default=1, help="Number of greetings.") 49 | @click.option("--name", prompt="Your name", help="The person to greet.") 50 | def hello(count, name): 51 | """Simple program that greets NAME for a total of COUNT times.""" 52 | for _ in range(count): 53 | click.echo(f"Hello, {name}!") 54 | 55 | if __name__ == '__main__': 56 | hello() 57 | ``` 58 | 59 | ``` 60 | $ python hello.py --count=3 61 | Your name: Click 62 | Hello, Click! 63 | Hello, Click! 64 | Hello, Click! 65 | ``` 66 | 67 | 68 | ## Donate 69 | 70 | The Pallets organization develops and supports Click and other popular 71 | packages. In order to grow the community of contributors and users, and 72 | allow the maintainers to devote more time to the projects, [please 73 | donate today][]. 74 | 75 | [please donate today]: https://palletsprojects.com/donate 76 | 77 | ## Contributing 78 | 79 | See our [detailed contributing documentation][contrib] for many ways to 80 | contribute, including reporting issues, requesting features, asking or answering 81 | questions, and making PRs. 82 | 83 | [contrib]: https://palletsprojects.com/contributing/ 84 | 85 | -------------------------------------------------------------------------------- /app/server/lib/markupsafe-3.0.3.dist-info/METADATA: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.4 2 | Name: MarkupSafe 3 | Version: 3.0.3 4 | Summary: Safely add untrusted strings to HTML/XML markup. 5 | Maintainer-email: Pallets 6 | License-Expression: BSD-3-Clause 7 | Project-URL: Donate, https://palletsprojects.com/donate 8 | Project-URL: Documentation, https://markupsafe.palletsprojects.com/ 9 | Project-URL: Changes, https://markupsafe.palletsprojects.com/page/changes/ 10 | Project-URL: Source, https://github.com/pallets/markupsafe/ 11 | Project-URL: Chat, https://discord.gg/pallets 12 | Classifier: Development Status :: 5 - Production/Stable 13 | Classifier: Environment :: Web Environment 14 | Classifier: Intended Audience :: Developers 15 | Classifier: Operating System :: OS Independent 16 | Classifier: Programming Language :: Python 17 | Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content 18 | Classifier: Topic :: Text Processing :: Markup :: HTML 19 | Classifier: Typing :: Typed 20 | Requires-Python: >=3.9 21 | Description-Content-Type: text/markdown 22 | License-File: LICENSE.txt 23 | Dynamic: license-file 24 | 25 |
    26 | 27 | # MarkupSafe 28 | 29 | MarkupSafe implements a text object that escapes characters so it is 30 | safe to use in HTML and XML. Characters that have special meanings are 31 | replaced so that they display as the actual characters. This mitigates 32 | injection attacks, meaning untrusted user input can safely be displayed 33 | on a page. 34 | 35 | 36 | ## Examples 37 | 38 | ```pycon 39 | >>> from markupsafe import Markup, escape 40 | 41 | >>> # escape replaces special characters and wraps in Markup 42 | >>> escape("") 43 | Markup('<script>alert(document.cookie);</script>') 44 | 45 | >>> # wrap in Markup to mark text "safe" and prevent escaping 46 | >>> Markup("Hello") 47 | Markup('hello') 48 | 49 | >>> escape(Markup("Hello")) 50 | Markup('hello') 51 | 52 | >>> # Markup is a str subclass 53 | >>> # methods and operators escape their arguments 54 | >>> template = Markup("Hello {name}") 55 | >>> template.format(name='"World"') 56 | Markup('Hello "World"') 57 | ``` 58 | 59 | ## Donate 60 | 61 | The Pallets organization develops and supports MarkupSafe and other 62 | popular packages. In order to grow the community of contributors and 63 | users, and allow the maintainers to devote more time to the projects, 64 | [please donate today][]. 65 | 66 | [please donate today]: https://palletsprojects.com/donate 67 | 68 | ## Contributing 69 | 70 | See our [detailed contributing documentation][contrib] for many ways to 71 | contribute, including reporting issues, requesting features, asking or answering 72 | questions, and making PRs. 73 | 74 | [contrib]: https://palletsprojects.com/contributing/ 75 | -------------------------------------------------------------------------------- /app/server/lib/colorama/ansi.py: -------------------------------------------------------------------------------- 1 | # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. 2 | ''' 3 | This module generates ANSI character codes to printing colors to terminals. 4 | See: http://en.wikipedia.org/wiki/ANSI_escape_code 5 | ''' 6 | 7 | CSI = '\033[' 8 | OSC = '\033]' 9 | BEL = '\a' 10 | 11 | 12 | def code_to_chars(code): 13 | return CSI + str(code) + 'm' 14 | 15 | def set_title(title): 16 | return OSC + '2;' + title + BEL 17 | 18 | def clear_screen(mode=2): 19 | return CSI + str(mode) + 'J' 20 | 21 | def clear_line(mode=2): 22 | return CSI + str(mode) + 'K' 23 | 24 | 25 | class AnsiCodes(object): 26 | def __init__(self): 27 | # the subclasses declare class attributes which are numbers. 28 | # Upon instantiation we define instance attributes, which are the same 29 | # as the class attributes but wrapped with the ANSI escape sequence 30 | for name in dir(self): 31 | if not name.startswith('_'): 32 | value = getattr(self, name) 33 | setattr(self, name, code_to_chars(value)) 34 | 35 | 36 | class AnsiCursor(object): 37 | def UP(self, n=1): 38 | return CSI + str(n) + 'A' 39 | def DOWN(self, n=1): 40 | return CSI + str(n) + 'B' 41 | def FORWARD(self, n=1): 42 | return CSI + str(n) + 'C' 43 | def BACK(self, n=1): 44 | return CSI + str(n) + 'D' 45 | def POS(self, x=1, y=1): 46 | return CSI + str(y) + ';' + str(x) + 'H' 47 | 48 | 49 | class AnsiFore(AnsiCodes): 50 | BLACK = 30 51 | RED = 31 52 | GREEN = 32 53 | YELLOW = 33 54 | BLUE = 34 55 | MAGENTA = 35 56 | CYAN = 36 57 | WHITE = 37 58 | RESET = 39 59 | 60 | # These are fairly well supported, but not part of the standard. 61 | LIGHTBLACK_EX = 90 62 | LIGHTRED_EX = 91 63 | LIGHTGREEN_EX = 92 64 | LIGHTYELLOW_EX = 93 65 | LIGHTBLUE_EX = 94 66 | LIGHTMAGENTA_EX = 95 67 | LIGHTCYAN_EX = 96 68 | LIGHTWHITE_EX = 97 69 | 70 | 71 | class AnsiBack(AnsiCodes): 72 | BLACK = 40 73 | RED = 41 74 | GREEN = 42 75 | YELLOW = 43 76 | BLUE = 44 77 | MAGENTA = 45 78 | CYAN = 46 79 | WHITE = 47 80 | RESET = 49 81 | 82 | # These are fairly well supported, but not part of the standard. 83 | LIGHTBLACK_EX = 100 84 | LIGHTRED_EX = 101 85 | LIGHTGREEN_EX = 102 86 | LIGHTYELLOW_EX = 103 87 | LIGHTBLUE_EX = 104 88 | LIGHTMAGENTA_EX = 105 89 | LIGHTCYAN_EX = 106 90 | LIGHTWHITE_EX = 107 91 | 92 | 93 | class AnsiStyle(AnsiCodes): 94 | BRIGHT = 1 95 | DIM = 2 96 | NORMAL = 22 97 | RESET_ALL = 0 98 | 99 | Fore = AnsiFore() 100 | Back = AnsiBack() 101 | Style = AnsiStyle() 102 | Cursor = AnsiCursor() 103 | -------------------------------------------------------------------------------- /app/server/lib/charset_normalizer/legacy.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING, Any 4 | from warnings import warn 5 | 6 | from .api import from_bytes 7 | from .constant import CHARDET_CORRESPONDENCE, TOO_SMALL_SEQUENCE 8 | 9 | # TODO: remove this check when dropping Python 3.7 support 10 | if TYPE_CHECKING: 11 | from typing_extensions import TypedDict 12 | 13 | class ResultDict(TypedDict): 14 | encoding: str | None 15 | language: str 16 | confidence: float | None 17 | 18 | 19 | def detect( 20 | byte_str: bytes, should_rename_legacy: bool = False, **kwargs: Any 21 | ) -> ResultDict: 22 | """ 23 | chardet legacy method 24 | Detect the encoding of the given byte string. It should be mostly backward-compatible. 25 | Encoding name will match Chardet own writing whenever possible. (Not on encoding name unsupported by it) 26 | This function is deprecated and should be used to migrate your project easily, consult the documentation for 27 | further information. Not planned for removal. 28 | 29 | :param byte_str: The byte sequence to examine. 30 | :param should_rename_legacy: Should we rename legacy encodings 31 | to their more modern equivalents? 32 | """ 33 | if len(kwargs): 34 | warn( 35 | f"charset-normalizer disregard arguments '{','.join(list(kwargs.keys()))}' in legacy function detect()" 36 | ) 37 | 38 | if not isinstance(byte_str, (bytearray, bytes)): 39 | raise TypeError( # pragma: nocover 40 | f"Expected object of type bytes or bytearray, got: {type(byte_str)}" 41 | ) 42 | 43 | if isinstance(byte_str, bytearray): 44 | byte_str = bytes(byte_str) 45 | 46 | r = from_bytes(byte_str).best() 47 | 48 | encoding = r.encoding if r is not None else None 49 | language = r.language if r is not None and r.language != "Unknown" else "" 50 | confidence = 1.0 - r.chaos if r is not None else None 51 | 52 | # automatically lower confidence 53 | # on small bytes samples. 54 | # https://github.com/jawah/charset_normalizer/issues/391 55 | if ( 56 | confidence is not None 57 | and confidence >= 0.9 58 | and encoding 59 | not in { 60 | "utf_8", 61 | "ascii", 62 | } 63 | and r.bom is False # type: ignore[union-attr] 64 | and len(byte_str) < TOO_SMALL_SEQUENCE 65 | ): 66 | confidence -= 0.2 67 | 68 | # Note: CharsetNormalizer does not return 'UTF-8-SIG' as the sig get stripped in the detection/normalization process 69 | # but chardet does return 'utf-8-sig' and it is a valid codec name. 70 | if r is not None and encoding == "utf_8" and r.bom: 71 | encoding += "_sig" 72 | 73 | if should_rename_legacy is False and encoding in CHARDET_CORRESPONDENCE: 74 | encoding = CHARDET_CORRESPONDENCE[encoding] 75 | 76 | return { 77 | "encoding": encoding, 78 | "language": language, 79 | "confidence": confidence, 80 | } 81 | -------------------------------------------------------------------------------- /app/server/lib/colorama/tests/ansi_test.py: -------------------------------------------------------------------------------- 1 | # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. 2 | import sys 3 | from unittest import TestCase, main 4 | 5 | from ..ansi import Back, Fore, Style 6 | from ..ansitowin32 import AnsiToWin32 7 | 8 | stdout_orig = sys.stdout 9 | stderr_orig = sys.stderr 10 | 11 | 12 | class AnsiTest(TestCase): 13 | 14 | def setUp(self): 15 | # sanity check: stdout should be a file or StringIO object. 16 | # It will only be AnsiToWin32 if init() has previously wrapped it 17 | self.assertNotEqual(type(sys.stdout), AnsiToWin32) 18 | self.assertNotEqual(type(sys.stderr), AnsiToWin32) 19 | 20 | def tearDown(self): 21 | sys.stdout = stdout_orig 22 | sys.stderr = stderr_orig 23 | 24 | 25 | def testForeAttributes(self): 26 | self.assertEqual(Fore.BLACK, '\033[30m') 27 | self.assertEqual(Fore.RED, '\033[31m') 28 | self.assertEqual(Fore.GREEN, '\033[32m') 29 | self.assertEqual(Fore.YELLOW, '\033[33m') 30 | self.assertEqual(Fore.BLUE, '\033[34m') 31 | self.assertEqual(Fore.MAGENTA, '\033[35m') 32 | self.assertEqual(Fore.CYAN, '\033[36m') 33 | self.assertEqual(Fore.WHITE, '\033[37m') 34 | self.assertEqual(Fore.RESET, '\033[39m') 35 | 36 | # Check the light, extended versions. 37 | self.assertEqual(Fore.LIGHTBLACK_EX, '\033[90m') 38 | self.assertEqual(Fore.LIGHTRED_EX, '\033[91m') 39 | self.assertEqual(Fore.LIGHTGREEN_EX, '\033[92m') 40 | self.assertEqual(Fore.LIGHTYELLOW_EX, '\033[93m') 41 | self.assertEqual(Fore.LIGHTBLUE_EX, '\033[94m') 42 | self.assertEqual(Fore.LIGHTMAGENTA_EX, '\033[95m') 43 | self.assertEqual(Fore.LIGHTCYAN_EX, '\033[96m') 44 | self.assertEqual(Fore.LIGHTWHITE_EX, '\033[97m') 45 | 46 | 47 | def testBackAttributes(self): 48 | self.assertEqual(Back.BLACK, '\033[40m') 49 | self.assertEqual(Back.RED, '\033[41m') 50 | self.assertEqual(Back.GREEN, '\033[42m') 51 | self.assertEqual(Back.YELLOW, '\033[43m') 52 | self.assertEqual(Back.BLUE, '\033[44m') 53 | self.assertEqual(Back.MAGENTA, '\033[45m') 54 | self.assertEqual(Back.CYAN, '\033[46m') 55 | self.assertEqual(Back.WHITE, '\033[47m') 56 | self.assertEqual(Back.RESET, '\033[49m') 57 | 58 | # Check the light, extended versions. 59 | self.assertEqual(Back.LIGHTBLACK_EX, '\033[100m') 60 | self.assertEqual(Back.LIGHTRED_EX, '\033[101m') 61 | self.assertEqual(Back.LIGHTGREEN_EX, '\033[102m') 62 | self.assertEqual(Back.LIGHTYELLOW_EX, '\033[103m') 63 | self.assertEqual(Back.LIGHTBLUE_EX, '\033[104m') 64 | self.assertEqual(Back.LIGHTMAGENTA_EX, '\033[105m') 65 | self.assertEqual(Back.LIGHTCYAN_EX, '\033[106m') 66 | self.assertEqual(Back.LIGHTWHITE_EX, '\033[107m') 67 | 68 | 69 | def testStyleAttributes(self): 70 | self.assertEqual(Style.DIM, '\033[2m') 71 | self.assertEqual(Style.NORMAL, '\033[22m') 72 | self.assertEqual(Style.BRIGHT, '\033[1m') 73 | 74 | 75 | if __name__ == '__main__': 76 | main() 77 | -------------------------------------------------------------------------------- /app/server/lib/mutagen/trueaudio.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2006 Joe Wreschnig 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | 8 | """True Audio audio stream information and tags. 9 | 10 | True Audio is a lossless format designed for real-time encoding and 11 | decoding. This module is based on the documentation at 12 | http://tausoft.org/wiki/True_Audio_Codec_Format 13 | 14 | True Audio files use ID3 tags. 15 | """ 16 | 17 | __all__ = ["TrueAudio", "Open", "delete", "EasyTrueAudio"] 18 | 19 | from mutagen import StreamInfo 20 | from mutagen.id3 import ID3FileType, delete 21 | from mutagen._util import cdata, MutagenError, convert_error, endswith 22 | 23 | 24 | class error(MutagenError): 25 | pass 26 | 27 | 28 | class TrueAudioHeaderError(error): 29 | pass 30 | 31 | 32 | class TrueAudioInfo(StreamInfo): 33 | """TrueAudioInfo() 34 | 35 | True Audio stream information. 36 | 37 | Attributes: 38 | length (`float`): audio length, in seconds 39 | sample_rate (`int`): audio sample rate, in Hz 40 | """ 41 | 42 | @convert_error(IOError, TrueAudioHeaderError) 43 | def __init__(self, fileobj, offset): 44 | """Raises TrueAudioHeaderError""" 45 | 46 | fileobj.seek(offset or 0) 47 | header = fileobj.read(18) 48 | if len(header) != 18 or not header.startswith(b"TTA"): 49 | raise TrueAudioHeaderError("TTA header not found") 50 | self.sample_rate = cdata.uint_le(header[10:14]) 51 | samples = cdata.uint_le(header[14:18]) 52 | self.length = 0.0 53 | if self.sample_rate != 0: 54 | self.length = float(samples) / self.sample_rate 55 | 56 | def pprint(self): 57 | return u"True Audio, %.2f seconds, %d Hz." % ( 58 | self.length, self.sample_rate) 59 | 60 | 61 | class TrueAudio(ID3FileType): 62 | """TrueAudio(filething, ID3=None) 63 | 64 | A True Audio file. 65 | 66 | Arguments: 67 | filething (filething) 68 | ID3 (mutagen.id3.ID3) 69 | 70 | Attributes: 71 | info (`TrueAudioInfo`) 72 | tags (`mutagen.id3.ID3`) 73 | """ 74 | 75 | _Info = TrueAudioInfo 76 | _mimes = ["audio/x-tta"] 77 | 78 | @staticmethod 79 | def score(filename, fileobj, header): 80 | return (header.startswith(b"ID3") + header.startswith(b"TTA") + 81 | endswith(filename.lower(), b".tta") * 2) 82 | 83 | 84 | Open = TrueAudio 85 | 86 | 87 | class EasyTrueAudio(TrueAudio): 88 | """EasyTrueAudio(filething, ID3=None) 89 | 90 | Like MP3, but uses EasyID3 for tags. 91 | 92 | Arguments: 93 | filething (filething) 94 | ID3 (mutagen.id3.ID3) 95 | 96 | Attributes: 97 | info (`TrueAudioInfo`) 98 | tags (`mutagen.easyid3.EasyID3`) 99 | """ 100 | 101 | from mutagen.easyid3 import EasyID3 as ID3 102 | ID3 = ID3 # type: ignore 103 | -------------------------------------------------------------------------------- /app/server/lib/watchdog-4.0.0.dist-info/AUTHORS: -------------------------------------------------------------------------------- 1 | Original Project Lead: 2 | ---------------------- 3 | Yesudeep Mangalapilly 4 | 5 | Current Project Lead: 6 | --------------------- 7 | Mickaël Schoentgen 8 | 9 | Contributors in alphabetical order: 10 | ----------------------------------- 11 | Adrian Tejn Kern 12 | Andrew Schaaf 13 | Danilo de Jesus da Silva Bellini 14 | David LaPalomento 15 | Filip Noetzel 16 | Gary van der Merwe 17 | Gora Khargosh 18 | Hannu Valtonen 19 | Jesse Printz 20 | Kurt McKee 21 | Léa Klein 22 | Luke McCarthy 23 | Lukáš Lalinský 24 | Malthe Borch 25 | Martin Kreichgauer 26 | Martin Kreichgauer 27 | Mike Lundy 28 | Raymond Hettinger 29 | Roman Ovchinnikov 30 | Rotem Yaari 31 | Ryan Kelly 32 | Senko Rasic 33 | Senko Rašić 34 | Shane Hathaway 35 | Simon Pantzare 36 | Simon Pantzare 37 | Steven Samuel Cole 38 | Stéphane Klein 39 | Thomas Guest 40 | Thomas Heller 41 | Tim Cuthbertson 42 | Todd Whiteman 43 | Will McGugan 44 | Yesudeep Mangalapilly 45 | Yesudeep Mangalapilly 46 | dvogel 47 | gfxmonk 48 | 49 | 50 | We would like to thank these individuals for ideas: 51 | --------------------------------------------------- 52 | Tim Golden 53 | Sebastien Martini 54 | 55 | Initially we used the flask theme for the documentation which was written by 56 | ---------------------------------------------------------------------------- 57 | Armin Ronacher 58 | 59 | 60 | Watchdog also includes open source libraries or adapted code 61 | from the following projects: 62 | 63 | - MacFSEvents - https://github.com/malthe/macfsevents 64 | - watch_directory.py - http://timgolden.me.uk/python/downloads/watch_directory.py 65 | - pyinotify - https://github.com/seb-m/pyinotify 66 | - fsmonitor - https://github.com/shaurz/fsmonitor 67 | - echo - http://wordaligned.org/articles/echo 68 | - Lukáš Lalinský's ordered set queue implementation: 69 | https://stackoverflow.com/questions/1581895/how-check-if-a-task-is-already-in-python-queue 70 | - Armin Ronacher's flask-sphinx-themes for the documentation: 71 | https://github.com/mitsuhiko/flask-sphinx-themes 72 | - pyfilesystem - https://github.com/PyFilesystem/pyfilesystem 73 | - get_FILE_NOTIFY_INFORMATION - http://blog.gmane.org/gmane.comp.python.ctypes/month=20070901 74 | -------------------------------------------------------------------------------- /app/server/lib/jinja2-3.1.6.dist-info/METADATA: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.4 2 | Name: Jinja2 3 | Version: 3.1.6 4 | Summary: A very fast and expressive template engine. 5 | Maintainer-email: Pallets 6 | Requires-Python: >=3.7 7 | Description-Content-Type: text/markdown 8 | Classifier: Development Status :: 5 - Production/Stable 9 | Classifier: Environment :: Web Environment 10 | Classifier: Intended Audience :: Developers 11 | Classifier: License :: OSI Approved :: BSD License 12 | Classifier: Operating System :: OS Independent 13 | Classifier: Programming Language :: Python 14 | Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content 15 | Classifier: Topic :: Text Processing :: Markup :: HTML 16 | Classifier: Typing :: Typed 17 | License-File: LICENSE.txt 18 | Requires-Dist: MarkupSafe>=2.0 19 | Requires-Dist: Babel>=2.7 ; extra == "i18n" 20 | Project-URL: Changes, https://jinja.palletsprojects.com/changes/ 21 | Project-URL: Chat, https://discord.gg/pallets 22 | Project-URL: Documentation, https://jinja.palletsprojects.com/ 23 | Project-URL: Donate, https://palletsprojects.com/donate 24 | Project-URL: Source, https://github.com/pallets/jinja/ 25 | Provides-Extra: i18n 26 | 27 | # Jinja 28 | 29 | Jinja is a fast, expressive, extensible templating engine. Special 30 | placeholders in the template allow writing code similar to Python 31 | syntax. Then the template is passed data to render the final document. 32 | 33 | It includes: 34 | 35 | - Template inheritance and inclusion. 36 | - Define and import macros within templates. 37 | - HTML templates can use autoescaping to prevent XSS from untrusted 38 | user input. 39 | - A sandboxed environment can safely render untrusted templates. 40 | - AsyncIO support for generating templates and calling async 41 | functions. 42 | - I18N support with Babel. 43 | - Templates are compiled to optimized Python code just-in-time and 44 | cached, or can be compiled ahead-of-time. 45 | - Exceptions point to the correct line in templates to make debugging 46 | easier. 47 | - Extensible filters, tests, functions, and even syntax. 48 | 49 | Jinja's philosophy is that while application logic belongs in Python if 50 | possible, it shouldn't make the template designer's job difficult by 51 | restricting functionality too much. 52 | 53 | 54 | ## In A Nutshell 55 | 56 | ```jinja 57 | {% extends "base.html" %} 58 | {% block title %}Members{% endblock %} 59 | {% block content %} 60 | 65 | {% endblock %} 66 | ``` 67 | 68 | ## Donate 69 | 70 | The Pallets organization develops and supports Jinja and other popular 71 | packages. In order to grow the community of contributors and users, and 72 | allow the maintainers to devote more time to the projects, [please 73 | donate today][]. 74 | 75 | [please donate today]: https://palletsprojects.com/donate 76 | 77 | ## Contributing 78 | 79 | See our [detailed contributing documentation][contrib] for many ways to 80 | contribute, including reporting issues, requesting features, asking or answering 81 | questions, and making PRs. 82 | 83 | [contrib]: https://palletsprojects.com/contributing/ 84 | 85 | -------------------------------------------------------------------------------- /app/server/lib/jinja2/async_utils.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import typing as t 3 | from functools import WRAPPER_ASSIGNMENTS 4 | from functools import wraps 5 | 6 | from .utils import _PassArg 7 | from .utils import pass_eval_context 8 | 9 | if t.TYPE_CHECKING: 10 | import typing_extensions as te 11 | 12 | V = t.TypeVar("V") 13 | 14 | 15 | def async_variant(normal_func): # type: ignore 16 | def decorator(async_func): # type: ignore 17 | pass_arg = _PassArg.from_obj(normal_func) 18 | need_eval_context = pass_arg is None 19 | 20 | if pass_arg is _PassArg.environment: 21 | 22 | def is_async(args: t.Any) -> bool: 23 | return t.cast(bool, args[0].is_async) 24 | 25 | else: 26 | 27 | def is_async(args: t.Any) -> bool: 28 | return t.cast(bool, args[0].environment.is_async) 29 | 30 | # Take the doc and annotations from the sync function, but the 31 | # name from the async function. Pallets-Sphinx-Themes 32 | # build_function_directive expects __wrapped__ to point to the 33 | # sync function. 34 | async_func_attrs = ("__module__", "__name__", "__qualname__") 35 | normal_func_attrs = tuple(set(WRAPPER_ASSIGNMENTS).difference(async_func_attrs)) 36 | 37 | @wraps(normal_func, assigned=normal_func_attrs) 38 | @wraps(async_func, assigned=async_func_attrs, updated=()) 39 | def wrapper(*args, **kwargs): # type: ignore 40 | b = is_async(args) 41 | 42 | if need_eval_context: 43 | args = args[1:] 44 | 45 | if b: 46 | return async_func(*args, **kwargs) 47 | 48 | return normal_func(*args, **kwargs) 49 | 50 | if need_eval_context: 51 | wrapper = pass_eval_context(wrapper) 52 | 53 | wrapper.jinja_async_variant = True # type: ignore[attr-defined] 54 | return wrapper 55 | 56 | return decorator 57 | 58 | 59 | _common_primitives = {int, float, bool, str, list, dict, tuple, type(None)} 60 | 61 | 62 | async def auto_await(value: t.Union[t.Awaitable["V"], "V"]) -> "V": 63 | # Avoid a costly call to isawaitable 64 | if type(value) in _common_primitives: 65 | return t.cast("V", value) 66 | 67 | if inspect.isawaitable(value): 68 | return await t.cast("t.Awaitable[V]", value) 69 | 70 | return value 71 | 72 | 73 | class _IteratorToAsyncIterator(t.Generic[V]): 74 | def __init__(self, iterator: "t.Iterator[V]"): 75 | self._iterator = iterator 76 | 77 | def __aiter__(self) -> "te.Self": 78 | return self 79 | 80 | async def __anext__(self) -> V: 81 | try: 82 | return next(self._iterator) 83 | except StopIteration as e: 84 | raise StopAsyncIteration(e.value) from e 85 | 86 | 87 | def auto_aiter( 88 | iterable: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", 89 | ) -> "t.AsyncIterator[V]": 90 | if hasattr(iterable, "__aiter__"): 91 | return iterable.__aiter__() 92 | else: 93 | return _IteratorToAsyncIterator(iter(iterable)) 94 | 95 | 96 | async def auto_to_list( 97 | value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", 98 | ) -> t.List["V"]: 99 | return [x async for x in auto_aiter(value)] 100 | -------------------------------------------------------------------------------- /app/server/lib/urllib3/http2/probe.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import threading 4 | 5 | 6 | class _HTTP2ProbeCache: 7 | __slots__ = ( 8 | "_lock", 9 | "_cache_locks", 10 | "_cache_values", 11 | ) 12 | 13 | def __init__(self) -> None: 14 | self._lock = threading.Lock() 15 | self._cache_locks: dict[tuple[str, int], threading.RLock] = {} 16 | self._cache_values: dict[tuple[str, int], bool | None] = {} 17 | 18 | def acquire_and_get(self, host: str, port: int) -> bool | None: 19 | # By the end of this block we know that 20 | # _cache_[values,locks] is available. 21 | value = None 22 | with self._lock: 23 | key = (host, port) 24 | try: 25 | value = self._cache_values[key] 26 | # If it's a known value we return right away. 27 | if value is not None: 28 | return value 29 | except KeyError: 30 | self._cache_locks[key] = threading.RLock() 31 | self._cache_values[key] = None 32 | 33 | # If the value is unknown, we acquire the lock to signal 34 | # to the requesting thread that the probe is in progress 35 | # or that the current thread needs to return their findings. 36 | key_lock = self._cache_locks[key] 37 | key_lock.acquire() 38 | try: 39 | # If the by the time we get the lock the value has been 40 | # updated we want to return the updated value. 41 | value = self._cache_values[key] 42 | 43 | # In case an exception like KeyboardInterrupt is raised here. 44 | except BaseException as e: # Defensive: 45 | assert not isinstance(e, KeyError) # KeyError shouldn't be possible. 46 | key_lock.release() 47 | raise 48 | 49 | return value 50 | 51 | def set_and_release( 52 | self, host: str, port: int, supports_http2: bool | None 53 | ) -> None: 54 | key = (host, port) 55 | key_lock = self._cache_locks[key] 56 | with key_lock: # Uses an RLock, so can be locked again from same thread. 57 | if supports_http2 is None and self._cache_values[key] is not None: 58 | raise ValueError( 59 | "Cannot reset HTTP/2 support for origin after value has been set." 60 | ) # Defensive: not expected in normal usage 61 | 62 | self._cache_values[key] = supports_http2 63 | key_lock.release() 64 | 65 | def _values(self) -> dict[tuple[str, int], bool | None]: 66 | """This function is for testing purposes only. Gets the current state of the probe cache""" 67 | with self._lock: 68 | return {k: v for k, v in self._cache_values.items()} 69 | 70 | def _reset(self) -> None: 71 | """This function is for testing purposes only. Reset the cache values""" 72 | with self._lock: 73 | self._cache_locks = {} 74 | self._cache_values = {} 75 | 76 | 77 | _HTTP2_PROBE_CACHE = _HTTP2ProbeCache() 78 | 79 | set_and_release = _HTTP2_PROBE_CACHE.set_and_release 80 | acquire_and_get = _HTTP2_PROBE_CACHE.acquire_and_get 81 | _values = _HTTP2_PROBE_CACHE._values 82 | _reset = _HTTP2_PROBE_CACHE._reset 83 | 84 | __all__ = [ 85 | "set_and_release", 86 | "acquire_and_get", 87 | ] 88 | --------------------------------------------------------------------------------